SerialDevice represents your physical device.
Extends Device.
@param {string} port       The Com Port path or name for Windows.
@param {Object} settings   The Com Port Settings.
@param {Object} Connection The constructor function of the connection.
174891
function SerialDevice(port, settings, Connection) {

  // call super class
  Device.call(this, Connection);

  this.set('portName', port);
  this.set('settings', settings);

  this.set('state', 'close');
}
143642
def _serial_close(self, port):
        '''
        
        '''
        if port in self.open_devices:
            try:
                self.open_devices[port].close()
            except Exception as exception:
                logger.error('Error closing device `%s`: %s', port, exception)
                return
        else:
            logger.debug('Device not connected to `%s`', port)
            self._publish_status(port)
            return
309617
function (jid, service) {
        var that = this._connection;
        if (service === undefined) {
            service = jid;
            jid = undefined;
        }
        this.jid = jid || that.jid;
        this.service = service || null;
        this._autoService = false;
    }
458181
function (connection) {
        delete Transaction.connections[connection.transactionId];
        connection.transactionId = null;
        connection.transactionConfig = null;
    }
310867
function ReconnectingConnection(id, connection) {
  this.id = id;
  this.connection = null;
  this.closed = false;
  this.queue = [];

  this.setConnection(connection);
}
1094293
function init(options) {
    if (options === void 0) { options = {}; }
    if ('debug' in options) {
        diag.debug.enabled = options.debug;
        Q.longStackSupport = options.debug;
    }
    if ('serverUrl' in options) {
        var myURL = url.parse(options.serverUrl);
        if (!myURL.protocol && !myURL.host) {
            return Q.reject(new Error(options.serverUrl + " is not an accepted Url, please add a Host and a Protocol."));
        }
    }
    _.assignWith(exports.initOptions, cloneServerInitOptions(options), function (left, right) { return _.isUndefined(right) ? left : right; });
    if ('push' in options) {
        exports.initOptions.push = _.cloneDeep(options.push);
    }
    return device.ready;
}
291128
function SetSettings(settings) {
		try { CFG = TLS.Fill(settings, CFG); Dbg = CFG.Debug } 
		catch (error) { LG.IF(error); }
	}
736086
function(port, host, opts) {
  if (!(this instanceof Connector)) {
    return new Connector(port, host, opts);
  }

  EventEmitter.call(this);
  this.port = port;
  this.host = host;
  this.opts = opts || {};

  this.adaptor = new Adaptor(this.opts);
}
59047
function Connection(options) {
	
	if (!(this instanceof Connection)){
		return new Connection(options);
	}
	
	
	this.prefixCounter = 0;
	this.serverMessages = {};
	this._options = {
		username: options.username || options.user || '',
		password: options.password || '',
		host: options.host || 'localhost',
		port: options.port || 143,
		secure: options.secure === true ? { // secure = true means default behavior
			rejectUnauthorized: false // Force pre-node-0.9.2 behavior
		} : (options.secure || false),
		timeout: options.timeout || 10000, // connection timeout in msecs
		xoauth: options.xoauth,
		xoauth2: options.xoauth2
	};
	
	this._messages = {};
	this._messages = {};
	
	if (options.debug===true){
		this.debug = function(msg){
			console.log(msg);
		}
	}
	
		
	if (options.chainDebug===true){
		this.chainDebug = function(msg){
			console.log(msg);
		}
	}
	
	this.socket = null;
	
	this._messages_prefix_key={};
	this._messages_key_prefix={};
	this._messages={};
	
	
	this._msg_buffer = '';
	this._resetChainCommands();
}
853788
function IOSocket(server, settings, adapter) {
    if (!(this instanceof IOSocket)) return new IOSocket(server, settings, adapter);

    this.settings   = settings || {};
    this.adapter    = adapter;
    this.webServer  = server;
    this.subscribes = {};

    let that = this;
    // do not send too many state updates
    let eventsThreshold = {
        count:          0,
        timeActivated:  0,
        active:         false,
        accidents:      0,
        repeatSeconds:  3,   // how many seconds continuously must be number of events > value
        value:          200, // how many events allowed in one check interval
        checkInterval:  1000 // duration of one check interval
    };

   // Extract user name from socket
    function getUserFromSocket(socket, callback) {
        let wait = false;
        try {
            if (socket.handshake.headers.cookie && (!socket.request || !socket.request._query || !socket.request._query.user)) {
                let cookie = decodeURIComponent(socket.handshake.headers.cookie);
                let m = cookie.match(/connect\.sid=(.+)/);
                if (m) {
                    // If session cookie exists
                    let c = m[1].split(';')[0];
                    let sessionID = cookieParser.signedCookie(c, that.settings.secret);
                    if (sessionID) {
                        // Get user for session
                        wait = true;
                        that.settings.store.get(sessionID, function (err, obj) {
                            if (obj && obj.passport && obj.passport.user) {
                                socket._sessionID = sessionID;
                                if (typeof callback === 'function') {
                                    callback(null, obj.passport.user);
                                } else {
                                    that.adapter.log.warn('[getUserFromSocket] Invalid callback')
                                }
                            } else {
                                if (typeof callback === 'function') {
                                    callback('unknown user');
                                } else {
                                    that.adapter.log.warn('[getUserFromSocket] Invalid callback')
                                }
                            }
                        });
                    }
                }
            }
            if (!wait) {
                let user = socket.request._query.user;
                let pass = socket.request._query.pass;
                if (user && pass) {
                    wait = true;
                    that.adapter.checkPassword(user, pass, function (res) {
                        if (res) {
                            that.adapter.log.debug('Logged in: ' + user);
                            if (typeof callback === 'function') {
                                callback(null, user);
                            } else {
                                that.adapter.log.warn('[getUserFromSocket] Invalid callback')
                            }
                        } else {
                            that.adapter.log.warn('Invalid password or user name: ' + user + ', ' + pass[0] + '***(' + pass.length + ')');
                            if (typeof callback === 'function') {
                                callback('unknown user');
                            } else {
                                that.adapter.log.warn('[getUserFromSocket] Invalid callback')
                            }
                        }
                    });
                }
            }
        } catch (e) {
            that.adapter.log.error(e);
            wait = false;
        }
        if (!wait && typeof callback === 'function') {
            callback('Cannot detect user');
        }
    }

    function disableEventThreshold(readAll) {
        if (eventsThreshold.active) {
            eventsThreshold.accidents = 0;
            eventsThreshold.count = 0;
            eventsThreshold.active = false;
            eventsThreshold.timeActivated = 0;
            that.adapter.log.info('Subscribe on all states again');

            setTimeout(function () {
                if (readAll) {
                    that.adapter.getForeignStates('*', function (err, res) {
                        that.adapter.log.info('received all states');
                        for (let id in res) {
                            if (res.hasOwnProperty(id) && JSON.stringify(states[id]) !== JSON.stringify(res[id])) {
                                that.server.sockets.emit('stateChange', id, res[id]);
                                states[id] = res[id];
                            }
                        }
                    });
                }

                that.server.sockets.emit('eventsThreshold', false);
                that.adapter.unsubscribeForeignStates('system.adapter.*');
                that.adapter.subscribeForeignStates('*');

            }, 50);
        }
    }

    function enableEventThreshold() {
        if (!eventsThreshold.active) {
            eventsThreshold.active = true;

            setTimeout(function () {
                that.adapter.log.info('Unsubscribe from all states, except system\'s, because over ' + eventsThreshold.repeatSeconds + ' seconds the number of events is over ' + eventsThreshold.value + ' (in last second ' + eventsThreshold.count + ')');
                eventsThreshold.timeActivated = new Date().getTime();

                that.server.sockets.emit('eventsThreshold', true);
                that.adapter.unsubscribeForeignStates('*');
                that.adapter.subscribeForeignStates('system.adapter.*');
            }, 100);
        }
    }

    function getClientAddress(socket) {
        let address;
        if (socket.handshake) {
            address = socket.handshake.address;
        }
        if (!address && socket.request && socket.request.connection) {
            address = socket.request.connection.remoteAddress;
        }
        return address;
    }

    this.initSocket = function (socket) {
        if (!socket._acl) {
            if (that.settings.auth) {
                getUserFromSocket(socket, function (err, user) {
                    if (err || !user) {
                        socket.emit('reauthenticate');
                        that.adapter.log.error('socket.io ' + (err || 'No user found in cookies'));
                        socket.disconnect();
                    } else {
                        socket._secure = true;
                        that.adapter.log.debug('socket.io client ' + user + ' connected');
                        that.adapter.calculatePermissions('system.user.' + user, commandsPermissions, function (acl) {
                            let address = getClientAddress(socket);
                            // socket._acl = acl;
                            socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
                            socketEvents(socket, address);
                        });
                    }
                });
            } else {
                that.adapter.calculatePermissions(that.settings.defaultUser, commandsPermissions, function (acl) {
                    let address = getClientAddress(socket);
                    // socket._acl = acl;
                    socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
                    socketEvents(socket, address);
                });
            }
        } else {
            let address = getClientAddress(socket);
            socketEvents(socket, address);
        }
    };

    this.getWhiteListIpForAddress = function (address, whiteList){
        return getWhiteListIpForAddress(address, whiteList);
    };
    
    function getWhiteListIpForAddress(address, whiteList) {
        if (!whiteList) return null;

        // check IPv6 or IPv4 direct match
        if (whiteList.hasOwnProperty(address)) {
            return address;
        }

        // check if address is IPv4
        let addressParts = address.split('.');
        if (addressParts.length !== 4) {
            return null;
        }

        // do we have settings for wild carded ips?
        let wildCardIps = Object.keys(whiteList).filter(function (key) {
            return key.indexOf('*') !== -1;
        });


        if (wildCardIps.length === 0) {
            // no wild carded ips => no ip configured
            return null;
        }

        wildCardIps.forEach(function (ip) {
            let ipParts = ip.split('.');
            if (ipParts.length === 4) {
                for (let i = 0; i < 4; i++) {
                    if (ipParts[i] === '*' && i === 3) {
                        // match
                        return ip;
                    }

                    if (ipParts[i] !== addressParts[i]) break;
                }
            }
        });

        return null;
    }

    function getPermissionsForIp(address, whiteList) {
        return whiteList[getWhiteListIpForAddress(address, whiteList) || 'default'];
    }

    function mergeACLs(address, acl, whiteList) {
        if (whiteList && address) {
            let whiteListAcl = getPermissionsForIp(address, whiteList);
            if (whiteListAcl) {
                ['object', 'state', 'file'].forEach(function (key) {
                    if (acl.hasOwnProperty(key) && whiteListAcl.hasOwnProperty(key)) {
                        Object.keys(acl[key]).forEach(function (permission) {
                            if (whiteListAcl[key].hasOwnProperty(permission)) {
                                acl[key][permission] = acl[key][permission] && whiteListAcl[key][permission];
                            }
                        })
                    }
                });

                if (whiteListAcl.user !== 'auth') {
                    acl.user = 'system.user.' + whiteListAcl.user;
                }
            }
        }

        return acl;
    }

    function pattern2RegEx(pattern) {
        if (!pattern) {
            return null;
        }
        pattern = pattern.toString();
        if (pattern !== '*') {
            if (pattern[0] === '*' && pattern[pattern.length - 1] !== '*') pattern += '$';
            if (pattern[0] !== '*' && pattern[pattern.length - 1] === '*') pattern = '^' + pattern;
        }
        pattern = pattern.replace(/\?/g, '\\?');
        pattern = pattern.replace(/\./g, '\\.');
        pattern = pattern.replace(/\*/g, '.*');
        pattern = pattern.replace(/\[/g, '\\[');
        pattern = pattern.replace(/]/g, '\\]');
        pattern = pattern.replace(/\(/g, '\\(');
        pattern = pattern.replace(/\)/g, '\\)');
        return pattern;
    }

    this.subscribe = function (socket, type, pattern) {
        //console.log((socket._name || socket.id) + ' subscribe ' + pattern);
        if (socket) {
            socket._subscribe = socket._subscribe || {};
        }
        if (!this.subscribes[type]) this.subscribes[type] = {};

        let s;
        if (socket) {
            s = socket._subscribe[type] = socket._subscribe[type] || [];
            for (let i = 0; i < s.length; i++) {
                if (s[i].pattern === pattern) return;
            }
        }

        let p = pattern2RegEx(pattern);
        if (p === null) {
            this.adapter.log.warn('Empty pattern!');
            return;
        }
        if (socket) {
            s.push({pattern: pattern, regex: new RegExp(p)});
        }

        if (this.subscribes[type][pattern] === undefined) {
            this.subscribes[type][pattern] = 1;
            if (type === 'stateChange') {
                this.adapter.subscribeForeignStates(pattern);
            } else if (type === 'objectChange') {
                if (this.adapter.subscribeForeignObjects) {
                    this.adapter.subscribeForeignObjects(pattern);
                }
            } else if (type === 'log') {
                if (this.adapter.requireLog) this.adapter.requireLog(true);
            }
        } else {
            this.subscribes[type][pattern]++;
        }
    };

    function showSubscribes(socket, type) {
        if (socket && socket._subscribe) {
            let s = socket._subscribe[type] || [];
            let ids = [];
            for (let i = 0; i < s.length; i++) {
                ids.push(s[i].pattern);
            }
            that.adapter.log.debug('Subscribes: ' + ids.join(', '));
        } else {
            that.adapter.log.debug('Subscribes: no subscribes');
        }
    }

    this.unsubscribe = function (socket, type, pattern) {
        //console.log((socket._name || socket.id) + ' unsubscribe ' + pattern);
        if (!this.subscribes[type]) this.subscribes[type] = {};

        if (socket) {
            if (!socket._subscribe || !socket._subscribe[type]) return;
            for (let i = socket._subscribe[type].length - 1; i >= 0; i--) {
                if (socket._subscribe[type][i].pattern === pattern) {

                    // Remove pattern from global list
                    if (this.subscribes[type][pattern] !== undefined) {
                        this.subscribes[type][pattern]--;
                        if (this.subscribes[type][pattern] <= 0) {
                            if (type === 'stateChange') {
                                //console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
                                this.adapter.unsubscribeForeignStates(pattern);
                            } else if (type === 'objectChange') {
                                //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
                                if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
                            } else if (type === 'log') {
                                //console.log((socket._name || socket.id) + ' requireLog false');
                                if (this.adapter.requireLog) this.adapter.requireLog(false);
                            }
                            delete this.subscribes[type][pattern];
                        }
                    }

                    delete socket._subscribe[type][i];
                    socket._subscribe[type].splice(i, 1);
                    return;
                }
            }
        } else if (pattern) {
            // Remove pattern from global list
            if (this.subscribes[type][pattern] !== undefined) {
                this.subscribes[type][pattern]--;
                if (this.subscribes[type][pattern] <= 0) {
                    if (type === 'stateChange') {
                        //console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
                        this.adapter.unsubscribeForeignStates(pattern);
                    } else if (type === 'objectChange') {
                        //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
                        if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
                    } else if (type === 'log') {
                        //console.log((socket._name || socket.id) + ' requireLog false');
                        if (this.adapter.requireLog) this.adapter.requireLog(false);
                    }
                    delete this.subscribes[type][pattern];
                }
            }
        } else {
            for (pattern in this.subscribes[type]) {
                if (!this.subscribes[type].hasOwnProperty(pattern)) continue;
                if (type === 'stateChange') {
                    //console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
                    this.adapter.unsubscribeForeignStates(pattern);
                } else if (type === 'objectChange') {
                    //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
                    if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
                } else if (type === 'log') {
                    //console.log((socket._name || socket.id) + ' requireLog false');
                    if (this.adapter.requireLog) this.adapter.requireLog(false);
                }
                delete this.subscribes[type][pattern];
            }
        }
    };

    this.unsubscribeAll = function () {
        if (this.server && this.server.sockets) {
            for (let s in this.server.sockets) {
                if (this.server.sockets.hasOwnProperty(s)) {
                    unsubscribeSocket(s, 'stateChange');
                    unsubscribeSocket(s, 'objectChange');
                    unsubscribeSocket(s, 'log');
                }
            }
        }
    };

    function unsubscribeSocket(socket, type) {
        if (!socket._subscribe || !socket._subscribe[type]) return;

        for (let i = 0; i < socket._subscribe[type].length; i++) {
            let pattern = socket._subscribe[type][i].pattern;
            if (that.subscribes[type][pattern] !== undefined) {
                that.subscribes[type][pattern]--;
                if (that.subscribes[type][pattern] <= 0) {
                    if (type === 'stateChange') {
                        that.adapter.unsubscribeForeignStates(pattern);
                    } else if (type === 'objectChange') {
                        if (that.adapter.unsubscribeForeignObjects) that.adapter.unsubscribeForeignObjects(pattern);
                    } else if (type === 'log') {
                        if (that.adapter.requireLog) that.adapter.requireLog(false);
                    }
                    delete that.subscribes[type][pattern];
                }
            }
        }
    }

    function subscribeSocket(socket, type) {
        //console.log((socket._name || socket.id) + ' subscribeSocket');
        if (!socket._subscribe || !socket._subscribe[type]) return;

        for (let i = 0; i < socket._subscribe[type].length; i++) {
            let pattern = socket._subscribe[type][i].pattern;
            if (that.subscribes[type][pattern] === undefined) {
                that.subscribes[type][pattern] = 1;
                if (type === 'stateChange') {
                    that.adapter.subscribeForeignStates(pattern);
                } else if (type === 'objectChange') {
                    if (that.adapter.subscribeForeignObjects) that.adapter.subscribeForeignObjects(pattern);
                } else if (type === 'log') {
                    if (that.adapter.requireLog) that.adapter.requireLog(true);
                }
            } else {
                that.subscribes[type][pattern]++;
            }
        }
    }

    function publish(socket, type, id, obj) {
        if (!socket._subscribe || !socket._subscribe[type]) return;
        let s = socket._subscribe[type];
        for (let i = 0; i < s.length; i++) {
            if (s[i].regex.test(id)) {
                updateSession(socket);
                socket.emit(type, id, obj);
                return;
            }
        }
    }

    // update session ID, but not ofter than 60 seconds
    function updateSession(socket) {
        if (socket._sessionID) {
            let time = (new Date()).getTime();
            if (socket._lastActivity && time - socket._lastActivity > settings.ttl * 1000) {
                socket.emit('reauthenticate');
                socket.disconnect();
                return false;
            }
            socket._lastActivity = time;
            if (!socket._sessionTimer) {
                socket._sessionTimer = setTimeout(function () {
                    socket._sessionTimer = null;
                    that.settings.store.get(socket._sessionID, function (err, obj) {
                        if (obj) {
                            that.adapter.setSession(socket._sessionID, settings.ttl, obj);
                        } else {
                            socket.emit('reauthenticate');
                            socket.disconnect();
                        }
                    });
                }, 60000);
            }
        }
        return true;
    }

    // static information
    let commandsPermissions = {
        getObject:          {type: 'object',    operation: 'read'},
        getObjects:         {type: 'object',    operation: 'list'},
        getObjectView:      {type: 'object',    operation: 'list'},
        setObject:          {type: 'object',    operation: 'write'},
        requireLog:         {type: 'object',    operation: 'write'}, // just mapping to some command
        delObject:          {type: 'object',    operation: 'delete'},
        extendObject:       {type: 'object',    operation: 'write'},
        getHostByIp:        {type: 'object',    operation: 'list'},
        subscribeObjects:   {type: 'object',    operation: 'read'},
        unsubscribeObjects: {type: 'object',    operation: 'read'},

        getStates:          {type: 'state',     operation: 'list'},
        getState:           {type: 'state',     operation: 'read'},
        setState:           {type: 'state',     operation: 'write'},
        delState:           {type: 'state',     operation: 'delete'},
        createState:        {type: 'state',     operation: 'create'},
        subscribe:          {type: 'state',     operation: 'read'},
        unsubscribe:        {type: 'state',     operation: 'read'},
        getStateHistory:    {type: 'state',     operation: 'read'},
        getVersion:         {type: '',          operation: ''},

        addUser:            {type: 'users',     operation: 'create'},
        delUser:            {type: 'users',     operation: 'delete'},
        addGroup:           {type: 'users',     operation: 'create'},
        delGroup:           {type: 'users',     operation: 'delete'},
        changePassword:     {type: 'users',     operation: 'write'},

        httpGet:            {type: 'other',     operation: 'http'},
        cmdExec:            {type: 'other',     operation: 'execute'},
        sendTo:             {type: 'other',     operation: 'sendto'},
        sendToHost:         {type: 'other',     operation: 'sendto'},
        readLogs:           {type: 'other',     operation: 'execute'},

        readDir:            {type: 'file',      operation: 'list'},
        createFile:         {type: 'file',      operation: 'create'},
        writeFile:          {type: 'file',      operation: 'write'},
        readFile:           {type: 'file',      operation: 'read'},
        deleteFile:         {type: 'file',      operation: 'delete'},
        readFile64:         {type: 'file',      operation: 'read'},
        writeFile64:        {type: 'file',      operation: 'write'},
        unlink:             {type: 'file',      operation: 'delete'},
        rename:             {type: 'file',      operation: 'write'},
        mkdir:              {type: 'file',      operation: 'write'},
        chmodFile:          {type: 'file',      operation: 'write'},

        authEnabled:        {type: '',          operation: ''},
        disconnect:         {type: '',          operation: ''},
        listPermissions:    {type: '',          operation: ''},
        getUserPermissions: {type: 'object',    operation: 'read'}
    };

    function addUser(user, pw, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = null;
        }

        if (!user.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&# ]+$/)) {
            if (typeof callback === 'function') {
                callback('Invalid characters in the name. Only following special characters are allowed: -@+$§=?!&# and letters');
            }
            return;
        }

        that.adapter.getForeignObject('system.user.' + user, options, (err, obj) => {
            if (obj) {
                if (typeof callback === 'function') {
                    callback('User yet exists');
                }
            } else {
                that.adapter.setForeignObject('system.user.' + user, {
                    type: 'user',
                    common: {
                        name: user,
                        enabled: true,
                        groups: []
                    }
                }, options, () => {
                    that.adapter.setPassword(user, pw, options, callback);
                });
            }
        });
    }

    function delUser(user, options, callback) {
        that.adapter.getForeignObject('system.user.' + user, options, (err, obj) => {
            if (err || !obj) {
                if (typeof callback === 'function') {
                    callback('User does not exist');
                }
            } else {
                if (obj.common.dontDelete) {
                    if (typeof callback === 'function') {
                        callback('Cannot delete user, while is system user');
                    }
                } else {
                    that.adapter.delForeignObject('system.user.' + user, options, err => {
                        // Remove this user from all groups in web client
                        if (typeof callback === 'function') {
                            callback(err);
                        }
                    });
                }
            }
        });
    }

    function addGroup(group, desc, acl, options, callback) {
        let name = group;
        if (typeof acl === 'function') {
            callback = acl;
            acl = null;
        }
        if (typeof desc === 'function') {
            callback = desc;
            desc = null;
        }
        if (typeof options === 'function') {
            callback = options;
            options = null;
        }
        if (name && name.substring(0, 1) !== name.substring(0, 1).toUpperCase()) {
            name = name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        group = group.substring(0, 1).toLowerCase() + group.substring(1);

        if (!group.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&#_ ]+$/)) {
            if (typeof callback === 'function') {
                callback('Invalid characters in the group name. Only following special characters are allowed: -@+$§=?!&# and letters');
            }
            return;
        }

        that.adapter.getForeignObject('system.group.' + group, options, (err, obj) => {
            if (obj) {
                if (typeof callback === 'function') {
                    callback('Group yet exists');
                }
            } else {
                obj = {
                    _id:  'system.group.' + group,
                    type: 'group',
                    common: {
                        name: name,
                        desc: desc,
                        members: [],
                        acl: acl
                    }
                };
                that.adapter.setForeignObject('system.group.' + group, obj, options, err => {
                    if (typeof callback === 'function') {
                        callback(err, obj);
                    }
                });
            }
        });
    }

    function delGroup(group, options, callback) {
        that.adapter.getForeignObject('system.group.' + group, options, (err, obj) => {
            if (err || !obj) {
                if (typeof callback === 'function') {
                    callback('Group does not exist');
                }
            } else {
                if (obj.common.dontDelete) {
                    if (typeof callback === 'function') {
                        callback('Cannot delete group, while is system group');
                    }
                } else {
                    that.adapter.delForeignObject('system.group.' + group, options, err => {
                        // Remove this group from all users in web client
                        if (typeof callback === 'function') {
                            callback(err);
                        }
                    });
                }
            }
        });
    }

    function checkPermissions(socket, command, callback, arg) {
        if (socket._acl.user !== 'system.user.admin') {
            // type: file, object, state, other
            // operation: create, read, write, list, delete, sendto, execute, sendToHost, readLogs
            if (commandsPermissions[command]) {
                // If permission required
                if (commandsPermissions[command].type) {
                    if (socket._acl[commandsPermissions[command].type] &&
                        socket._acl[commandsPermissions[command].type][commandsPermissions[command].operation]) {
                        return true;
                    } else {
                        that.adapter.log.warn('No permission for "' + socket._acl.user + '" to call ' + command + '. Need "' + commandsPermissions[command].type + '"."' + commandsPermissions[command].operation + '"');
                    }
                } else {
                    return true;
                }
            } else {
                that.adapter.log.warn('No rule for command: ' + command);
            }

            if (typeof callback === 'function') {
                callback('permissionError');
            } else {
                if (commandsPermissions[command]) {
                    socket.emit('permissionError', {
                        command: command,
                        type: commandsPermissions[command].type,
                        operation: commandsPermissions[command].operation,
                        arg: arg
                    });
                } else {
                    socket.emit('permissionError', {
                        command: command,
                        arg: arg
                    });
                }
            }
            return false;
        } else {
            return true;
        }
    }

    function checkObject(obj, options, flag) {
        // read rights of object
        if (!obj || !obj.common || !obj.acl || flag === 'list') {
            return true;
        }

        if (options.user !== 'system.user.admin' &&
            options.groups.indexOf('system.group.administrator') === -1) {
            if (obj.acl.owner !== options.user) {
                // Check if the user is in the group
                if (options.groups.indexOf(obj.acl.ownerGroup) !== -1) {
                    // Check group rights
                    if (!(obj.acl.object & (flag << 4))) {
                        return false
                    }
                } else {
                    // everybody
                    if (!(obj.acl.object & flag)) {
                        return false
                    }
                }
            } else {
                // Check group rights
                if (!(obj.acl.object & (flag << 8))) {
                    return false
                }
            }
        }
        return true;
    }

    this.send = function (socket, cmd, id, data) {
        if (socket._apiKeyOk) {
            socket.emit(cmd, id, data);
        }
    };

    function stopAdapter(reason, callback) {
        reason && that.adapter.log.warn('Adapter stopped. Reason: ' + reason);
        that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) {
            if (err) that.adapter.log.error('[getForeignObject]: ' + err);
            if (obj) {
                obj.common.enabled = false;
                setTimeout(function () {
                    that.adapter.setForeignObject(obj._id, obj, function (err) {
                        if (err) that.adapter.log.error('[setForeignObject]: ' + err);
                        callback && callback();
                    });
                }, 5000);
            } else {
                callback && callback();
            }
        });
    }

    function redirectAdapter(url, callback) {
        if (!url) {
            that.adapter.log.warn('Received redirect command, but no URL');
        } else {
            that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) {
                if (err) that.adapter.log.error('redirectAdapter [getForeignObject]: ' + err);
                if (obj) {
                    obj.native.cloudUrl = url;
                    setTimeout(function () {
                        that.adapter.setForeignObject(obj._id, obj, function (err) {
                            if (err) that.adapter.log.error('redirectAdapter [setForeignObject]: ' + err);
                            callback && callback();
                        });
                    }, 3000);
                } else {
                    callback && callback();
                }
            });
        }
    }

    function waitForConnect(delaySeconds) {
        that.emit && that.emit('connectWait', delaySeconds);
    }

    function socketEvents(socket, address) {
        if (socket.conn) {
            that.adapter.log.info('==>Connected ' + socket._acl.user + ' from ' + address);
        } else {
            that.adapter.log.info('Trying to connect as ' + socket._acl.user + ' from ' + address);
        }

        if (!that.infoTimeout) {
            that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
        }

        socket.on('authenticate', function (user, pass, callback) {
            that.adapter.log.debug((new Date()).toISOString() + ' Request authenticate [' + socket._acl.user + ']');
            if (typeof user === 'function') {
                callback = user;
                user = undefined;
            }
            if (socket._acl.user !== null) {
                if (typeof callback === 'function') {
                    callback(socket._acl.user !== null, socket._secure);
                }
            } else {
                that.adapter.log.debug((new Date()).toISOString() + ' Request authenticate [' + socket._acl.user + ']');
                socket._authPending = callback;
            }
        });

        socket.on('name', function (name, cb) {
            that.adapter.log.debug('Connection from ' + name);
            updateSession(socket);
            if (this._name === undefined) {
                this._name = name;
                if (!that.infoTimeout) {
                    that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
                }
            } else if (this._name !== name) {
                that.adapter.log.warn('socket ' + this.id + ' changed socket name from ' + this._name + ' to ' + name);
                this._name = name;
            }
            if (typeof cb === 'function') {
                cb();
            }
        });

        /*
         *      objects
         */
        socket.on('getObject', function (id, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getObject', callback, id)) {
                that.adapter.getForeignObject(id, {user: socket._acl.user}, callback);
            }
        });

        socket.on('getObjects', function (callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
                that.adapter.getForeignObjects('*', 'state', 'rooms', {user: socket._acl.user}, function (err, objs) {
                    if (typeof callback === 'function') {
                        callback(err, objs);
                    } else {
                        that.adapter.log.warn('[getObjects] Invalid callback')
                    }
                });
            }
        });

        socket.on('subscribeObjects', function (pattern, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'subscribeObjects', callback, pattern)) {
                if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
                    for (let p = 0; p < pattern.length; p++) {
                        that.subscribe(this, 'objectChange', pattern[p]);
                    }
                } else {
                    that.subscribe(this, 'objectChange', pattern);
                }
                if (typeof callback === 'function') {
                    setImmediate(callback, null);
                }
            }
        });

        socket.on('unsubscribeObjects', function (pattern, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'unsubscribeObjects', callback, pattern)) {
                if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
                    for (let p = 0; p < pattern.length; p++) {
                        that.unsubscribe(this, 'objectChange', pattern[p]);
                    }
                } else {
                    that.unsubscribe(this, 'objectChange', pattern);
                }
                if (typeof callback === 'function') {
                    setImmediate(callback, null);
                }
            }
        });
        
        socket.on('getObjectView', function (design, search, params, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getObjectView', callback, search)) {
                that.adapter.objects.getObjectView(design, search, params, {user: socket._acl.user}, callback);
            }
        });

        socket.on('setObject', function (id, obj, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'setObject', callback, id)) {
                that.adapter.setForeignObject(id, obj, {user: socket._acl.user}, callback);
            }
        });

        /*
         *      states
         */
        socket.on('getStates', function (pattern, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getStates', callback, pattern)) {
                if (typeof pattern === 'function') {
                    callback = pattern;
                    pattern = null;
                }
                that.adapter.getForeignStates(pattern || '*', {user: socket._acl.user}, callback);
            }
        });

        socket.on('error', function (err) {
            that.adapter.log.error('Socket error: ' + err);
        });

        // allow admin access
        if (that.settings.allowAdmin) {
            socket.on('getAllObjects', function (callback) {
                if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
                    that.adapter.objects.getObjectList({include_docs: true}, function (err, res) {
                        that.adapter.log.info('received all objects');
                        res = res.rows;
                        let objects = {};

                        if (socket._acl &&
                            socket._acl.user !== 'system.user.admin' &&
                            socket._acl.groups.indexOf('system.group.administrator') === -1) {
                            for (let i = 0; i < res.length; i++) {
                                if (checkObject(res[i].doc, socket._acl, 4 /* 'read' */)) {
                                    objects[res[i].doc._id] = res[i].doc;
                                }
                            }
                            if (typeof callback === 'function') {
                                callback(null, objects);
                            } else {
                                that.adapter.log.warn('[getAllObjects] Invalid callback')
                            }
                        } else {
                            for (let j = 0; j < res.length; j++) {
                                objects[res[j].doc._id] = res[j].doc;
                            }
                            if (typeof callback === 'function') {
                                callback(null, objects);
                            } else {
                                that.adapter.log.warn('[getAllObjects] Invalid callback')
                            }
                        }
                    });
                }
            });

            socket.on('delObject', function (id, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'delObject', callback, id)) {
                    that.adapter.delForeignObject(id, {user: socket._acl.user}, callback);
                }
            });
            socket.on('extendObject', function (id, obj, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'extendObject', callback, id)) {
                    that.adapter.extendForeignObject(id, obj, {user: socket._acl.user}, callback);
                }
            });
            socket.on('getHostByIp', function (ip, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'getHostByIp', ip)) {
                    that.adapter.objects.getObjectView('system', 'host', {}, {user: socket._acl.user}, function (err, data) {
                        if (data.rows.length) {
                            for (let i = 0; i < data.rows.length; i++) {
                                if (data.rows[i].value.common.hostname === ip) {
                                    if (typeof callback === 'function') {
                                        callback(ip, data.rows[i].value);
                                    } else {
                                        that.adapter.log.warn('[getHostByIp] Invalid callback')
                                    }
                                    return;
                                }
                                if (data.rows[i].value.native.hardware && data.rows[i].value.native.hardware.networkInterfaces) {
                                    let net = data.rows[i].value.native.hardware.networkInterfaces;
                                    for (let eth in net) {
                                        if (!net.hasOwnProperty(eth)) continue;
                                        for (let j = 0; j < net[eth].length; j++) {
                                            if (net[eth][j].address === ip) {
                                                if (typeof callback === 'function') {
                                                    callback(ip, data.rows[i].value);
                                                } else {
                                                    that.adapter.log.warn('[getHostByIp] Invalid callback')
                                                }
                                                return;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (typeof callback === 'function') {
                            callback(ip, null);
                        } else {
                            that.adapter.log.warn('[getHostByIp] Invalid callback')
                        }
                    });
                }
            });

            socket.on('getForeignObjects', function (pattern, type, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
                    if (typeof type === 'function') {
                        callback = type;
                        type = undefined;
                    }

                    that.adapter.getForeignObjects(pattern, type, {user: socket._acl.user}, function (err, objs) {
                        if (typeof callback === 'function') {
                            callback(err, objs);
                        } else {
                            that.adapter.log.warn('[getObjects] Invalid callback')
                        }
                    });
                }
            });

            socket.on('getForeignStates', function (pattern, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'getStates', callback)) {
                    that.adapter.getForeignStates(pattern, {user: socket._acl.user}, function (err, objs) {
                        if (typeof callback === 'function') {
                            callback(err, objs);
                        } else {
                            that.adapter.log.warn('[getObjects] Invalid callback')
                        }
                    });
                }
            });

            socket.on('requireLog', function (isEnabled, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'setObject', callback)) {
                    if (isEnabled) {
                        that.subscribe(this, 'log', 'dummy')
                    } else {
                        that.unsubscribe(this, 'log', 'dummy')
                    }
                    if (that.adapter.log.level === 'debug') showSubscribes(socket, 'log');

                    if (typeof callback === 'function') {
                        setImmediate(callback, null);
                    }
                }
            });

            socket.on('readLogs', function (callback) {
                if (updateSession(socket) && checkPermissions(socket, 'readLogs', callback)) {
                    let result = {list: []};

                    // deliver file list
                    try {
                        let config = adapter.systemConfig;
                        // detect file log
                        if (config && config.log && config.log.transport) {
                            for (let transport in config.log.transport) {
                                if (config.log.transport.hasOwnProperty(transport) && config.log.transport[transport].type === 'file') {
                                    let filename = config.log.transport[transport].filename || 'log/';
                                    let parts = filename.replace(/\\/g, '/').split('/');
                                    parts.pop();
                                    filename = parts.join('/');
                                    if (filename[0] === '.') {
                                        filename = path.normalize(__dirname + '/../../../') + filename;
                                    }
                                    if (fs.existsSync(filename)) {
                                        let files = fs.readdirSync(filename);
                                        for (let f = 0; f < files.length; f++) {
                                            try {
                                                if (!fs.lstatSync(filename + '/' + files[f]).isDirectory()) {
                                                    result.list.push('log/' + transport + '/' + files[f]);
                                                }
                                            } catch (e) {
                                                // push unchecked
                                                // result.list.push('log/' + transport + '/' + files[f]);
                                                adapter.log.error('Cannot check file: ' + filename + '/' + files[f]);
                                            }
                                        }
                                    }
                                }
                            }
                        } else {
                            result.error = 'no file loggers';
                            result.list = undefined;
                        }
                    } catch (e) {
                        adapter.log.error(e);
                        result.error = e;
                        result.list = undefined;
                    }
                    if (typeof callback === 'function') {
                        callback(result.error, result.list);
                    }
                }
            });
        } else {
            // only flot allowed
            socket.on('delObject', function (id, callback) {
                if (id.match(/^flot\./)) {
                    if (updateSession(socket) && checkPermissions(socket, 'delObject', callback, id)) {
                        that.adapter.delForeignObject(id, {user: socket._acl.user}, callback);
                    }
                } else {
                    if (typeof callback === 'function') {
                        callback('permissionError');
                    }
                }
            });
        }

        socket.on('getState', function (id, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getState', callback, id)) {
                that.adapter.getForeignState(id, {user: socket._acl.user}, callback);
            }
        });

        socket.on('setState', function (id, state, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'setState', callback, id)) {
                if (typeof state !== 'object') state = {val: state};
                that.adapter.setForeignState(id, state, {user: socket._acl.user}, function (err, res) {
                    if (typeof callback === 'function') {
                        callback(err, res);
                    }
                });
            }
        });

        // allow admin access
        if (that.settings.allowAdmin) {
            socket.on('delState', function (id, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'delState', callback, id)) {
                    that.adapter.delForeignState(id, {user: socket._acl.user}, callback);
                }
            });
            socket.on('addUser', function (user, pass, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'addUser', callback, user)) {
                    addUser(user, pass, {user: socket._acl.user}, callback);
                }
            });

            socket.on('delUser', function (user, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'delUser', callback, user)) {
                    delUser(user, {user: socket._acl.user}, callback);
                }
            });

            socket.on('addGroup', function (group, desc, acl, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'addGroup', callback, group)) {
                    addGroup(group, desc, acl, {user: socket._acl.user}, callback);
                }
            });

            socket.on('delGroup', function (group, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'delGroup', callback, group)) {
                    delGroup(group, {user: socket._acl.user}, callback);
                }
            });

            socket.on('changePassword', function (user, pass, callback) {
                if (updateSession(socket)) {
                    if (user === socket._acl.user || checkPermissions(socket, 'changePassword', callback, user)) {
                        that.adapter.setPassword(user, pass, {user: socket._acl.user}, callback);
                    }
                }
            });
            // commands will be executed on host/controller
            // following response commands are expected: cmdStdout, cmdStderr, cmdExit
            socket.on('cmdExec', function (host, id, cmd, callback) {
                if (updateSession(socket) && checkPermissions(socket, 'cmdExec', callback, cmd)) {
                    that.adapter.log.debug('cmdExec on ' + host + '(' + id + '): ' + cmd);
                    that.adapter.sendToHost(host, 'cmdExec', {data: cmd, id: id});
                }
            });

            socket.on('eventsThreshold', function (isActive) {
                if (!isActive) {
                    disableEventThreshold(true);
                } else {
                    enableEventThreshold();
                }
            });
        }

        socket.on('getVersion', function (callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getVersion', callback)) {
                if (typeof callback === 'function') {
                    callback(that.adapter.version);
                } else {
                    that.adapter.log.warn('[getVersion] Invalid callback')
                }
            }
        });

        socket.on('subscribe', function (pattern, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'subscribe', callback, pattern)) {
                if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
                    for (let p = 0; p < pattern.length; p++) {
                        that.subscribe(this, 'stateChange', pattern[p]);
                    }
                } else {
                    that.subscribe(this, 'stateChange', pattern);
                }
                if (that.adapter.log.level === 'debug') showSubscribes(socket, 'stateChange');
                if (typeof callback === 'function') {
                    setImmediate(callback, null);
                }
            }
        });

        socket.on('unsubscribe', function (pattern, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'unsubscribe', callback, pattern)) {
                if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
                    for (let p = 0; p < pattern.length; p++) {
                        that.unsubscribe(this, 'stateChange', pattern[p]);
                    }
                } else {
                    that.unsubscribe(this, 'stateChange', pattern);
                }
                if (that.adapter.log.level === 'debug') showSubscribes(socket, 'stateChange');
                if (typeof callback === 'function') {
                    setImmediate(callback, null);
                }
            }
        });


        // new History
        socket.on('getHistory', function (id, options, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getStateHistory', callback, id)) {
                options = options || {};
                options.user = socket._acl.user;
                that.adapter.getHistory(id, options, function (err, data, step, sessionId) {
                    if (typeof callback === 'function') {
                        callback(err, data, step, sessionId);
                    } else {
                        that.adapter.log.warn('[getHistory] Invalid callback')
                    }
                });
            }
        });

        // HTTP
        socket.on('httpGet', function (url, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'httpGet', callback, url)) {
                if (!request) request = require('request');
                that.adapter.log.debug('httpGet: ' + url);
                request(url, callback);
            }
        });

        // commands
        socket.on('sendTo', function (adapterInstance, command, message, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'sendTo', callback, command)) {
                that.adapter.sendTo(adapterInstance, command, message, callback);
            }
        });

        // following commands are protected and require the extra permissions
        const protectedCommands = ['cmdExec', 'getLocationOnDisk', 'getDiagData', 'getDevList', 'delLogs', 'writeDirAsZip', 'writeObjectsAsZip', 'readObjectsAsZip', 'checkLogging', 'updateMultihost'];

        socket.on('sendToHost', function (host, command, message, callback) {
            // host can answer following commands: cmdExec, getRepository, getInstalled, getInstalledAdapter, getVersion, getDiagData, getLocationOnDisk, getDevList, getLogs, getHostInfo,
            // delLogs, readDirAsZip, writeDirAsZip, readObjectsAsZip, writeObjectsAsZip, checkLogging, updateMultihost
            if (updateSession(socket) && checkPermissions(socket, protectedCommands.indexOf(command) !== -1 ? 'cmdExec' : 'sendToHost', callback, command)) {
                that.adapter.sendToHost(host, command, message, callback);
            }
        });

        socket.on('authEnabled', callback => {
            if (updateSession(socket) && checkPermissions(socket, 'authEnabled', callback)) {
                if (typeof callback === 'function') {
                    callback(that.settings.auth, (socket._acl.user || '').replace(/^system\.user\./, ''));
                } else {
                    that.adapter.log.warn('[authEnabled] Invalid callback')
                }
            }
        });

        // file operations
        socket.on('readFile', function (_adapter, fileName, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'readFile', callback, fileName)) {
                that.adapter.readFile(_adapter, fileName, {user: socket._acl.user}, callback);
            }
        });

        socket.on('readFile64', function (_adapter, fileName, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'readFile64', callback, fileName)) {
                that.adapter.readFile(_adapter, fileName, {user: socket._acl.user}, function (err, buffer, type) {
                    let data64;
                    if (buffer) {
                        if (type === 'application/json') {
                            data64 = new Buffer(encodeURIComponent(buffer)).toString('base64');
                        } else {
                            if (typeof buffer === 'string') {
                                data64 = new Buffer(buffer).toString('base64');
                            } else {
                                data64 = buffer.toString('base64');
                            }
                        }
                    }

                    //Convert buffer to base 64
                    if (typeof callback === 'function') {
                        callback(err, data64 || '', type);
                    } else {
                        that.adapter.log.warn('[readFile64] Invalid callback')
                    }
                });
            }
        });

        socket.on('writeFile64', function (_adapter, fileName, data64, options, callback) {
            if (typeof options === 'function') {
                callback = options;
                options = {user: socket._acl.user};
            }
            if (!options) options = {};
            options.user = socket._acl.user;

            if (updateSession(socket) && checkPermissions(socket, 'writeFile64', callback, fileName)) {
                //Convert base 64 to buffer
                let buffer = new Buffer(data64, 'base64');
                that.adapter.writeFile(_adapter, fileName, buffer, options, function (err) {
                    if (typeof callback === 'function') {
                        callback(err);
                    }
                });
            }
        });

        socket.on('writeFile', function (_adapter, fileName, data, options, callback) {
            if (typeof options === 'function') {
                callback = options;
                options = {user: socket._acl.user};
            }
            if (!options) options = {};
            options.user = socket._acl.user;
            if (updateSession(socket) && checkPermissions(socket, 'writeFile', callback, fileName)) {
                that.adapter.writeFile(_adapter, fileName, data, options, callback);
            }
        });

        socket.on('unlink', function (_adapter, name, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'unlink', callback, name)) {
                that.adapter.unlink(_adapter, name, {user: socket._acl.user}, callback);
            }
        });

        socket.on('rename', function (_adapter, oldName, newName, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'rename', callback, oldName)) {
                that.adapter.rename(_adapter, oldName, newName, {user: socket._acl.user}, callback);
            }
        });

        socket.on('mkdir', function (_adapter, dirName, callback) {
            if (updateSession(socket) && checkPermissions(socket, 'mkdir', callback, dirName)) {
                that.adapter.mkdir(_adapter, dirName, {user: socket._acl.user}, callback);
            }
        });

        socket.on('readDir', function (_adapter, dirName, options, callback) {
            if (typeof options === 'function') {
                callback = options;
                options = {};
            }
            options = options || {};
            options.user = socket._acl.user;

            if (options.filter === undefined) options.filter = true;

            if (updateSession(socket) && checkPermissions(socket, 'readDir', callback, dirName)) {
                that.adapter.readDir(_adapter, dirName, options, callback);
            }
        });

        socket.on('chmodFile', function (_adapter, dirName, options, callback) {
            if (typeof options === 'function') {
                callback = options;
                options = {};
            }
            options = options || {};
            options.user = socket._acl.user;

            if (options.filter === undefined) options.filter = true;

            if (updateSession(socket) && checkPermissions(socket, 'chmodFile', callback, dirName)) {
                that.adapter.chmodFile(_adapter, dirName, options, callback);
            }
        });

        // connect/disconnect
        socket.on('disconnect', function (error) {
            that.adapter.log.info('<==Disconnect ' + socket._acl.user + ' from ' + getClientAddress(socket) + ' ' + (socket._name || ''));
            unsubscribeSocket(this, 'stateChange');
            unsubscribeSocket(this, 'objectChange');
            unsubscribeSocket(this, 'log');
            if (!that.infoTimeout) {
                that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
            }

            // if client mode
            if (!socket.conn) {
                socket._apiKeyOk = false;
                that.emit && that.emit('disconnect', error);
            }
        });

        socket.on('logout', function (callback) {
            that.adapter.destroySession(socket._sessionID, callback);
        });

        socket.on('listPermissions', function (callback) {
            if (updateSession(socket)) {
                if (typeof callback === 'function') {
                    callback(commandsPermissions);
                } else {
                    that.adapter.log.warn('[listPermissions] Invalid callback');
                }
            }
        });

        socket.on('getUserPermissions', function (callback) {
            if (updateSession(socket) && checkPermissions(socket, 'getUserPermissions', callback)) {
                if (typeof callback === 'function') {
                    callback(null, socket._acl);
                } else {
                    that.adapter.log.warn('[getUserPermissions] Invalid callback')
                }
            }
        });

        if (typeof that.settings.extensions === 'function') {
            that.settings.extensions(socket);
        }

        // if client mode
        if (!socket.conn) {
            socket._apiKeyOk = false;

            socket.on('cloudDisconnect', function (err) {
                err && that.adapter.log.warn('User disconnected from cloud: ' + err);
                unsubscribeSocket(socket, 'stateChange');
                unsubscribeSocket(socket, 'objectChange');
                unsubscribeSocket(socket, 'log');
                that.emit('cloudDisconnect');
            });

            socket.on('cloudConnect', function () {
                // do not autosubscribe. The client must resubscribe all states anew
                // subscribeSocket(socket, 'stateChange');
                // subscribeSocket(socket, 'objectChange');
                // subscribeSocket(socket, 'log');
                that.emit('cloudConnect');
            });

            socket.on('cloudCommand', function (cmd, data) {
                if (cmd === 'stop') {
                    stopAdapter(data);
                } else if (cmd === 'redirect') {
                    redirectAdapter(data);
                } else if (cmd === 'wait') {
                    waitForConnect(data || 30);
                }
            });

            // only active in client mode
            socket.on('connect', function () {
                that.adapter.log.debug('Connected. Check api key...');
                socket._apiKeyOk = false;

                // 2018_01_20 workaround for pro: Remove it after next pro maintenance
                if (that.settings.apikey.indexOf('@pro_') !== -1) {
                    socket._apiKeyOk = true;
                    that.emit && that.emit('connect');
                }

                // send api key if exists
                this.emit('apikey', that.settings.apikey, that.settings.version, that.settings.uuid, function (err, instructions) {
                    // instructions = {
                    //     validTill: '2018-03-14T01:01:01.567Z',
                    //     command: 'wait' | 'stop' | 'redirect'
                    //     data: some data for command (URL for redirect or seconds for wait'

                    if (instructions) {
                        if (typeof instructions !== 'object') {
                            that.adapter.setState('info.remoteTill', new Date(instructions).toISOString(), true);
                        } else {
                            if (instructions.validTill) {
                                that.adapter.setState('info.remoteTill', new Date(instructions.validTill).toISOString(), true);
                            }
                            if (instructions.command === 'stop') {
                                stopAdapter(instructions.data);
                            } else if (instructions.command === 'redirect') {
                                redirectAdapter(instructions.data);
                            } else if (instructions.command === 'wait') {
                                waitForConnect(instructions.data || 30);
                            }
                        }
                    }

                    if (!err) {
                        that.adapter.log.debug('API KEY OK');
                        socket._apiKeyOk = true;

                        that.emit && that.emit('connect');
                    } else {
                        if (err.indexOf('Please buy remote access to use pro.') !== -1) {
                            stopAdapter('Please buy remote access to use pro.');
                        }
                        that.adapter.log.error(err);
                        this.close(); // disconnect
                    }
                });

                if (socket._sessionID) {
                    that.adapter.getSession(socket._sessionID, function (obj) {
                        if (obj && obj.passport) {
                            socket._acl.user = obj.passport.user;
                        } else {
                            socket._acl.user = '';
                            socket.emit('reauthenticate');
                            socket.disconnect();
                        }
                        if (socket._authPending) {
                            socket._authPending(!!socket._acl.user, true);
                            delete socket._authPending;
                        }
                    });
                }

                subscribeSocket(this, 'stateChange');
                subscribeSocket(this, 'objectChange');
                subscribeSocket(this, 'log');
            });

            /*socket.on('reconnect', function (attempt) {
                that.adapter.log.debug('Connected after attempt ' + attempt);
            });
            socket.on('reconnect_attempt', function (attempt) {
                that.adapter.log.debug('reconnect_attempt');
            });
            socket.on('connect_error', function (error) {
                that.adapter.log.debug('connect_error: ' + error);
            });
            socket.on('connect_timeout', function (error) {
                that.adapter.log.debug('connect_timeout');
            });
            socket.on('reconnect_failed', function (error) {
                that.adapter.log.debug('reconnect_failed');
            });*/
        } else {
            // if server mode
            if (socket.conn.request.sessionID) {
                socket._secure    = true;
                socket._sessionID = socket.conn.request.sessionID;
                // Get user for session
                that.settings.store.get(socket.conn.request.sessionID, function (err, obj) {
                    if (!obj || !obj.passport) {
                        socket._acl.user = '';
                        socket.emit('reauthenticate');
                        socket.disconnect();
                    }
                    if (socket._authPending) {
                        socket._authPending(!!socket._acl.user, true);
                        delete socket._authPending;
                    }
                });
            }

            subscribeSocket(socket, 'stateChange');
            subscribeSocket(socket, 'objectChange');
            subscribeSocket(socket, 'log');
        }
    }

    function updateConnectedInfo() {
        if (that.infoTimeout) {
            clearTimeout(that.infoTimeout);
            that.infoTimeout = null;
        }
        if (that.server.sockets) {
            let text = '';
            let cnt = 0;
            if (that.server) {
                let clients = that.server.sockets.connected;

                for (let i in clients) {
                    if (clients.hasOwnProperty(i)) {
                        text += (text ? ', ' : '') + (clients[i]._name || 'noname');
                        cnt++;
                    }
                }
            }
            text = '[' + cnt + ']' + text;
            that.adapter.setState('connected', text, true);
        }
    }

    this.publishAll = function (type, id, obj) {
        if (id === undefined) {
            console.log('Problem');
        }

        let clients = this.server.sockets.connected;

        for (let i in clients) {
            if (clients.hasOwnProperty(i)) {
                publish(clients[i], type, id, obj);
            }
        }
    };

    this.sendLog = function (obj) {
        // TODO Build in some threshold
        if (this.server && this.server.sockets) {
            this.server.sockets.emit('log', obj);
        }
    };

    (function __constructor() {

        if (that.settings.allowAdmin) {
            // detect event bursts
            setInterval(function () {
                if (!eventsThreshold.active) {
                    if (eventsThreshold.count > eventsThreshold.value) {
                        eventsThreshold.accidents++;

                        if (eventsThreshold.accidents >= eventsThreshold.repeatSeconds) {
                            enableEventThreshold();
                        }
                    } else {
                        eventsThreshold.accidents = 0;
                    }
                    eventsThreshold.count = 0;
                } else if (new Date().getTime() - eventsThreshold.timeActivated > 60000) {
                    disableEventThreshold();
                }
            }, eventsThreshold.checkInterval);
         }

        // it can be used as client too for cloud
        if (!that.settings.apikey) {
            if (!that.webServer.__inited) {
                that.server = socketio.listen(that.webServer);
                that.webServer.__inited = true;
            }

            // force using only websockets
            if (that.settings.forceWebSockets) that.server.set('transports', ['websocket']);
        } else {
            that.server = server;
        }

        //    socket = socketio.listen(settings.port, (settings.bind && settings.bind !== "0.0.0.0") ? settings.bind : undefined);
        that.settings.defaultUser = that.settings.defaultUser || 'system.user.admin';
        if (!that.settings.defaultUser.match(/^system\.user\./)) that.settings.defaultUser = 'system.user.' + that.settings.defaultUser;

        if (that.settings.auth && that.server) {
            that.server.use(function (socket, next) {
                if (!socket.request._query.user || !socket.request._query.pass) {
                    getUserFromSocket(socket, function (err, user) {
                        if (err || !user) {
                            socket.emit('reauthenticate');
                            that.adapter.log.error('socket.io ' + (err || 'User not found'));
                            socket.disconnect();
                        } else {
                            socket._secure = true;
                            that.adapter.calculatePermissions('system.user.' + user, commandsPermissions, function (acl) {
                                let address = getClientAddress(socket);
                                // socket._acl = acl;
                                socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
                                next();
                            });
                        }
                    });
                } else {
                    that.adapter.checkPassword(socket.request._query.user, socket.request._query.pass, function (res) {
                        if (res) {
                            that.adapter.log.debug('Logged in: ' + socket.request._query.user + ', ' + socket.request._query.pass);
                            next();
                        } else {
                            that.adapter.log.warn('Invalid password or user name: ' + socket.request._query.user + ', ' + socket.request._query.pass);
                            socket.emit('reauthenticate');
                            next(new Error('Invalid password or user name'));
                        }
                    });
                }
            });
        }

        // Enable cross domain access
        if (that.settings.crossDomain && that.server.set) {
            that.server.set('origins', '*:*');
        }

        that.settings.ttl = that.settings.ttl || 3600;

        that.server.on('connection', that.initSocket);

        if (settings.port) {
            that.adapter.log.info((settings.secure ? 'Secure ' : '') + 'socket.io server listening on port ' + settings.port);
        }

        if (!that.infoTimeout) {
            that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
        }

        // if client mode => add event handlers
        if (that.settings.apikey) {
            that.initSocket(that.server);
        }
    })();
}
939078
function isLegalPort(port: number) : boolean {
  if (typeof port === 'string' && port.trim() === '') {
    return false;
  }
  return +port === (port >>> 0) && port >= 0 && port <= 0xFFFF;
}
936727
function onPortSelectInput(newPort) {
			newPort = newPort.replace(/\n/g, ""); newPort = newPort.replace(/\r/g, "");
			var portExists = false;
			for(var i=0; i < ports.length; i++) if(newPort == ports[i].comName) { portExists = true; break; }
			if(!portExists && Number(newPort) && ports[Number(newPort)-1]) {
				newPort = ports[Number(newPort)-1].comName; portExists = true;
			}
			if(portExists) {
				console.log(chalk.bgGreen.black("Listening on port \""+newPort+"\""));
				process.stdin.removeListener('data', onPortSelectInput);
				console.log(); callback(newPort);
			} else {
				console.log(chalk.bgRed.black("Port \""+newPort+"\" does not exist!"));
			}
		}
723045
function isPortTaken(port, fn) {
  const net = require('net')
  const tester = net.createServer()
    .once('error', function (err) {
      if (err.code != 'EADDRINUSE') return fn(err)
      fn(null, true)
    })
    .once('listening', function() {
      tester.once('close', function() { fn(null, false) })
        .close()
    })
    .listen(port)
}
157535
function Prox(settings) {

    var self = this;
    this.log = settings.log;

    this.devices = new DeviceManager(settings);
    this.server = new ServerConnection(settings);

    this.server.on('listening', function (localPort, localAddress, protocol) {
        self.log('Web-Remote-Control Proxy Server listening to "' + protocol + '" requests on ' + localAddress + ':' + localPort);
    });

    this.server.on('error', this.handleError.bind(this));

    this.server.on('socket-close', function (socketId) {
        self.devices.removeBySocketId(socketId);
    });

    this.server.on('register', this.registerDevice.bind(this));
    this.server.on('ping', this.respondToPing.bind(this));
    this.server.on('status', this.forwardStatus.bind(this));
    this.server.on('command', this.forwardCommand.bind(this));

    this.stickers = new StickyMessages();

    EventEmitter.call(this);

}
389368
function(config) {
    var transport;
    if (config.wifi) {
      transport = new WiFiTransport({
        configuration: config.wifi
      });
    } else if (config.ethernet) {
      transport = new EthernetTransport({
        configuration: config.ethernet
      });
    } else if (config.ble) {
      transport = new BLETransport({
        configuration: config.ble
      });
    } else if (config.serial) {
      transport = new SerialTransport({
        configuration: config.serial
      });
    } else {
      throw new Error("Must specify a valid connection type");
    }
    return transport;
  }
341429
function configureConnection(connection) {
        // Set the common hub
        abp.signalr.hubs.common = connection;

        // Reconnect if hub disconnects
        connection.onclose(function (e) {
            if (e) {
                abp.log.debug('Connection closed with error: ' + e);
            }
            else {
                abp.log.debug('Disconnected');
            }

            if (!abp.signalr.autoConnect) {
                return;
            }

            setTimeout(function () {
                if ($.connection.hub.state === $.signalR.connectionState.disconnected) {
                    $.connection.hub.start();
                }
            }, 5000);
        });

        // Register to get notifications
        connection.on('getNotification', function (notification) {
            abp.event.trigger('abp.notifications.received', notification);
        });
    }
1291968
function (host, port) {
  this.name = 'AVTransport'
  this.host = host
  this.port = port || 1400
  this.controlURL = '/MediaRenderer/AVTransport/Control'
  this.eventSubURL = '/MediaRenderer/AVTransport/Event'
  this.SCPDURL = '/xml/AVTransport1.xml'
}