<commit_before>$.Cow.Websocket.prototype = {

    _onOpen: function() {

        console.log('connected');
    },
    _onMessage: function(message) {
        var core = this.obj.core;
        console.debug('message: '+message.data);
        var data = JSON.parse(message.data);
        var uid = data.uid;
        var UID = core.UID;
        var action = data.action;
        var payload = data.payload;
        var target = data.target;
        switch (action) {
        //Messages from Server
            //webscocket confirms connection by returning a CID
            case 'connected':
                this.obj._onConnect(payload)
            break;
            //the server noticed a peer disconnecting and send its connection-id to the pool
            case 'peerGone':
                this.obj._onPeerGone(payload);
            break;
        //Messages from Peers: targeted messages
            //the client has joined and receives the status from peers: connection-id, uid, extent
            case 'informPeer':
                if(target == this.obj.core.UID) {
                    this.obj._onInformPeer(payload,uid);
                }
            break;
            //the alpha peer sends a sync message with new features and a feature request
            case 'syncPeer':
                if(target == this.obj.core.UID) {
                    this.obj._onSyncPeer(payload,uid);
                }
            break;
            //requested feats are returning from peer
            case 'requestedFeats':
                if(uid != UID) {
                    this.obj._onRequestedFeats(payload,uid);
                }
            break;

        //Messages from Peers: broadcasted messages
            //a peer is gone and everybody has a new connection-id, recieve a connectionID with UID
            case 'updatePeers':
                if(uid != UID) {
                    this.obj._onUpdatePeers(payload,uid);
                }
            break;
            //a new peer just joined, recieve its status: connection-id, uid, extent
            case 'newPeer':
                if(uid != this.obj.core.UID) {
                    this.obj._onNewPeer(payload,uid);
                }
            break;
            //a new peer just sent it's fidlist
            case 'newPeerFidList':
                if(uid != this.obj.core.UID) {
                    this.obj._onNewPeerFidList(payload,uid);
                }
            break;
            //a peer has changed, update the peer
            case 'peerUpdated':
                if(uid != UID) {
                    this.obj._onPeerUpdated(payload,uid);
                }
            break;

            //a new object was drawn or updated by a peer
            case 'newFeature':
                if(uid != UID) {
                    var item = JSON.parse(payload);
                    if (self.core.activeHerd == item.feature.properties.store)
                        core.featurestore().updateItem(item);
                }
            break;
            case 'updateFeature':
                if(uid != UID) {
                    var item = JSON.parse(payload);
                    if (self.core.activeHerd == item.feature.properties.store)
                        core.featurestore().updateItem(item);
                }
            break;
            //A peer request information about a herd
            case 'getHerdInfo':
                if(uid != UID) {
                    this.obj._onGetHerdInfo(payload);
                }
            break;
            //Info about a herd comes in...
            case 'herdUpdate':
                if(uid != UID) {
                    this.obj._onHerdUpdate(payload);
                }
            break;

        }
    },
    _onClose: function(event) {
        var code = event.code;
        var self = this;
        var reason = event.reason;
        var wasClean = event.wasClean;
        console.log('disconnected');
        this.close();
        this.obj.core.removeAllPeers();
        this.obj.core.trigger('ws-disconnected');
        //TODO: doe iets slimmers, hij hangt nu af van de global variable 'core'....
        var restart = function(){
            try{
                core.ws.closews();
            }
            catch(err){
                console.warn(err);
            }
            core.ws.openws();
        }
        setTimeout(restart,5000);
    },
    _onError: function(event, error) {
        //alert(error);
        console.warn('error: ' + event);
    },
    sendData: function(data, action, target){
        //TODO: check if data is an object
        var message = {};
        message.uid = this.core.UID;
        message.target = target;
        message.action = action;
        message.payload = data;
        if (this.ws && this.ws.readyState == 1){
            this.ws.send(JSON.stringify(message));
        }
    },
    _onConnect: function(payload) {
        var self = this;
        console.log('onConnect');

        var name = $('#'+this.core.options.namefield).val();

        var options = {};

        options.uid = this.core.UID;
        options.cid = payload.cid;
       options.family = 'alpha'; //used to check if client is able to act as alpha peer
        var me = this.core.peers(options);
        me.view({"extent":{"bottom":0,"left":0,"top":1,"right":1}});
        var herd = this.core.getHerdById(this.core.activeHerd);
        me.herd(herd);
        me.owner({"name":name});
        me.video({"state":"off"});
        console.log('nr peers: '+this.core.peers().length);
        this.core.trigger('ws-connected');
        this.sendData(options,'newPeer');
        //triggers _onNewPeer()

        var sendFidList = function(){
            var store = core.featurestore();
            var fids = store.getIdList();
            var message = {};
            message.fids = fids;
            message.storename = self.core.activeHerd;
            self.core.websocket().sendData(message, "newPeerFidList");

        }
        //TODO TT: at the moment we only check for 1 store to be loaded
        if (this.core.featurestore().loaded == true)
            sendFidList();
        else
            setTimeout(sendFidList, 2000);

    },

    //You just joined and you get from each peer the relevant info
    //Add it to your peerList
    _onInformPeer: function(payload,uid) {
        console.log('Got peerinfo from: '+uid);
        if(payload.options.uid !== undefined && payload.options.cid !== undefined) {
            var me = this.core.peers(payload.options);
            me.view({"extent":payload.view});
            me.position({"point":payload.position});
            me.owner(payload.owner);
            me.herd(payload.herd);
            if (payload.video)
                me.video(payload.video);
            this.core.trigger('ws-peerInfo');
        }
        else console.log('badpeer '+uid);
    },
    //A new peer has joined, send it your info, compare its features and add it to your
    //peerList
    _onNewPeer: function(payload,uid) {
        console.log('This peer just connected: '+uid);
        if(payload.uid !== undefined && payload.cid !== undefined) {
            console.log('adding peer');
            this.core.peers(payload);
            var message = {};
            message.options = this.core.me().options;
            message.view = this.core.me().view().extent;
            message.owner = this.core.me().owner();
            message.position = this.core.me().position().point;
            message.herd = this.core.me().herd();
            message.video = this.core.me().video();
            this.sendData(message,'informPeer',uid);
            this.core.trigger('ws-newPeer');
        }
        else console.warn('badpeer '+uid);
    },
    _amIAlpha: function(id,herd){ //find out wether I am alpha
        if (this.core.me().herd().uid == herd){ //I need to be part of the herd
            if (this.core.me().options.cid == id) //yes, I certainly am (the oldest)
                return true;
            else { //check again if younger peer turns out not to be from alpha family or not part of my herd
                id++;
                var nextpeer = this.core.getPeerByCid(id);
                if ((nextpeer.options.family && nextpeer.options.family != 'alpha') ||
                    (nextpeer.herd().uid && nextpeer.herd().uid != this.core.me().herd().uid))
                    this._amIAlpha(id, herd);    //I might still be alpha
            }
            return false; //Not the oldest in the herd
        }
        else return false; //Not part of herd
    },
    _onNewPeerFidList: function(payload, uid) {
        var self = this; //TODO !! : alpha check must incorporate activeherd!!
        //if (this._amIAlpha(0, payload.storename)){ //Check wether I'm alpha
            //console.log('I am alpha');
            if (self.core.activeHerd == payload.storename){
                var data = this.core.featurestore().compareIdList(payload.fids);
                var message = {};
                //First the requestlist
                message.requestlist = data.requestlist;
                message.pushlist = []; //empty
                message.storename = payload.storename;
                this.sendData(message,'syncPeer',uid);
                //Now the pushlist bit by bit
                message.requestlist = []; //empty
                var i = 0;
                $.each(data.pushlist, function(id, item){
                        message.pushlist.push(item);
                        i++;
                        if (i >= 1) { //max 1 feat every time
                            i = 0;
                            self.sendData(message,'syncPeer',uid);
                            message.pushlist = []; //empty
                        }
                });
                //sent the remainder of the list
                if (i > 0)
                    this.sendData(message,'syncPeer',uid);
            }
        //}
    },

    //The alpha peer sends a sync message including a list with new features and
    //a request list with features it wants from us
    _onSyncPeer: function(payload,uid) {
        var requested_fids = payload.requestlist;
        var pushed_feats = payload.pushlist;
        if (self.core.activeHerd == payload.storename){
            var store = this.core.featurestore();
            //First sent the features that are asked for
            if (requested_fids.length > 0){
                var message = {};
                message.features = store.requestFeatures(requested_fids);
                message.storename = payload.storename;
                this.sendData(message, 'requestedFeats');
            }
            //Now add the features that have been sent to the featurestore
            if (pushed_feats.length > 0){
                store.putFeatures(pushed_feats);
            }
        }
    },
    //Peer sends back requested features, now store them
    _onRequestedFeats: function(payload,uid) {
        var requested_feats = payload;
        if (self.core.me().herd().uid == payload.storename){
            var store = this.core.featurestore();
            if (requested_feats.length > 0){
                store.putFeatures(requested_feats);
            }
        }
    },
    //A peer has disconnected, remove it from your peerList and
    //send your new CID to the remaining peers
    _onPeerGone: function(payload) {
        var peerGone = payload.peerCid;
        var newCid = payload.newCid;
        this.core.removePeer(peerGone);
        this.core.me().options.cid = newCid;
        this.core.trigger('ws-peerGone'); //this.core.trigger('peerGinfromone',payload);
        var message = {};
        message.uid = this.core.me().uid;
        message.connectionID = this.core.me().options.cid;
        this.sendData(message,'updatePeers');
    },
    //Pure websocket function, only needed to keep the connection-ids in sync with the uids
    _onUpdatePeers: function(payload,uid) {
        var peer = this.core.getPeerByUid(uid);
        console.log('updatePeer');
        if(peer !== undefined) {
            var peerCid = payload.connectionID;
            peer.options.cid = peerCid
        }
        else console.warn('badpeer '+uid);
    },
    //A peer has updated, tell the peer object to change
    _onPeerUpdated: function(payload,uid) {
        var peer = this.core.getPeerByUid(uid);
        if(peer !== undefined) {
            peer.events.trigger('ws-updatePeer',payload);
        }
        else console.warn('badpeer '+uid);
    },
    //A peer wants to have more info about a herd. send it
    _onGetHerdInfo: function(payload){
        //Everybody sends data back, if available
        var herdId = payload.herdId;
        var myherds = this.core.herds();
        var self = this;
        $.each(myherds, function(i, herd){
             if (herd.uid == herdId){
                 message = herd;
                 self.sendData(message,'herdUpdate');
             }
        })
    },
    _onHerdUpdate: function(payload){
        this.core.herd(payload);
    },
    //My stuff has changed, send over the changed data to the other peers
    _onMeChanged: function(evt, payload) {
        var self = evt.data.widget;
        console.log('mechanged '+ JSON.stringify(payload));
        //TODO: check if the payload is good?
        self.sendData(payload,"peerUpdated");
    },

    bind: function(types, data, fn) {
        var self = this;

        // A map of event/handle pairs, wrap each of them
        if(arguments.length===1) {
            var wrapped = {};
            $.each(types, function(type, fn) {
                wrapped[type] = function() {
                    return fn.apply(self, arguments);
                };
            });
            this.events.bind.apply(this.events, [wrapped]);
        }
        else {
            var args = [types];
            // Only callback given, but no data (types, fn), hence
            // `data` is the function
            if(arguments.length===2) {
                fn = data;
            }
            else {
                if (!$.isFunction(fn)) {
                    throw('bind: you might have a typo in the function name');
                }
                // Callback and data given (types, data, fn), hence include
                // the data in the argument list
                args.push(data);
            }

            args.push(function() {
                return fn.apply(self, arguments);
            });

            this.events.bind.apply(this.events, args);
        }

        return this;
    },
    trigger: function() {
        // There is no point in using trigger() insted of triggerHandler(), as
        // we don't fire native events
        this.events.triggerHandler.apply(this.events, arguments);
        return this;
    },
    // Basically a trigger that returns the return value of the last listener
    _triggerReturn: function() {
        return this.events.triggerHandler.apply(this.events, arguments);
    },

    closews: function() {
        if (this.ws){
            this.ws.close();
            this.ws = null;
        }
        else
            throw('No websocket active');
    },
    openws: function(url) {
        var core = this.core;
        var ws = new WebSocket(this.url, 'connect');
        ws.onopen=this._onOpen;
        ws.onmessage = this._onMessage;
        ws.onclose = this._onClose;
        ws.onerror = this._onError;
        ws.obj = this;
        this.ws =ws;
    }

};<commit_msg>HerdS met een sss<commit_after>$.Cow.Websocket.prototype = {

    _onOpen: function() {

        console.log('connected');
    },
    _onMessage: function(message) {
        var core = this.obj.core;
        console.debug('message: '+message.data);
        var data = JSON.parse(message.data);
        var uid = data.uid;
        var UID = core.UID;
        var action = data.action;
        var payload = data.payload;
        var target = data.target;
        switch (action) {
        //Messages from Server
            //webscocket confirms connection by returning a CID
            case 'connected':
                this.obj._onConnect(payload)
            break;
            //the server noticed a peer disconnecting and send its connection-id to the pool
            case 'peerGone':
                this.obj._onPeerGone(payload);
            break;
        //Messages from Peers: targeted messages
            //the client has joined and receives the status from peers: connection-id, uid, extent
            case 'informPeer':
                if(target == this.obj.core.UID) {
                    this.obj._onInformPeer(payload,uid);
                }
            break;
            //the alpha peer sends a sync message with new features and a feature request
            case 'syncPeer':
                if(target == this.obj.core.UID) {
                    this.obj._onSyncPeer(payload,uid);
                }
            break;
            //requested feats are returning from peer
            case 'requestedFeats':
                if(uid != UID) {
                    this.obj._onRequestedFeats(payload,uid);
                }
            break;

        //Messages from Peers: broadcasted messages
            //a peer is gone and everybody has a new connection-id, recieve a connectionID with UID
            case 'updatePeers':
                if(uid != UID) {
                    this.obj._onUpdatePeers(payload,uid);
                }
            break;
            //a new peer just joined, recieve its status: connection-id, uid, extent
            case 'newPeer':
                if(uid != this.obj.core.UID) {
                    this.obj._onNewPeer(payload,uid);
                }
            break;
            //a new peer just sent it's fidlist
            case 'newPeerFidList':
                if(uid != this.obj.core.UID) {
                    this.obj._onNewPeerFidList(payload,uid);
                }
            break;
            //a peer has changed, update the peer
            case 'peerUpdated':
                if(uid != UID) {
                    this.obj._onPeerUpdated(payload,uid);
                }
            break;

            //a new object was drawn or updated by a peer
            case 'newFeature':
                if(uid != UID) {
                    var item = JSON.parse(payload);
                    if (self.core.activeHerd == item.feature.properties.store)
                        core.featurestore().updateItem(item);
                }
            break;
            case 'updateFeature':
                if(uid != UID) {
                    var item = JSON.parse(payload);
                    if (self.core.activeHerd == item.feature.properties.store)
                        core.featurestore().updateItem(item);
                }
            break;
            //A peer request information about a herd
            case 'getHerdInfo':
                if(uid != UID) {
                    this.obj._onGetHerdInfo(payload);
                }
            break;
            //Info about a herd comes in...
            case 'herdUpdate':
                if(uid != UID) {
                    this.obj._onHerdUpdate(payload);
                }
            break;

        }
    },
    _onClose: function(event) {
        var code = event.code;
        var self = this;
        var reason = event.reason;
        var wasClean = event.wasClean;
        console.log('disconnected');
        this.close();
        this.obj.core.removeAllPeers();
        this.obj.core.trigger('ws-disconnected');
        //TODO: doe iets slimmers, hij hangt nu af van de global variable 'core'....
        var restart = function(){
            try{
                core.ws.closews();
            }
            catch(err){
                console.warn(err);
            }
            core.ws.openws();
        }
        setTimeout(restart,5000);
    },
    _onError: function(event, error) {
        //alert(error);
        console.warn('error: ' + event);
    },
    sendData: function(data, action, target){
        //TODO: check if data is an object
        var message = {};
        message.uid = this.core.UID;
        message.target = target;
        message.action = action;
        message.payload = data;
        if (this.ws && this.ws.readyState == 1){
            this.ws.send(JSON.stringify(message));
        }
    },
    _onConnect: function(payload) {
        var self = this;
        console.log('onConnect');

        var name = $('#'+this.core.options.namefield).val();

        var options = {};

        options.uid = this.core.UID;
        options.cid = payload.cid;
       options.family = 'alpha'; //used to check if client is able to act as alpha peer
        var me = this.core.peers(options);
        me.view({"extent":{"bottom":0,"left":0,"top":1,"right":1}});
        var herd = this.core.getHerdById(this.core.activeHerd);
        me.herd(herd);
        me.owner({"name":name});
        me.video({"state":"off"});
        console.log('nr peers: '+this.core.peers().length);
        this.core.trigger('ws-connected');
        this.sendData(options,'newPeer');
        //triggers _onNewPeer()

        var sendFidList = function(){
            var store = core.featurestore();
            var fids = store.getIdList();
            var message = {};
            message.fids = fids;
            message.storename = self.core.activeHerd;
            self.core.websocket().sendData(message, "newPeerFidList");

        }
        //TODO TT: at the moment we only check for 1 store to be loaded
        if (this.core.featurestore().loaded == true)
            sendFidList();
        else
            setTimeout(sendFidList, 2000);

    },

    //You just joined and you get from each peer the relevant info
    //Add it to your peerList
    _onInformPeer: function(payload,uid) {
        console.log('Got peerinfo from: '+uid);
        if(payload.options.uid !== undefined && payload.options.cid !== undefined) {
            var me = this.core.peers(payload.options);
            me.view({"extent":payload.view});
            me.position({"point":payload.position});
            me.owner(payload.owner);
            me.herd(payload.herd);
            if (payload.video)
                me.video(payload.video);
            this.core.trigger('ws-peerInfo');
        }
        else console.log('badpeer '+uid);
    },
    //A new peer has joined, send it your info, compare its features and add it to your
    //peerList
    _onNewPeer: function(payload,uid) {
        console.log('This peer just connected: '+uid);
        if(payload.uid !== undefined && payload.cid !== undefined) {
            console.log('adding peer');
            this.core.peers(payload);
            var message = {};
            message.options = this.core.me().options;
            message.view = this.core.me().view().extent;
            message.owner = this.core.me().owner();
            message.position = this.core.me().position().point;
            message.herd = this.core.me().herd();
            message.video = this.core.me().video();
            this.sendData(message,'informPeer',uid);
            this.core.trigger('ws-newPeer');
        }
        else console.warn('badpeer '+uid);
    },
    _amIAlpha: function(id,herd){ //find out wether I am alpha
        if (this.core.me().herd().uid == herd){ //I need to be part of the herd
            if (this.core.me().options.cid == id) //yes, I certainly am (the oldest)
                return true;
            else { //check again if younger peer turns out not to be from alpha family or not part of my herd
                id++;
                var nextpeer = this.core.getPeerByCid(id);
                if ((nextpeer.options.family && nextpeer.options.family != 'alpha') ||
                    (nextpeer.herd().uid && nextpeer.herd().uid != this.core.me().herd().uid))
                    this._amIAlpha(id, herd);    //I might still be alpha
            }
            return false; //Not the oldest in the herd
        }
        else return false; //Not part of herd
    },
    _onNewPeerFidList: function(payload, uid) {
        var self = this; //TODO !! : alpha check must incorporate activeherd!!
        //if (this._amIAlpha(0, payload.storename)){ //Check wether I'm alpha
            //console.log('I am alpha');
            if (self.core.activeHerd == payload.storename){
                var data = this.core.featurestore().compareIdList(payload.fids);
                var message = {};
                //First the requestlist
                message.requestlist = data.requestlist;
                message.pushlist = []; //empty
                message.storename = payload.storename;
                this.sendData(message,'syncPeer',uid);
                //Now the pushlist bit by bit
                message.requestlist = []; //empty
                var i = 0;
                $.each(data.pushlist, function(id, item){
                        message.pushlist.push(item);
                        i++;
                        if (i >= 1) { //max 1 feat every time
                            i = 0;
                            self.sendData(message,'syncPeer',uid);
                            message.pushlist = []; //empty
                        }
                });
                //sent the remainder of the list
                if (i > 0)
                    this.sendData(message,'syncPeer',uid);
            }
        //}
    },

    //The alpha peer sends a sync message including a list with new features and
    //a request list with features it wants from us
    _onSyncPeer: function(payload,uid) {
        var requested_fids = payload.requestlist;
        var pushed_feats = payload.pushlist;
        if (self.core.activeHerd == payload.storename){
            var store = this.core.featurestore();
            //First sent the features that are asked for
            if (requested_fids.length > 0){
                var message = {};
                message.features = store.requestFeatures(requested_fids);
                message.storename = payload.storename;
                this.sendData(message, 'requestedFeats');
            }
            //Now add the features that have been sent to the featurestore
            if (pushed_feats.length > 0){
                store.putFeatures(pushed_feats);
            }
        }
    },
    //Peer sends back requested features, now store them
    _onRequestedFeats: function(payload,uid) {
        var requested_feats = payload;
        if (self.core.me().herd().uid == payload.storename){
            var store = this.core.featurestore();
            if (requested_feats.length > 0){
                store.putFeatures(requested_feats);
            }
        }
    },
    //A peer has disconnected, remove it from your peerList and
    //send your new CID to the remaining peers
    _onPeerGone: function(payload) {
        var peerGone = payload.peerCid;
        var newCid = payload.newCid;
        this.core.removePeer(peerGone);
        this.core.me().options.cid = newCid;
        this.core.trigger('ws-peerGone'); //this.core.trigger('peerGinfromone',payload);
        var message = {};
        message.uid = this.core.me().uid;
        message.connectionID = this.core.me().options.cid;
        this.sendData(message,'updatePeers');
    },
    //Pure websocket function, only needed to keep the connection-ids in sync with the uids
    _onUpdatePeers: function(payload,uid) {
        var peer = this.core.getPeerByUid(uid);
        console.log('updatePeer');
        if(peer !== undefined) {
            var peerCid = payload.connectionID;
            peer.options.cid = peerCid
        }
        else console.warn('badpeer '+uid);
    },
    //A peer has updated, tell the peer object to change
    _onPeerUpdated: function(payload,uid) {
        var peer = this.core.getPeerByUid(uid);
        if(peer !== undefined) {
            peer.events.trigger('ws-updatePeer',payload);
        }
        else console.warn('badpeer '+uid);
    },
    //A peer wants to have more info about a herd. send it
    _onGetHerdInfo: function(payload){
        //Everybody sends data back, if available
        var herdId = payload.herdId;
        var myherds = this.core.herds();
        var self = this;
        $.each(myherds, function(i, herd){
             if (herd.uid == herdId){
                 message = herd;
                 self.sendData(message,'herdUpdate');
             }
        })
    },
    _onHerdUpdate: function(payload){
        this.core.herds(payload);
    },
    //My stuff has changed, send over the changed data to the other peers
    _onMeChanged: function(evt, payload) {
        var self = evt.data.widget;
        console.log('mechanged '+ JSON.stringify(payload));
        //TODO: check if the payload is good?
        self.sendData(payload,"peerUpdated");
    },

    bind: function(types, data, fn) {
        var self = this;

        // A map of event/handle pairs, wrap each of them
        if(arguments.length===1) {
            var wrapped = {};
            $.each(types, function(type, fn) {
                wrapped[type] = function() {
                    return fn.apply(self, arguments);
                };
            });
            this.events.bind.apply(this.events, [wrapped]);
        }
        else {
            var args = [types];
            // Only callback given, but no data (types, fn), hence
            // `data` is the function
            if(arguments.length===2) {
                fn = data;
            }
            else {
                if (!$.isFunction(fn)) {
                    throw('bind: you might have a typo in the function name');
                }
                // Callback and data given (types, data, fn), hence include
                // the data in the argument list
                args.push(data);
            }

            args.push(function() {
                return fn.apply(self, arguments);
            });

            this.events.bind.apply(this.events, args);
        }

        return this;
    },
    trigger: function() {
        // There is no point in using trigger() insted of triggerHandler(), as
        // we don't fire native events
        this.events.triggerHandler.apply(this.events, arguments);
        return this;
    },
    // Basically a trigger that returns the return value of the last listener
    _triggerReturn: function() {
        return this.events.triggerHandler.apply(this.events, arguments);
    },

    closews: function() {
        if (this.ws){
            this.ws.close();
            this.ws = null;
        }
        else
            throw('No websocket active');
    },
    openws: function(url) {
        var core = this.core;
        var ws = new WebSocket(this.url, 'connect');
        ws.onopen=this._onOpen;
        ws.onmessage = this._onMessage;
        ws.onclose = this._onClose;
        ws.onerror = this._onError;
        ws.obj = this;
        this.ws =ws;
    }

};<|endoftext|>


<commit_before>$.Cow.Websocket.prototype = {

	_onOpen: function() {

		console.log('connected');
	},
	_onMessage: function(message) {
		var core = this.obj.core;
		console.debug('message: '+message.data);
		var data = JSON.parse(message.data);
		var uid = data.uid;
		var UID = core.UID;
		var action = data.action;
		var payload = data.payload;
		var target = data.target;
		switch (action) {
		//Messages from Server
			//webscocket confirms connection by returning a CID
			case 'connected':
				this.obj._onConnect(payload)
            break;
			//the server noticed a peer disconnecting and send its connection-id to the pool
			case 'peerGone':
				this.obj._onPeerGone(payload);
			break;
		//Messages from Peers: targeted messages
			//the client has joined and receives the status from peers: connection-id, uid, extent
			case 'informPeer':
				if(target == this.obj.core.UID) {
					this.obj._onInformPeer(payload,uid);
				}
            break;
            //the alpha peer sends a sync message with new features and a feature request
        	case 'syncPeer':
        		if(target == this.obj.core.UID) {
					this.obj._onSyncPeer(payload,uid);
				}
            break;
            //requested feats are returning from peer
            case 'requestedFeats':
        		if(uid != UID) {
					this.obj._onRequestedFeats(payload,uid);
				}
            break;

		//Messages from Peers: broadcasted messages
			//a peer is gone and everybody has a new connection-id, recieve a connectionID with UID
			case 'updatePeers':
				if(uid != UID) {
					this.obj.__onUpdatePeer(payload,uid);
				}
            break;
			//a new peer just joined, recieve its status: connection-id, uid, extent
			case 'newPeer':
				if(uid != this.obj.core.UID) {
					this.obj._onNewPeer(payload,uid);
				}
            break;
            //a new peer just sent it's fidlist
            case 'newPeerFidList':
				if(uid != this.obj.core.UID) {
					this.obj._onNewPeerFidList(payload,uid);
				}
            break;
			//a peer has moved its map, recieve a new extent
			case 'peerMoved':
				if(uid != UID) {
					this.obj._onPeerMoved(payload,uid);
				}
			break;
			//a peer has changed its location
			case 'peerLocationChanged':
				if(uid != UID) {
					this.obj._onPeerChangedLocation(payload,uid);
				}
			break;
			//a peer has changed its params (name, herd)
			case 'peerParamsChanged':
				if(uid != UID) {
					this.obj._onPeerChangedParams(payload,uid);
				}
			break;

			//a new object was drawn or updated by a peer
			case 'newFeature':
				if(uid != UID) {
					var item = JSON.parse(payload);
					if (self.core.options.activeHerd == item.feature.properties.store)
					    core.featurestore().updateItem(item);
				}
			break;
			case 'updateFeature':
				if(uid != UID) {
					var item = JSON.parse(payload);
					if (self.core.options.activeHerd == item.feature.properties.store)
					    core.featurestore().updateItem(item);
				}
			break;
		}
	},
	_onClose: function(event) {
		var code = event.code;
		var self = this;
		var reason = event.reason;
		var wasClean = event.wasClean;
		console.log('disconnected');
		this.close();
		this.obj.core.trigger('disconnected');
		//TODO: doe iets slimmers, hij hangt nu af van de global variable 'core'....
		var restart = function(){
			try{
				core.ws.closews();
			}
			catch(err){
				console.warn(err);
			}
			core.ws.openws();
		}
		setTimeout(restart,5000);
	},
	_onError: function(event, error) {
		alert(error);
		console.log('error');
	},
	sendData: function(data, action, target){
		//TODO: check if data is an object
		var message = {};
		message.uid = this.core.UID;
		message.target = target;
		message.action = action;
		message.payload = data;
		if (this.ws && this.ws.readyState == 1){
			this.ws.send(JSON.stringify(message));
		}
	},
	_onConnect: function(payload) {
		var self = this;
		console.log('onConnect');
		//TODO TT: Extent should not be taken from map object directly but from mapwidget
		//var extent = this.core.map.getExtent();
		var extent = {left: 0, bottom: 0, top: 1, right: 1};
		var name = $('#'+this.core.options.namefield).val();

		var options = {};
		options.extent = JSON.parse(JSON.stringify(extent));
		options.uid = this.core.UID;
		options.cid = payload.cid;
		options.owner = name;
		options.herd = self.core.options.activeHerd;
		options.family = 'alpha'; //used to check if client is able to act as alpha peer
		var me = this.core.peers(options);
		console.log('nr peers: '+this.core.peers().length);
		this.core.trigger('connected');
		this.sendData(options,'newPeer');

		var sendFidList = function(){
			var store = core.featurestore();
            var fids = store.getIdList();
            var message = {};
            message.fids = fids;
            message.storename = self.core.options.activeHerd;
            self.core.websocket().sendData(message, "newPeerFidList");

		}
		//TODO TT: at the moment we only check for 1 store to be loaded
		if (this.core.featurestore().loaded == true)
			sendFidList();
		else
			setTimeout(sendFidList, 2000);

	},

	_onDBLoaded: function(){

	},
	//You just joined and you get from each peer the relevant info
	//Add it to your peerList
	_onInformPeer: function(payload,uid) {
		console.log('Got peerinfo from: '+uid);
		if(payload.uid !== undefined && payload.extent !== undefined && payload.cid !== undefined) {
			this.core.peers(payload);
			this.core.trigger('peerInfo');
		}
		else console.log('badpeer');
	},
	//A new peer has joined, send it your info, compare its features and add it to your
	//peerList
	_onNewPeer: function(payload,uid) {
		console.log('This peer just connected: '+uid);
		if(payload.uid !== undefined && payload.extent !== undefined && payload.cid !== undefined) {
			this.core.peers(payload);
			var message = this.core.me().options;
			this.sendData(message,'informPeer',uid);
			this.core.trigger('newPeer');
		}
		else console.warn('badpeer');
	},
	_amIAlpha: function(id,herd){ //find out wether I am alpha
	    if (this.core.me().options.herd == herd){ //I need to be part of the herd
            if (this.core.me().options.cid == id) //yes, I certainly am (the oldest)
                return true;
            else { //check again if younger peer turns out not to be from alpha family or not part of my herd
                id++;
                var nextpeer = this.core.getPeerByCid(id);
                if ((nextpeer.options.family && nextpeer.options.family != 'alpha') ||
                    (nextpeer.options.herd && nextpeer.options.herd != this.core.me().options.herd))
                    this._amIAlpha(id, herd);	//I might still be alpha
            }
            return false; //Not the oldest in the herd
        }
        else return false; //Not part of herd
	},
	_onNewPeerFidList: function(payload, uid) {
		var self = this; //TODO !! : alpha check must incorporate activeherd!!
		//if (this._amIAlpha(0, payload.storename)){ //Check wether I'm alpha
			//console.log('I am alpha');
			if (self.core.options.activeHerd == payload.storename){
                var data = this.core.featurestore().compareIdList(payload.fids);
                var message = {};
                //First the requestlist
                message.requestlist = data.requestlist;
                message.pushlist = []; //empty
                message.storename = payload.storename;
                this.sendData(message,'syncPeer',uid);
                //Now the pushlist bit by bit
                message.requestlist = []; //empty
                var i = 0;
                $.each(data.pushlist, function(id, item){
                        message.pushlist.push(item);
                        i++;
                        if (i >= 1) { //max 1 feat every time
                            i = 0;
                            self.sendData(message,'syncPeer',uid);
                            message.pushlist = []; //empty
                        }
                });
                //sent the remainder of the list
                if (i > 0)
                    this.sendData(message,'syncPeer',uid);
			}
		//}
	},

	//The alpha peer sends a sync message including a list with new features and
	//a request list with features it wants from us
	_onSyncPeer: function(payload,uid) {
		var requested_fids = payload.requestlist;
		var pushed_feats = payload.pushlist;
		if (self.core.options.activeHerd == payload.storename){
            var store = this.core.featurestore();
            //First sent the features that are asked for
            if (requested_fids.length > 0){
                var message = {};
                message.features = store.requestFeatures(requested_fids);
                message.storename = payload.storename;
                this.sendData(message, 'requestedFeats');
            }
            //Now add the features that have been sent to the featurestore
            if (pushed_feats.length > 0){
                store.putFeatures(pushed_feats);
            }
        }
	},
	//Peer sends back requested features, now store them
	_onRequestedFeats: function(payload,uid) {
		var requested_feats = payload;
		if (self.core.me().options.herd == payload.storename){
            var store = this.core.featurestore();
            if (requested_feats.length > 0){
                store.putFeatures(requested_feats);
            }
        }
	},
	//A peer has disconnected, remove it from your peerList and
	//send your new CID to the remaining peers
	_onPeerGone: function(payload) {
		var peerGone = payload.peerCid;
		var newCid = payload.newCid;
		this.core.removePeer(peerGone);
		this.core.me().options.cid = newCid;
		//this.core.trigger('peerGinfromone',payload);
		var message = {};
		message.uid = this.core.me().uid;
		message.connectionID = this.core.me().options.cid;
		this.sendData(message,'updatePeers');
	},
	//Pure websocket function, only needed to keep the connection-ids in sync with the uids
	__onUpdatePeer: function(payload,uid) {
		var peer = this.core.getPeerByUid(uid);
		console.log('updatePeer');
		if(peer !== undefined) {
			var peerCid = payload.connectionID;
			peer.options.cid = peerCid
		}
		else console.warn('badpeer');
	},
	_onPeerMoved: function(payload,uid) {
		var peer = this.core.getPeerByUid(uid);
		if(peer !== undefined) {
			peer.events.trigger('peerMoved',payload);
			//console.log('peerMoved');
		}
		else console.warn('badpeer');
	},
	//a peer has changed location, redraw its position on the map
	_onPeerChangedLocation: function(payload, uid){
		var peer = this.core.getPeerByUid(uid);

		if(peer !== undefined) {
			peer.events.trigger('locationChange',payload);
			//console.log('locationChange');
		}
		else console.warn('badpeer');
	},
	//a peer has changed its parameters, reset its peer options
	_onPeerChangedParams: function(payload, uid){
		var peer = this.core.getPeerByUid(uid);

		if(peer !== undefined) {
			peer.events.trigger('paramChange',payload);
			//console.log('locationChange');
		}
		else console.warn('badpeer');
	},
	_onMapMoved: function(evt,extent) {
		var self = evt.data.widget;
		//if you initialise the map it gives a mapmove event, but core.me() is not yet finished
		if(self.core.me() !== undefined) {
			self.core.me().extent(extent);
			var message = {};
			message.extent = self.core.me().extent();
			message.owner = self.core.me().options.owner;
			self.sendData(message,'peerMoved');
		}
	},
	//my location has changed, send update to world
	_onLocationChanged: function(evt, payload) {
		var self = evt.data.widget;
		var position = payload.position;
		var message = {};
		message.position = position;
		message.uid = self.core.UID;
		self.sendData(message,'peerLocationChanged');
	},
	//my params changed, send update to world
	_onParamsChanged: function(evt, payload) {
		var self = evt.data.widget;
		var name = payload.name;
		var herd = payload.herd;
		var message = {};
		message.name = name;
		message.herd = herd;
		message.uid = self.core.UID;
		self.sendData(message,'peerParamsChanged');
	},

	bind: function(types, data, fn) {
        var self = this;

        // A map of event/handle pairs, wrap each of them
        if(arguments.length===1) {
            var wrapped = {};
            $.each(types, function(type, fn) {
                wrapped[type] = function() {
                    return fn.apply(self, arguments);
                };
            });
            this.events.bind.apply(this.events, [wrapped]);
        }
        else {
            var args = [types];
            // Only callback given, but no data (types, fn), hence
            // `data` is the function
            if(arguments.length===2) {
                fn = data;
            }
            else {
                if (!$.isFunction(fn)) {
                    throw('bind: you might have a typo in the function name');
                }
                // Callback and data given (types, data, fn), hence include
                // the data in the argument list
                args.push(data);
            }

            args.push(function() {
                return fn.apply(self, arguments);
            });

            this.events.bind.apply(this.events, args);
        }

        return this;
    },
	trigger: function() {
        // There is no point in using trigger() insted of triggerHandler(), as
        // we don't fire native events
        this.events.triggerHandler.apply(this.events, arguments);
        return this;
    },
    // Basically a trigger that returns the return value of the last listener
    _triggerReturn: function() {
        return this.events.triggerHandler.apply(this.events, arguments);
    },
	closews: function() {
		if (this.ws){
			this.ws.close();
			this.ws = null;
		}
		else
			throw('No websocket active');
    },
	openws: function(url) {
		var core = this.core;
		var ws = new WebSocket(this.url, 'connect');
		ws.onopen=this._onOpen;
		ws.onmessage = this._onMessage;
		ws.onclose = this._onClose;
		ws.onerror = this._onError;
		ws.obj = this;
		this.ws =ws;
	}

};<commit_msg>Removed annoying alert from websocket connect error (became console.warn)<commit_after>$.Cow.Websocket.prototype = {

	_onOpen: function() {

		console.log('connected');
	},
	_onMessage: function(message) {
		var core = this.obj.core;
		console.debug('message: '+message.data);
		var data = JSON.parse(message.data);
		var uid = data.uid;
		var UID = core.UID;
		var action = data.action;
		var payload = data.payload;
		var target = data.target;
		switch (action) {
		//Messages from Server
			//webscocket confirms connection by returning a CID
			case 'connected':
				this.obj._onConnect(payload)
            break;
			//the server noticed a peer disconnecting and send its connection-id to the pool
			case 'peerGone':
				this.obj._onPeerGone(payload);
			break;
		//Messages from Peers: targeted messages
			//the client has joined and receives the status from peers: connection-id, uid, extent
			case 'informPeer':
				if(target == this.obj.core.UID) {
					this.obj._onInformPeer(payload,uid);
				}
            break;
            //the alpha peer sends a sync message with new features and a feature request
        	case 'syncPeer':
        		if(target == this.obj.core.UID) {
					this.obj._onSyncPeer(payload,uid);
				}
            break;
            //requested feats are returning from peer
            case 'requestedFeats':
        		if(uid != UID) {
					this.obj._onRequestedFeats(payload,uid);
				}
            break;

		//Messages from Peers: broadcasted messages
			//a peer is gone and everybody has a new connection-id, recieve a connectionID with UID
			case 'updatePeers':
				if(uid != UID) {
					this.obj.__onUpdatePeer(payload,uid);
				}
            break;
			//a new peer just joined, recieve its status: connection-id, uid, extent
			case 'newPeer':
				if(uid != this.obj.core.UID) {
					this.obj._onNewPeer(payload,uid);
				}
            break;
            //a new peer just sent it's fidlist
            case 'newPeerFidList':
				if(uid != this.obj.core.UID) {
					this.obj._onNewPeerFidList(payload,uid);
				}
            break;
			//a peer has moved its map, recieve a new extent
			case 'peerMoved':
				if(uid != UID) {
					this.obj._onPeerMoved(payload,uid);
				}
			break;
			//a peer has changed its location
			case 'peerLocationChanged':
				if(uid != UID) {
					this.obj._onPeerChangedLocation(payload,uid);
				}
			break;
			//a peer has changed its params (name, herd)
			case 'peerParamsChanged':
				if(uid != UID) {
					this.obj._onPeerChangedParams(payload,uid);
				}
			break;

			//a new object was drawn or updated by a peer
			case 'newFeature':
				if(uid != UID) {
					var item = JSON.parse(payload);
					if (self.core.options.activeHerd == item.feature.properties.store)
					    core.featurestore().updateItem(item);
				}
			break;
			case 'updateFeature':
				if(uid != UID) {
					var item = JSON.parse(payload);
					if (self.core.options.activeHerd == item.feature.properties.store)
					    core.featurestore().updateItem(item);
				}
			break;
		}
	},
	_onClose: function(event) {
		var code = event.code;
		var self = this;
		var reason = event.reason;
		var wasClean = event.wasClean;
		console.log('disconnected');
		this.close();
		this.obj.core.trigger('disconnected');
		//TODO: doe iets slimmers, hij hangt nu af van de global variable 'core'....
		var restart = function(){
			try{
				core.ws.closews();
			}
			catch(err){
				console.warn(err);
			}
			core.ws.openws();
		}
		setTimeout(restart,5000);
	},
	_onError: function(event, error) {
		//alert(error);
		console.warn('error: ' + event);
	},
	sendData: function(data, action, target){
		//TODO: check if data is an object
		var message = {};
		message.uid = this.core.UID;
		message.target = target;
		message.action = action;
		message.payload = data;
		if (this.ws && this.ws.readyState == 1){
			this.ws.send(JSON.stringify(message));
		}
	},
	_onConnect: function(payload) {
		var self = this;
		console.log('onConnect');
		//TODO TT: Extent should not be taken from map object directly but from mapwidget
		//var extent = this.core.map.getExtent();
		var extent = {left: 0, bottom: 0, top: 1, right: 1};
		var name = $('#'+this.core.options.namefield).val();

		var options = {};
		options.extent = JSON.parse(JSON.stringify(extent));
		options.uid = this.core.UID;
		options.cid = payload.cid;
		options.owner = name;
		options.herd = self.core.options.activeHerd;
		options.family = 'alpha'; //used to check if client is able to act as alpha peer
		var me = this.core.peers(options);
		console.log('nr peers: '+this.core.peers().length);
		this.core.trigger('connected');
		this.sendData(options,'newPeer');

		var sendFidList = function(){
			var store = core.featurestore();
            var fids = store.getIdList();
            var message = {};
            message.fids = fids;
            message.storename = self.core.options.activeHerd;
            self.core.websocket().sendData(message, "newPeerFidList");

		}
		//TODO TT: at the moment we only check for 1 store to be loaded
		if (this.core.featurestore().loaded == true)
			sendFidList();
		else
			setTimeout(sendFidList, 2000);

	},

	_onDBLoaded: function(){

	},
	//You just joined and you get from each peer the relevant info
	//Add it to your peerList
	_onInformPeer: function(payload,uid) {
		console.log('Got peerinfo from: '+uid);
		if(payload.uid !== undefined && payload.extent !== undefined && payload.cid !== undefined) {
			this.core.peers(payload);
			this.core.trigger('peerInfo');
		}
		else console.log('badpeer');
	},
	//A new peer has joined, send it your info, compare its features and add it to your
	//peerList
	_onNewPeer: function(payload,uid) {
		console.log('This peer just connected: '+uid);
		if(payload.uid !== undefined && payload.extent !== undefined && payload.cid !== undefined) {
			this.core.peers(payload);
			var message = this.core.me().options;
			this.sendData(message,'informPeer',uid);
			this.core.trigger('newPeer');
		}
		else console.warn('badpeer');
	},
	_amIAlpha: function(id,herd){ //find out wether I am alpha
	    if (this.core.me().options.herd == herd){ //I need to be part of the herd
            if (this.core.me().options.cid == id) //yes, I certainly am (the oldest)
                return true;
            else { //check again if younger peer turns out not to be from alpha family or not part of my herd
                id++;
                var nextpeer = this.core.getPeerByCid(id);
                if ((nextpeer.options.family && nextpeer.options.family != 'alpha') ||
                    (nextpeer.options.herd && nextpeer.options.herd != this.core.me().options.herd))
                    this._amIAlpha(id, herd);	//I might still be alpha
            }
            return false; //Not the oldest in the herd
        }
        else return false; //Not part of herd
	},
	_onNewPeerFidList: function(payload, uid) {
		var self = this; //TODO !! : alpha check must incorporate activeherd!!
		//if (this._amIAlpha(0, payload.storename)){ //Check wether I'm alpha
			//console.log('I am alpha');
			if (self.core.options.activeHerd == payload.storename){
                var data = this.core.featurestore().compareIdList(payload.fids);
                var message = {};
                //First the requestlist
                message.requestlist = data.requestlist;
                message.pushlist = []; //empty
                message.storename = payload.storename;
                this.sendData(message,'syncPeer',uid);
                //Now the pushlist bit by bit
                message.requestlist = []; //empty
                var i = 0;
                $.each(data.pushlist, function(id, item){
                        message.pushlist.push(item);
                        i++;
                        if (i >= 1) { //max 1 feat every time
                            i = 0;
                            self.sendData(message,'syncPeer',uid);
                            message.pushlist = []; //empty
                        }
                });
                //sent the remainder of the list
                if (i > 0)
                    this.sendData(message,'syncPeer',uid);
			}
		//}
	},

	//The alpha peer sends a sync message including a list with new features and
	//a request list with features it wants from us
	_onSyncPeer: function(payload,uid) {
		var requested_fids = payload.requestlist;
		var pushed_feats = payload.pushlist;
		if (self.core.options.activeHerd == payload.storename){
            var store = this.core.featurestore();
            //First sent the features that are asked for
            if (requested_fids.length > 0){
                var message = {};
                message.features = store.requestFeatures(requested_fids);
                message.storename = payload.storename;
                this.sendData(message, 'requestedFeats');
            }
            //Now add the features that have been sent to the featurestore
            if (pushed_feats.length > 0){
                store.putFeatures(pushed_feats);
            }
        }
	},
	//Peer sends back requested features, now store them
	_onRequestedFeats: function(payload,uid) {
		var requested_feats = payload;
		if (self.core.me().options.herd == payload.storename){
            var store = this.core.featurestore();
            if (requested_feats.length > 0){
                store.putFeatures(requested_feats);
            }
        }
	},
	//A peer has disconnected, remove it from your peerList and
	//send your new CID to the remaining peers
	_onPeerGone: function(payload) {
		var peerGone = payload.peerCid;
		var newCid = payload.newCid;
		this.core.removePeer(peerGone);
		this.core.me().options.cid = newCid;
		//this.core.trigger('peerGinfromone',payload);
		var message = {};
		message.uid = this.core.me().uid;
		message.connectionID = this.core.me().options.cid;
		this.sendData(message,'updatePeers');
	},
	//Pure websocket function, only needed to keep the connection-ids in sync with the uids
	__onUpdatePeer: function(payload,uid) {
		var peer = this.core.getPeerByUid(uid);
		console.log('updatePeer');
		if(peer !== undefined) {
			var peerCid = payload.connectionID;
			peer.options.cid = peerCid
		}
		else console.warn('badpeer');
	},
	_onPeerMoved: function(payload,uid) {
		var peer = this.core.getPeerByUid(uid);
		if(peer !== undefined) {
			peer.events.trigger('peerMoved',payload);
			//console.log('peerMoved');
		}
		else console.warn('badpeer');
	},
	//a peer has changed location, redraw its position on the map
	_onPeerChangedLocation: function(payload, uid){
		var peer = this.core.getPeerByUid(uid);

		if(peer !== undefined) {
			peer.events.trigger('locationChange',payload);
			//console.log('locationChange');
		}
		else console.warn('badpeer');
	},
	//a peer has changed its parameters, reset its peer options
	_onPeerChangedParams: function(payload, uid){
		var peer = this.core.getPeerByUid(uid);

		if(peer !== undefined) {
			peer.events.trigger('paramChange',payload);
			//console.log('locationChange');
		}
		else console.warn('badpeer');
	},
	_onMapMoved: function(evt,extent) {
		var self = evt.data.widget;
		//if you initialise the map it gives a mapmove event, but core.me() is not yet finished
		if(self.core.me() !== undefined) {
			self.core.me().extent(extent);
			var message = {};
			message.extent = self.core.me().extent();
			message.owner = self.core.me().options.owner;
			self.sendData(message,'peerMoved');
		}
	},
	//my location has changed, send update to world
	_onLocationChanged: function(evt, payload) {
		var self = evt.data.widget;
		var position = payload.position;
		var message = {};
		message.position = position;
		message.uid = self.core.UID;
		self.sendData(message,'peerLocationChanged');
	},
	//my params changed, send update to world
	_onParamsChanged: function(evt, payload) {
		var self = evt.data.widget;
		var name = payload.name;
		var herd = payload.herd;
		var message = {};
		message.name = name;
		message.herd = herd;
		message.uid = self.core.UID;
		self.sendData(message,'peerParamsChanged');
	},

	bind: function(types, data, fn) {
        var self = this;

        // A map of event/handle pairs, wrap each of them
        if(arguments.length===1) {
            var wrapped = {};
            $.each(types, function(type, fn) {
                wrapped[type] = function() {
                    return fn.apply(self, arguments);
                };
            });
            this.events.bind.apply(this.events, [wrapped]);
        }
        else {
            var args = [types];
            // Only callback given, but no data (types, fn), hence
            // `data` is the function
            if(arguments.length===2) {
                fn = data;
            }
            else {
                if (!$.isFunction(fn)) {
                    throw('bind: you might have a typo in the function name');
                }
                // Callback and data given (types, data, fn), hence include
                // the data in the argument list
                args.push(data);
            }

            args.push(function() {
                return fn.apply(self, arguments);
            });

            this.events.bind.apply(this.events, args);
        }

        return this;
    },
	trigger: function() {
        // There is no point in using trigger() insted of triggerHandler(), as
        // we don't fire native events
        this.events.triggerHandler.apply(this.events, arguments);
        return this;
    },
    // Basically a trigger that returns the return value of the last listener
    _triggerReturn: function() {
        return this.events.triggerHandler.apply(this.events, arguments);
    },
	closews: function() {
		if (this.ws){
			this.ws.close();
			this.ws = null;
		}
		else
			throw('No websocket active');
    },
	openws: function(url) {
		var core = this.core;
		var ws = new WebSocket(this.url, 'connect');
		ws.onopen=this._onOpen;
		ws.onmessage = this._onMessage;
		ws.onclose = this._onClose;
		ws.onerror = this._onError;
		ws.obj = this;
		this.ws =ws;
	}

};<|endoftext|>


<commit_before>/**
 *  Reactor
 *  =======
 *
 *  An "reactive" object, which notifies it's subscribers as properties got changed.
 *
 *  ToDo:
 *
 *  - check if multiple reactors receive different IDs and are therefore seperated
 */

var list = [],    // record of reactors

    SYNC = 100;   // delay for exchange - getter/setter

/**
 *  [getReactor description]
 *  @return {[type]} [description]
 */

var getReactor = function() {

  var args = [], obj = Object.create( Object.prototype );

  args.push.apply( args, arguments );

  list.push({ reference: {}, callbacks: args });

  checkProperties( list.length - 1, obj );

  return obj;
};

/**
 *  [checkProperties description]
 *
 *  @param  {[type]} id      [description]
 *  @param  {[type]} current [description]
 *  @return {[type]}         [description]
 */

function checkProperties ( id, current ) {

  var last    = list[id].reference,
      diff    = getDifferences( last, current ),

      add     = diff.add,
      remove  = diff.remove,

      i, l;

  // add - watching | unwatch - remove
  if ( add.length || remove.length ) {

    for ( i = 0, l = add.length; i < l; i++ ) defineProperty( id, current, add[i] );

    for ( i = 0, l = remove.length; i < l; i++ ) delete last[ remove[i] ];
  }

  setTimeout( checkProperties, SYNC, id, current );
}

/**
 *  [getDifferences description]
 *  @param  {[type]} last    [description]
 *  @param  {[type]} current [description]
 *  @return {[type]}         [description]
 */

var getKeys = Object.keys;

function getDifferences ( last, current ) {

  var lastKeys    = getKeys( last ),
      currentKeys = getKeys( current ),

      add         = [],
      remove      = [],

      i, l;

  for ( i = 0, l = lastKeys.length; i < l; i++ ) {

    if ( current[ lastKeys[i] ] == void 0 ) remove.push( lastKeys[i] );
  }

  for ( i = 0, l = currentKeys.length; i < l; i++ ) {

    if ( last[ currentKeys[i] ] == void 0 ) add.push( currentKeys[i] );
  }

  return { add: add, remove: remove };
}

/**
 *  [defineProperty description]
 *  @param  {[type]} id      [description]
 *  @param  {[type]} current [description]
 *  @param  {[type]} prop    [description]
 *  @return {[type]}         [description]
 */

function defineProperty ( id, current, prop ) {

  var getter = function() { return list[id].reference[ prop ]; },

      setter = function ( value ) {

        // prevent redundancy: old = new
        if ( value === list[id].reference[ prop ] ) return;

        list[id].reference[ prop ] = value;

        var callbacks = list[id].callbacks,

            i, l;

        for ( i = 0, l = callbacks.length; i < l; i++ ) {

          callbacks[i].apply( callbacks[i], [ prop, value ] );
        }

        return value;
      };

  // initial call + set diff
  setter( current[prop] );

  // setup watcher
  Object.defineProperty( current, prop, {

    enumerable  : true,
    configurable: true,
    get         : getter,
    set         : setter
  });

}
<commit_msg>allow deep nesting<commit_after>/**
 *  Reactor
 *  =======
 *
 *  An "reactive" object, which notifies it's subscribers as properties got changed.
 *
 *  ToDo:
 *
 *  - check if multiple reactors receive different IDs and are therefore seperated
 */

var list = [],    // record of reactors

    SYNC = 100;   // delay for exchange - getter/setter

/**
 *  [getReactor description] can use multiple callbacks
 *  @return {[type]} [description]
 */

var getReactor = function() {

  var args = [], obj = Object.create( Object.prototype );

  args.push.apply( args, arguments );

  list.push({ reference: {}, callbacks: args });

  checkProperties( list.length - 1, obj );

  return obj;
};

/**
 *  [checkProperties description]
 *
 *  @param  {[type]} id      [description]
 *  @param  {[type]} current [description]
 *  @return {[type]}         [description]
 */

function checkProperties ( id, current ) {

  var last    = list[id].reference,
      diff    = getDifferences( last, current ),

      add     = diff.add,
      remove  = diff.remove,

      i, l;

  // add - watching | unwatch - remove
  if ( add.length || remove.length ) {

    for ( i = 0, l = add.length; i < l; i++ ) defineProperty( id, current, add[i] );

    for ( i = 0, l = remove.length; i < l; i++ ) delete last[ remove[i] ];
  }

  setTimeout( checkProperties, SYNC, id, current );
}

/**
 *  [getDifferences description]
 *  @param  {[type]} last    [description]
 *  @param  {[type]} current [description]
 *  @return {[type]}         [description]
 */

var getKeys = Object.keys;

function getDifferences ( last, current ) {

  var lastKeys    = getKeys( last ),
      currentKeys = getKeys( current ),

      add         = [],
      remove      = [],

      i, l;

  for ( i = 0, l = lastKeys.length; i < l; i++ ) {

    if ( current[ lastKeys[i] ] == void 0 ) remove.push( lastKeys[i] );
  }

  for ( i = 0, l = currentKeys.length; i < l; i++ ) {

    if ( last[ currentKeys[i] ] == void 0 ) add.push( currentKeys[i] );
  }

  return { add: add, remove: remove };
}

// - array & object dont geta new value set, but the lengths of their keys can be changed !

// TODO:
// - still problem with object 'delete' won't trigger as the setter - no new value send !
// - array.lenght, -1 || clearing an array wont triggger !
// - no functions can be shared ! -> for handling logic, better use RPC and the custom channel
// - deep nesting for complex sync

/**
 *  [defineProperty description]
 *  @param  {[type]} id      [description]
 *  @param  {[type]} current [description]
 *  @param  {[type]} prop    [description]
 *  @return {[type]}         [description]
 */

function defineProperty ( id, current, prop ) {

  var getter = function() { return list[id].reference[ prop ]; }, // set array ! change it

      setter = function ( value ) {

        // prevent redundancy: old = new
        if ( value === list[id].reference[ prop ] ) return;

        if ( typeof value === 'object' ) {

          // Array
          if ( !Array.isArray(value) ) {

            // method cloaking: @WatchJS |https://github.com/melanke/Watch.JS/blob/master/src/watch.js
            var methods = [ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift' ];

            for ( var i = 0, l = methods.length; i < l; i++ ) setMethod( value, methods[ i ] );

          } else { // Object

            value = utils.extend( getReactor( function ( inner, value ) {

              var result = list[id].reference[ prop ];

              result[inner] = value;

              return refer( result );

            }), value );
          }

        }

        refer( value );

        function refer ( value ) {

          list[id].reference[ prop ] = value;

          var callbacks = list[id].callbacks,

              i, l;

          for ( i = 0, l = callbacks.length; i < l; i++ ) {

            callbacks[i].apply( callbacks[i], [ prop, value ] );
          }

          return value;
        }

        // call protype then - and trigger the callback !
        function setMethod( arr, fn ) {

          arr[ fn ] = function(){

            Array.prototype[ fn ].apply( this, arguments );

            return refer( arr );
          };
        }

      };

  // initial call + set diff
  setter( current[prop] );

  // setup watcher
  Object.defineProperty( current, prop, {

    enumerable  : true,
    configurable: true,
    get         : getter,
    set         : setter
  });

}
<|endoftext|>


<commit_before>var app = new Vue({
    el: '#app',
    data: {
        books: [],
        MySearch: '',
        orderCol: 'id',
        orderInverse: 1,
        pagination: {
            maxPage: 4,
            current: 1,
            totalItems: 0,
            totalPages: 0,
            listPagination: [],
        },
    },
    methods: {
        filterOrderBy: function (e, col) {
            e.preventDefault();
            this.orderCol = col;
            this.orderInverse = this.orderInverse * (-1);
            //console.log(this.orderInverse);
        },
        previous: function (e) {
            e.preventDefault();

            if(this.pagination.current === 1){
                return false;
            }
            this.pagination.current = this.pagination.current - 1;

            console.log('maxPage: ' + this.pagination.maxPage);
            console.log('current: ' + this.pagination.current);
            console.log('totalItems: ' + this.pagination.totalItems);
            console.log('totalPages: ' + this.pagination.totalPages);
            console.log('listPagination: ' + this.pagination.listPagination);
        },
        pagePagination: function (e, id) {
            e.preventDefault();

            if(this.pagination.current === this.pagination.totalPages){
                return false;
            }
            this.pagination.current = this.pagination.current + 1;

            console.log('maxPage: ' + this.pagination.maxPage);
            console.log('current: ' + this.pagination.current);
            console.log('totalItems: ' + this.pagination.totalItems);
            console.log('totalPages: ' + this.pagination.totalPages);
            console.log('listPagination: ' + this.pagination.listPagination);
        },
        next: function (e) {
            e.preventDefault();
            console.log('maxPage: ' + this.pagination.maxPage);
            console.log('current: ' + this.pagination.current);
            console.log('totalItems: ' + this.pagination.totalItems);
            console.log('totalPages: ' + this.pagination.totalPages);
            console.log('listPagination: ' + this.pagination.listPagination);
        },
    },
    ready: function () {
        var self = this;
        self.$http.get('dataServer.json').then(function (response) {
            self.pagination.totalItems = response.data.length;
            self.pagination.totalPages = Math.ceil(response.data.lenght / self.pagination.maxPage);

            self.books = response.data;
        });
    },
});<commit_msg>vue.js_1.paginacao_parte_3<commit_after>var app = new Vue({
    el: '#app',
    data: {
        books: [],
        MySearch: '',
        orderCol: 'id',
        orderInverse: 1,
        pagination: {
            maxPage: 4,
            current: 1,
            totalItems: 0,
            totalPages: 0,
            listPagination: [],
        },
    },
    methods: {
        filterOrderBy: function (e, col) {
            e.preventDefault();
            this.orderCol = col;
            this.orderInverse = this.orderInverse * (-1);
            //console.log(this.orderInverse);
        },
        previous: function (e) {
            e.preventDefault();

            if (this.pagination.current === 1) {
                return false;
            }
            this.pagination.current = this.pagination.current - 1;
            this.books = this.pagination.listPagination[this.pagination.current - 1];
        },
        pagePagination: function (e, id) {
            e.preventDefault();

        },
        next: function (e) {
            e.preventDefault();
            if (this.pagination.current === this.pagination.totalPages) {
                return false;
            }
            this.pagination.current = this.pagination.current + 1;
            this.books = this.pagination.listPagination[this.pagination.current - 1];
        },
    },
    ready: function () {
        var self = this;
        self.$http.get('dataServer.json').then(function (response) {
            self.pagination.totalItems = response.data.length;
            self.pagination.totalPages = Math.ceil(response.data.lenght / self.pagination.maxPage);

            var aux = [];
            for (var k in response.data) {
                aux.push(response.data[k]);
                if (aux.length === self.pagination.maxPage) {
                    self.pagination.listPagination.push(aux);
                    aux = [];
                }
            }
            if (aux.length > 0) {
                self.pagination.listPagination.push(aux);
            }

            self.books = self.pagination.listPagination[0];
        });
    },
});<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import CenterText from './styling/CenterText';
import Box from './styling/Box';

class Quiz extends Component {
    render() {
        const quizInfo =
            <CenterText>

Vraag: {this.props.questionNum} Ronde: {this.props.roundNum}

            </CenterText>;

        const teamInfo = this.props.teams.map((team) =>
            <Box key={team.teamName}>

Team naam: {team.teamName}

                   Punten in deze ronde: {team.roundScore}

                   Totale rondepunten: {team.totalScore}

            </Box>
        );

        let question;
        if (this.props.question && this.props.status !== 'invisible') {
            question =
                <CenterText>

                        {this.props.question.category}

                        {this.props.question.question}

                        {this.props.status === 'answer' ?

                                {this.props.question.answer}

                            : ''
                        }
                </CenterText>
        } else question = '';

        let results;
        if (this.props.results && this.props.status !== 'invisible') {
            results = this.props.results.map((result) =>
                <Box key={result.teamName + '1'}>
                    {result.teamName}

                    {result.answer}

                    {result.approved ? 'Goed' : 'Fout'}
                </Box>
            );
        } else results = '';

        return (

{quizInfo}

{teamInfo}

{question}

{results}

    )};
}

Quiz.propTypes = {
    teams: PropTypes.array.isRequired,
    question: PropTypes.object,
    status: PropTypes.string.isRequired,
    results: PropTypes.array,
    questionNum: PropTypes.number.isRequired,
    roundNum: PropTypes.number.isRequired
};

export default Quiz;<commit_msg>Added team status while question is open<commit_after>import React, {Component, PropTypes} from 'react';
import CenterText from './styling/CenterText';
import Box from './styling/Box';

class Quiz extends Component {
    render() {
        const quizInfo =
            <CenterText>

Vraag: {this.props.questionNum} Ronde: {this.props.roundNum}

            </CenterText>;

        const teamInfo = this.props.teams.map((team) =>
            <Box key={team.teamName}>

Team naam: {team.teamName}

                   Punten in deze ronde: {team.roundScore}

                   Totale rondepunten: {team.totalScore}

            </Box>
        );

        let question;
        if (this.props.question && this.props.status !== 'invisible') {
            question =
                <CenterText>

{this.props.question.category}

{this.props.question.question}

                        {this.props.status === 'answer' ?

{this.props.question.answer}

                            : ''
                        }
                </CenterText>
        } else question = '';

        let results;
        if (this.props.results && this.props.status !== 'invisible') {
            results = this.props.results.map((result) =>
                <Box key={result.teamName + '1'}>

Team: {result.teamName}

                    {this.props.status === 'answer' ?

Antwoord: {result.answer}

                            {result.approved !== null ?

{result.approved ? 'Goed' : 'Fout'}

                                : ''
                            }

                        : ''
                    }
                </Box>
            )
        } else results = '';

        return (

{quizInfo}

{teamInfo}

{question}

{results}

    )};
}

Quiz.propTypes = {
    teams: PropTypes.array.isRequired,
    question: PropTypes.object,
    status: PropTypes.string.isRequired,
    results: PropTypes.array,
    questionNum: PropTypes.number.isRequired,
    roundNum: PropTypes.number.isRequired
};

export default Quiz;<|endoftext|>


<commit_before>/*jshint esversion: 6 */

(function() {
  'use strict';

  const fs = require('fs');
  const PDFParser = require("pdf2json");
  const AbstractScraper = require('./abstract-scraper');

  class AbstractPdfScraper extends AbstractScraper {

    constructor(pdfFile) {
      super();
      this.pdfParser = new PDFParser();
      this.pdfFile = pdfFile;

      this.pdfParser.on('pdfParser_dataError', this.onPdfParseError.bind(this));
      this.pdfParser.on('pdfParser_dataReady', this.onPdfParseReady.bind(this));
      this.pdfParser.loadPDF(this.pdfFile);
    }

    onPdfParseError(errData) {

    }

    onPdfParseReady(pdfData) {

    }

  }

  module.exports = AbstractPdfScraper;

}).call(this);<commit_msg>Implemented pdf parsing<commit_after>/*jshint esversion: 6 */

(function() {
  'use strict';

  const fs = require('fs');
  const PDFParser = require("pdf2json");
  const AbstractScraper = require('./abstract-scraper');

  class AbstractPdfScraper extends AbstractScraper {

    constructor(pdfFile) {
      super();
      this.pdfParser = new PDFParser();
      this.pdfFile = pdfFile;

      this.pdfParser.on('pdfParser_dataError', this.onPdfParseError.bind(this));
      this.pdfParser.on('pdfParser_dataReady', this.onPdfParseReady.bind(this));
      this.pdfParser.loadPDF(this.pdfFile);
      this._pdfData = null;
      this._pdfDataPromise = null;
    }

    onPdfParseError(errData) {
      if (this._pdfDataPromise !== null) {
        this._pdfDataPromise.reject(errData);
        this._pdfDataPromise = null;
      }
    }

    onPdfParseReady(pdfData) {
      if (this._pdfDataPromise !== null) {
        this._pdfDataPromise.resolve(pdfData);
        this._pdfData = pdfData;
        this._pdfDataPromise = null;
      } else {
        this._pdfData = pdfData;
      }
    }

    get pdfData() {
      return new Promise((resolve, reject) => {
        if (this._pdfData === null) {
          this._pdfDataPromise = new Promise((resolve, reject));
        } else {
          resolve(this._pdfData);
        }
      });
    }

  }

  module.exports = AbstractPdfScraper;

}).call(this);<|endoftext|>


<commit_before>// @TODO Break up clearance code into easier to digest API commands
var jp = jp || {};

$(document).ready(function () {
    var _private = {
        recursiveClearance: function (xStart, yStart, distance) {
            if (jp.map.isEdgeOpen(xStart, yStart, distance)) {
                return _private.recursiveClearance(xStart, yStart, distance + 1);
            }

            // New distance failed, return the previous value
            return distance - 1;
        }
    };

    jp.clearance = {
        map: null, // An array of all existing clearance values
        debug: false, // Output debug display of clearance values

        /**
         * Sets clearance values, reliant on the Map API to have collision data set
         * @param width
         * @param height
         */
        setMap: function (width, height) {
            var x, y, start = Date.now();

            this.map = [];

            for (y = 0; y < height; y++) {
                this.map.push([]);
                for (x = 0; x < width; x++) {
                    // Recursively check clearance until false returns
                    // set clearance equal to number of successful recursive checks
                    this.map[y].push(_private.recursiveClearance(x, y, 1));
                }
            }

            return this;
        },

        getTile: function (x, y) {
            return this.map[y][x];
        }
    };
});<commit_msg>Added a set tile API method for clearance<commit_after>// @TODO Break up clearance code into easier to digest API commands
var jp = jp || {};

$(document).ready(function () {
    var _private = {
        recursiveClearance: function (xStart, yStart, distance) {
            if (jp.map.isEdgeOpen(xStart, yStart, distance)) {
                return _private.recursiveClearance(xStart, yStart, distance + 1);
            }

            // New distance failed, return the previous value
            return distance - 1;
        }
    };

    jp.clearance = {
        map: null, // An array of all existing clearance values
        debug: false, // Output debug display of clearance values

        /**
         * Sets clearance values, reliant on the Map API to have collision data set
         * @param width
         * @param height
         */
        setMap: function (width, height) {
            var x, y, start = Date.now();

            this.map = [];

            for (y = 0; y < height; y++) {
                this.map.push([]);
                for (x = 0; x < width; x++) {
                    // Recursively check clearance until false returns
                    // set clearance equal to number of successful recursive checks
                    this.map[y].push(_private.recursiveClearance(x, y, 1));
                }
            }

            return this;
        },

        setTile: function (x, y, value) {
            this.map[y][x] = value;
            return this;
        },

        getTile: function (x, y) {
            return this.map[y][x];
        }
    };
});<|endoftext|>


<commit_before>/*    Copyright 2016-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const sysManager = require('../net2/SysManager.js');

const HostManager = require('../net2/HostManager.js');
const HostTool = require('../net2/HostTool.js');
const hostTool = new HostTool();

class DnsLoopAvoidanceSensor extends Sensor {
  run() {
    setInterval(() => {
      this.check();
    }, 300000);
    setTimeout(() => {
      this.check();
    }, 60000);
  }

  async check() {
    const hostManager = new HostManager();
    let dnsServers = [];
    const monitoringInterfaces = sysManager.getMonitoringInterfaces();
    for (const i of monitoringInterfaces) {
      const dns = (i.name && sysManager.myDNS(i.name) || []).concat(i.name && sysManager.myResolver(i.name) || []);
      for (let n of dns) {
        if (!dnsServers.includes(n))
          dnsServers.push(n);
      }
    }
    log.info("Current dns servers: ", dnsServers);
    const macEntries = await hostTool.getAllMACEntries();
    for (let i in macEntries) {
      const macEntry = macEntries[i];
      const ipv4Addr = macEntry.ipv4Addr;
      const ipv6Addrs = macEntry.ipv6Addr && JSON.parse(macEntry.ipv6Addr) || [];
      let disableDnsCaching = false;
      if (ipv4Addr && dnsServers.includes(ipv4Addr)) {
        log.info(`Device ${macEntry.mac} has ip address ${ipv4Addr}, which is dns server. Disable dns caching on it...`);
        disableDnsCaching = true;
      }
      ipv6Addrs.forEach((ipv6Addr) => {
        if (dnsServers.includes(ipv6Addr)) {
          log.info(`Device ${macEntry.mac} has ipv6 address ${ipv6Addr}, which is dns server. Disable dns caching on it...`);
          disableDnsCaching = true;
        }
      })

      if (disableDnsCaching) {
        hostManager.getHost(macEntry.mac, (err, host) => {
          if (host != null) {
            host.loadPolicy((err, data) => {
              if (!err) {
                const oldValue = (data && data['dnsmasq']) || {};
                const newValue = Object.assign({}, oldValue, {dnsCaching: false});
                host.setPolicy('dnsmasq', newValue, (err, data) => {
                  if (err) {
                    log.error("Failed to disable dns caching on " + macEntry.mac);
                  }
                })
              } else {
                log.error("Failed to load policy of " + macEntry.mac);
              }
            });
          }
        });
      }
    }
  }
}

module.exports = DnsLoopAvoidanceSensor;<commit_msg>do not turn off dns booster on dns server if doh/family/unbound is enabled on it (#4744)<commit_after>/*    Copyright 2016-2021 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const sysManager = require('../net2/SysManager.js');

const HostManager = require('../net2/HostManager.js');
const HostTool = require('../net2/HostTool.js');
const hostTool = new HostTool();
const _ = require('lodash');

class DnsLoopAvoidanceSensor extends Sensor {
  run() {
    setInterval(() => {
      this.check();
    }, 300000);
    setTimeout(() => {
      this.check();
    }, 60000);
  }

  async check() {
    const hostManager = new HostManager();
    let dnsServers = [];
    const monitoringInterfaces = sysManager.getMonitoringInterfaces();
    for (const i of monitoringInterfaces) {
      const dns = (i.name && sysManager.myDNS(i.name) || []).concat(i.name && sysManager.myResolver(i.name) || []);
      for (let n of dns) {
        if (!dnsServers.includes(n))
          dnsServers.push(n);
      }
    }
    log.info("Current dns servers: ", dnsServers);
    const macEntries = await hostTool.getAllMACEntries();
    for (let i in macEntries) {
      const macEntry = macEntries[i];
      const ipv4Addr = macEntry.ipv4Addr;
      const ipv6Addrs = macEntry.ipv6Addr && JSON.parse(macEntry.ipv6Addr) || [];
      let disableDnsCaching = false;
      if (ipv4Addr && dnsServers.includes(ipv4Addr)) {
        log.info(`Device ${macEntry.mac} has ip address ${ipv4Addr}, which is dns server.`);
        disableDnsCaching = true;
      }
      for (const ipv6Addr of ipv6Addrs) {
        if (dnsServers.includes(ipv6Addr)) {
          log.info(`Device ${macEntry.mac} has ipv6 address ${ipv6Addr}, which is dns server.`);
          disableDnsCaching = true;
          break;
        }
      }

      if (disableDnsCaching) {
        const host = await hostManager.getHostAsync(macEntry.mac).catch((err) => null);
        if (host != null) {
          // double-check if dns upstream-related feature is enabled on this host, e.g., doh, family, unbound. If enabled, no need to turn off dns booster on this host
          const data = await host.loadPolicyAsync().catch((err) => {
            log.error("Failed to load policy of " + macEntry.mac, err.message);
            return null;
          });
          if (data) {
            if (_.isObject(data.doh) && data.doh.state === true) {
              log.info(`Device ${macEntry.mac} is using doh as DNS upstream, no need to turn off dns booster on it`);
              continue;
            }
            if (data.family === true) {
              log.info(`Device ${macEntry.mac} is using family protect as DNS upstream, no need to turn off dns booster on it`);
              continue;
            }
            if (_.isObject(data.unbound) && data.unbound.state === true) {
              log.info(`Device ${macEntry.mac} is using unbound as DNS upstream, no need to turn off dns booster on it`);
              continue;
            }
            log.info(`Going to turn off dns booster on ${macEntry.mac} ...`);
            const oldValue = (data && data['dnsmasq']) || {};
            const newValue = Object.assign({}, oldValue, { dnsCaching: false });
            await host.setPolicyAsync('dnsmasq', newValue).catch((err) => {
              log.error("Failed to disable dns caching on " + macEntry.mac);
            });
          }
        }
      }
    }
  }
}

module.exports = DnsLoopAvoidanceSensor;<|endoftext|>