<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');

function TChannelRequest(channel, options) {
    options = options || {};
    assert(!options.streamed, "streaming request federation not implemented");
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.responseEvent = self.defineEvent('response');

    self.channel = channel;
    self.services = self.channel.services;
    self.logger = self.channel.logger;
    self.random = self.channel.random;
    self.timers = self.channel.timers;

    self.options = options;

    if (!self.options.retryFlags) {
        self.options.retryFlags = {
            never: false,
            onConnectionError: true,
            onTimeout: false
        };
    }

    self.triedRemoteAddrs = {};
    self.outReqs = [];
    self.timeout = self.options.timeout || TChannelRequest.defaultTimeout;
    self.limit = self.options.retryLimit || TChannelRequest.defaultRetryLimit;
    self.start = 0;
    self.end = 0;
    self.elapsed = 0;
    self.resendSanity = 0;
    self.trackPending = self.options.trackPending || false;

    self.serviceName = options.serviceName || '';
    self.headers = self.options.headers || {}; // so that as-foo can punch req.headers.X
    self.options.headers = self.headers; // for passing to peer.request(opts) later

    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.err = null;
    self.res = null;
}

inherits(TChannelRequest, EventEmitter);

TChannelRequest.defaultRetryLimit = 5;
TChannelRequest.defaultTimeout = 5000;

TChannelRequest.prototype.type = 'tchannel.request';

TChannelRequest.prototype.emitError = function emitError(err) {
    var self = this;
    if (!self.end) self.end = self.timers.now();
    self.err = err;
    self.services.onRequestError(self);
    self.errorEvent.emit(self, err);
};

TChannelRequest.prototype.emitResponse = function emitResponse(res) {
    var self = this;
    if (!self.end) self.end = self.timers.now();
    self.res = res;
    self.services.onRequestResponse(self);
    self.responseEvent.emit(self, res);
};

TChannelRequest.prototype.hookupStreamCallback = function hookupCallback(callback) {
    throw new Error('not implemented');
};

TChannelRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    if (callback.canStream) {
        return self.hookupStreamCallback(callback);
    }
    var called = false;

    self.errorEvent.on(onError);
    self.responseEvent.on(onResponse);

    function onError(err) {
        if (called) return;
        called = true;

        if (err.isErrorFrame) {
            self.channel.outboundCallsSystemErrorsStat.increment(1, {
                'target-service': self.serviceName,
                'service': self.headers.cn,
                // TODO should always be buffer
                'target-endpoint': String(self.arg1),
                'type': err.codeName
            });
        } else {
            self.channel.outboundCallsOperationalErrorsStat.increment(1, {
                'target-service': self.serviceName,
                'service': self.headers.cn,
                // TODO should always be buffer
                'target-endpoint': String(self.arg1),
                'type': err.type || 'unknown'
            });
        }

        emitLatency();

        callback(err, null, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        res.withArg23(function gotArg23(err, arg2, arg3) {
            if (res.ok) {
                self.channel.outboundCallsSuccessStat.increment(1, {
                    'target-service': self.serviceName,
                    'service': self.headers.cn,
                    // TODO should always be buffer
                    'target-endpoint': String(self.arg1)
                });
            } else {
                self.channel.outboundCallsAppErrorsStat.increment(1, {
                    'target-service': self.serviceName,
                    'service': self.headers.cn,
                    // TODO should always be buffer
                    'target-endpoint': String(self.arg1),
                    // TODO define transport header
                    // for application error type
                    'type': 'unknown'
                });
            }

            emitLatency();

            callback(err, res, arg2, arg3);
        });
    }

    function emitLatency() {
        var latency = self.end - self.start;
        self.channel.outboundCallsLatencyStat.add(latency, {
            'target-service': self.serviceName,
            'service': self.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1)
        });
    }

    return self;
};

TChannelRequest.prototype.choosePeer = function choosePeer() {
    var self = this;
    return self.channel.peers.choosePeer(self, self.options);
};

TChannelRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;
    self.arg1 = arg1;
    self.arg2 = arg2;
    self.arg3 = arg3;
    if (callback) {
        self.hookupCallback(callback);
    }
    self.start = self.timers.now();
    self.resendSanity = self.limit + 1;

    self.services.onRequest(self);
    self.resend();
};

TChannelRequest.prototype.resend = function resend() {
    var self = this;

    if (self.channel.destroyed) return;

    if (self.trackPending && self.checkPending()) return;

    if (self.checkTimeout()) return;

    var peer = self.choosePeer();
    if (!peer) {
        if (self.outReqs.length) {
            var lastReq = self.outReqs[self.outReqs.length - 1];
            if (lastReq.err) {
                self.emitError(lastReq.err);
            } else {
                self.emitResponse(lastReq.res);
            }
        } else {
            self.emitError(errors.NoPeerAvailable());
        }
        return;
    }

    var perAttemptStart = self.timers.now();

    var opts = {};
    var keys = Object.keys(self.options);
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        opts[key] = self.options[key];
    }
    opts.timeout = self.timeout - self.elapsed;

    var conn = peer.connect();
    if (!peer.isConnected() && conn.handler) {
        conn.on('identified', onIdentified);
        var timer = self.timers.setTimeout(onIdentifyTimeout, opts.timeout);
        return;
    } else {
        onIdentified();
    }

    function onIdentifyTimeout() {
        self.checkTimeout();
    }

    function onIdentified() {
        if (timer) {
            self.timers.clearTimeout(timer);
        }
        self.onIdentified(peer, opts, perAttemptStart);
    }
};

TChannelRequest.prototype.onIdentified = function onIdentified(peer, opts, perAttemptStart) {
    var self = this;
    var outReq = peer.request(opts);
    self.outReqs.push(outReq);

    if (self.outReqs.length === 1) {
        self.channel.outboundCallsSentStat.increment(1, {
            'target-service': outReq.serviceName,
            'service': outReq.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1)
        });
    } else {
        self.channel.outboundCallsRetriesStat.increment(1, {
            'target-service': outReq.serviceName,
            'service': outReq.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1),
            'retry-count': self.outReqs.length - 1
        });
    }

    self.triedRemoteAddrs[outReq.remoteAddr] = (self.triedRemoteAddrs[outReq.remoteAddr] || 0) + 1;
    outReq.responseEvent.on(onResponse);
    outReq.errorEvent.on(onError);
    outReq.send(self.arg1, self.arg2, self.arg3);

    function onError(err) {
        emitPerAttemptLatency();

        self.onSubreqError(err);
    }

    function onResponse(res) {
        emitPerAttemptLatency();

        self.onSubreqResponse(res);
    }

    function emitPerAttemptLatency() {
        var latency = self.timers.now() - perAttemptStart;

        self.channel.outboundCallsPerAttemptLatencyStat.add(latency, {
            'target-service': self.serviceName,
            'service': self.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1),
            'peer': peer.hostPort,
            'retry-count': self.outReqs.length - 1
        });
    }
};

TChannelRequest.prototype.onSubreqError = function onSubreqError(err) {
    var self = this;
    if (self.checkTimeout(err)) return;
    if (self.shouldRetryError(err)) {
        self.deferResend();
    } else {
        self.emitError(err);
    }
};

TChannelRequest.prototype.onSubreqResponse = function onSubreqResponse(res) {
    var self = this;
    if (self.checkTimeout(null, res)) return;
    if (res.ok) {
        self.emitResponse(res);
    } else if (self.options.shouldApplicationRetry) {
        self.maybeAppRetry(res);
    } else {
        self.emitResponse(res);
    }
};

TChannelRequest.prototype.deferResend = function deferResend() {
    var self = this;
    if (--self.resendSanity <= 0) {
        self.emitError(new Error('TChannelRequest out of resend sanity'));
    } else {
        process.nextTick(doResend);
    }
    function doResend() {
        self.resend();
    }
};

TChannelRequest.prototype.checkPending = function checkPending() {
    var self = this;
    var err = self.services.errorIfExceedsMaxPending(self);
    if (err) {
        self.emitError(err);
        return true;
    }
    return false;
};

TChannelRequest.prototype.checkTimeout = function checkTimeout(err, res) {
    var self = this;
    var now = self.timers.now();
    self.elapsed = now - self.start;
    if (self.elapsed < self.timeout) return false;
    if (err) {
        if (!self.err) {
            self.emitError(err);
        }
    } else if (res) {
        if (!self.err && !self.res) {
            self.emitResponse(res);
        }
    } else if (!self.err) {
        self.emitError(errors.TimeoutError({
            start: self.start,
            elapsed: self.elapsed,
            timeout: self.timeout
        }));
    }
    return true;
};

TChannelRequest.prototype.shouldRetryError = function shouldRetryError(err) {
    var self = this;

    if (self.outReqs.length >= self.limit) {
        return false;
    }

    if (self.options.retryFlags.never) {
        return false;
    }

    if (err) {
        switch (err.type) {
            case 'tchannel.bad-request':
            case 'tchannel.canceled':
                return false;

            case 'tchannel.busy':
            case 'tchannel.declined':
                return true;

            case 'tchannel.timeout':
                return !!self.options.retryFlags.onTimeout;

            case 'tchannel.socket':
            case 'tchannel.socket-closed':
            case 'tchannel.network':
            case 'tchannel.protocol':
            case 'tchannel.unexpected':
                return !!self.options.retryFlags.onConnectionError;

            default:
                self.logger.error('unknown error type in request retry', {
                    error: err
                });
                return true;
        }
    }

    return false;
};

TChannelRequest.prototype.maybeAppRetry = function maybeAppRetry(res) {
    var self = this;
    self.options.shouldApplicationRetry(self, res, retry, done);

    function retry() {
        if (self.checkTimeout(null, res)) return;
        self.deferResend();
    }

    function done(err) {
        if (err) {
            self.emitError(err);
        } else {
            self.emitResponse(res);
        }
    }
};

module.exports = TChannelRequest;
<commit_msg>move opts to onIdentified function<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');

function TChannelRequest(channel, options) {
    options = options || {};
    assert(!options.streamed, "streaming request federation not implemented");
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.responseEvent = self.defineEvent('response');

    self.channel = channel;
    self.services = self.channel.services;
    self.logger = self.channel.logger;
    self.random = self.channel.random;
    self.timers = self.channel.timers;

    self.options = options;

    if (!self.options.retryFlags) {
        self.options.retryFlags = {
            never: false,
            onConnectionError: true,
            onTimeout: false
        };
    }

    self.triedRemoteAddrs = {};
    self.outReqs = [];
    self.timeout = self.options.timeout || TChannelRequest.defaultTimeout;
    self.limit = self.options.retryLimit || TChannelRequest.defaultRetryLimit;
    self.start = 0;
    self.end = 0;
    self.elapsed = 0;
    self.resendSanity = 0;
    self.trackPending = self.options.trackPending || false;

    self.serviceName = options.serviceName || '';
    self.headers = self.options.headers || {}; // so that as-foo can punch req.headers.X
    self.options.headers = self.headers; // for passing to peer.request(opts) later

    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.err = null;
    self.res = null;
}

inherits(TChannelRequest, EventEmitter);

TChannelRequest.defaultRetryLimit = 5;
TChannelRequest.defaultTimeout = 5000;

TChannelRequest.prototype.type = 'tchannel.request';

TChannelRequest.prototype.emitError = function emitError(err) {
    var self = this;
    if (!self.end) self.end = self.timers.now();
    self.err = err;
    self.services.onRequestError(self);
    self.errorEvent.emit(self, err);
};

TChannelRequest.prototype.emitResponse = function emitResponse(res) {
    var self = this;
    if (!self.end) self.end = self.timers.now();
    self.res = res;
    self.services.onRequestResponse(self);
    self.responseEvent.emit(self, res);
};

TChannelRequest.prototype.hookupStreamCallback = function hookupCallback(callback) {
    throw new Error('not implemented');
};

TChannelRequest.prototype.hookupCallback = function hookupCallback(callback) {
    var self = this;
    if (callback.canStream) {
        return self.hookupStreamCallback(callback);
    }
    var called = false;

    self.errorEvent.on(onError);
    self.responseEvent.on(onResponse);

    function onError(err) {
        if (called) return;
        called = true;

        if (err.isErrorFrame) {
            self.channel.outboundCallsSystemErrorsStat.increment(1, {
                'target-service': self.serviceName,
                'service': self.headers.cn,
                // TODO should always be buffer
                'target-endpoint': String(self.arg1),
                'type': err.codeName
            });
        } else {
            self.channel.outboundCallsOperationalErrorsStat.increment(1, {
                'target-service': self.serviceName,
                'service': self.headers.cn,
                // TODO should always be buffer
                'target-endpoint': String(self.arg1),
                'type': err.type || 'unknown'
            });
        }

        emitLatency();

        callback(err, null, null, null);
    }

    function onResponse(res) {
        if (called) return;
        called = true;
        res.withArg23(function gotArg23(err, arg2, arg3) {
            if (res.ok) {
                self.channel.outboundCallsSuccessStat.increment(1, {
                    'target-service': self.serviceName,
                    'service': self.headers.cn,
                    // TODO should always be buffer
                    'target-endpoint': String(self.arg1)
                });
            } else {
                self.channel.outboundCallsAppErrorsStat.increment(1, {
                    'target-service': self.serviceName,
                    'service': self.headers.cn,
                    // TODO should always be buffer
                    'target-endpoint': String(self.arg1),
                    // TODO define transport header
                    // for application error type
                    'type': 'unknown'
                });
            }

            emitLatency();

            callback(err, res, arg2, arg3);
        });
    }

    function emitLatency() {
        var latency = self.end - self.start;
        self.channel.outboundCallsLatencyStat.add(latency, {
            'target-service': self.serviceName,
            'service': self.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1)
        });
    }

    return self;
};

TChannelRequest.prototype.choosePeer = function choosePeer() {
    var self = this;
    return self.channel.peers.choosePeer(self, self.options);
};

TChannelRequest.prototype.send = function send(arg1, arg2, arg3, callback) {
    var self = this;
    self.arg1 = arg1;
    self.arg2 = arg2;
    self.arg3 = arg3;
    if (callback) {
        self.hookupCallback(callback);
    }
    self.start = self.timers.now();
    self.resendSanity = self.limit + 1;

    self.services.onRequest(self);
    self.resend();
};

TChannelRequest.prototype.resend = function resend() {
    var self = this;

    if (self.channel.destroyed) return;

    if (self.trackPending && self.checkPending()) return;

    if (self.checkTimeout()) return;

    var peer = self.choosePeer();
    if (!peer) {
        if (self.outReqs.length) {
            var lastReq = self.outReqs[self.outReqs.length - 1];
            if (lastReq.err) {
                self.emitError(lastReq.err);
            } else {
                self.emitResponse(lastReq.res);
            }
        } else {
            self.emitError(errors.NoPeerAvailable());
        }
        return;
    }

    var perAttemptStart = self.timers.now();

    var conn = peer.connect();
    if (!peer.isConnected() && conn.handler) {
        conn.on('identified', onIdentified);
        var timer = self.timers.setTimeout(onIdentifyTimeout, self.timeout - self.elapsed);
        return;
    } else {
        onIdentified();
    }

    function onIdentifyTimeout() {
        self.checkTimeout();
    }

    function onIdentified() {
        if (timer) {
            self.timers.clearTimeout(timer);
        }
        self.onIdentified(peer, perAttemptStart);
    }
};

TChannelRequest.prototype.onIdentified = function onIdentified(peer, perAttemptStart) {
    var self = this;
    var opts = {};
    var keys = Object.keys(self.options);
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        opts[key] = self.options[key];
    }
    opts.timeout = self.timeout - self.elapsed;
    var outReq = peer.request(opts);
    self.outReqs.push(outReq);

    if (self.outReqs.length === 1) {
        self.channel.outboundCallsSentStat.increment(1, {
            'target-service': outReq.serviceName,
            'service': outReq.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1)
        });
    } else {
        self.channel.outboundCallsRetriesStat.increment(1, {
            'target-service': outReq.serviceName,
            'service': outReq.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1),
            'retry-count': self.outReqs.length - 1
        });
    }

    self.triedRemoteAddrs[outReq.remoteAddr] = (self.triedRemoteAddrs[outReq.remoteAddr] || 0) + 1;
    outReq.responseEvent.on(onResponse);
    outReq.errorEvent.on(onError);
    outReq.send(self.arg1, self.arg2, self.arg3);

    function onError(err) {
        emitPerAttemptLatency();

        self.onSubreqError(err);
    }

    function onResponse(res) {
        emitPerAttemptLatency();

        self.onSubreqResponse(res);
    }

    function emitPerAttemptLatency() {
        var latency = self.timers.now() - perAttemptStart;

        self.channel.outboundCallsPerAttemptLatencyStat.add(latency, {
            'target-service': self.serviceName,
            'service': self.headers.cn,
            // TODO should always be buffer
            'target-endpoint': String(self.arg1),
            'peer': peer.hostPort,
            'retry-count': self.outReqs.length - 1
        });
    }
};

TChannelRequest.prototype.onSubreqError = function onSubreqError(err) {
    var self = this;
    if (self.checkTimeout(err)) return;
    if (self.shouldRetryError(err)) {
        self.deferResend();
    } else {
        self.emitError(err);
    }
};

TChannelRequest.prototype.onSubreqResponse = function onSubreqResponse(res) {
    var self = this;
    if (self.checkTimeout(null, res)) return;
    if (res.ok) {
        self.emitResponse(res);
    } else if (self.options.shouldApplicationRetry) {
        self.maybeAppRetry(res);
    } else {
        self.emitResponse(res);
    }
};

TChannelRequest.prototype.deferResend = function deferResend() {
    var self = this;
    if (--self.resendSanity <= 0) {
        self.emitError(new Error('TChannelRequest out of resend sanity'));
    } else {
        process.nextTick(doResend);
    }
    function doResend() {
        self.resend();
    }
};

TChannelRequest.prototype.checkPending = function checkPending() {
    var self = this;
    var err = self.services.errorIfExceedsMaxPending(self);
    if (err) {
        self.emitError(err);
        return true;
    }
    return false;
};

TChannelRequest.prototype.checkTimeout = function checkTimeout(err, res) {
    var self = this;
    var now = self.timers.now();
    self.elapsed = now - self.start;
    if (self.elapsed < self.timeout) return false;
    if (err) {
        if (!self.err) {
            self.emitError(err);
        }
    } else if (res) {
        if (!self.err && !self.res) {
            self.emitResponse(res);
        }
    } else if (!self.err) {
        self.emitError(errors.TimeoutError({
            start: self.start,
            elapsed: self.elapsed,
            timeout: self.timeout
        }));
    }
    return true;
};

TChannelRequest.prototype.shouldRetryError = function shouldRetryError(err) {
    var self = this;

    if (self.outReqs.length >= self.limit) {
        return false;
    }

    if (self.options.retryFlags.never) {
        return false;
    }

    if (err) {
        switch (err.type) {
            case 'tchannel.bad-request':
            case 'tchannel.canceled':
                return false;

            case 'tchannel.busy':
            case 'tchannel.declined':
                return true;

            case 'tchannel.timeout':
                return !!self.options.retryFlags.onTimeout;

            case 'tchannel.socket':
            case 'tchannel.socket-closed':
            case 'tchannel.network':
            case 'tchannel.protocol':
            case 'tchannel.unexpected':
                return !!self.options.retryFlags.onConnectionError;

            default:
                self.logger.error('unknown error type in request retry', {
                    error: err
                });
                return true;
        }
    }

    return false;
};

TChannelRequest.prototype.maybeAppRetry = function maybeAppRetry(res) {
    var self = this;
    self.options.shouldApplicationRetry(self, res, retry, done);

    function retry() {
        if (self.checkTimeout(null, res)) return;
        self.deferResend();
    }

    function done(err) {
        if (err) {
            self.emitError(err);
        } else {
            self.emitResponse(res);
        }
    }
};

module.exports = TChannelRequest;
<|endoftext|>


<commit_before>var devices = require('./database').collection('devices');

module.exports = function(socket, callback) {

  var newTimestamp = new Date().getTime();
  console.log("update socket: " + JSON.stringify(socket));
  devices.update({
    uuid: {"$regex":socket.uuid,"$options":"i"}, token: socket.token
  }, {
    $set: {socketId: socket.socketid, online: true, timestamp: newTimestamp}
  }, function(err, saved) {
    console.log('Error: ' + err);
    console.log('Saved: ' + JSON.stringify(saved));

    // if(err || saved === 0) {
    if(err || saved === 0) {
      console.log('Device not found or token not valid for: ' + socket.uuid);
      console.log('Error: ' + err);

      if(socket.uuid){
        callback({uuid: socket.uuid, status: 401});
      } else {
        // auto-register device if UUID not provided on authentication
        require('./register')({"autoRegister":true, socketId: socket.socketid, online: true, timestamp: newTimestamp}, function(results){
          console.log('Device auto-registered: ' + results.uuid)
          console.log(results);
          callback({uuid: results.uuid, token: results.token, status: 201});
        });
      }

    } else {
      console.log('SocketId and presence updated for device: ' + socket.uuid);
      callback({uuid: socket.uuid, status: 201});
    }

  });

};<commit_msg>tweaked auto register<commit_after>var devices = require('./database').collection('devices');

module.exports = function(socket, callback) {

  var newTimestamp = new Date().getTime();
  console.log("update socket: " + JSON.stringify(socket));
  if(socket.uuid && socket.token){

    devices.update({
      uuid: {"$regex":socket.uuid,"$options":"i"}, token: socket.token
    }, {
      $set: {socketId: socket.socketid, online: true, timestamp: newTimestamp}
    }, function(err, saved) {
      console.log('Error: ' + err);
      console.log('Saved: ' + JSON.stringify(saved));

      // if(err || saved === 0) {
      if(err) {
        console.log('Device not found or token not valid for: ' + socket.uuid);
        console.log('Error: ' + err);

      } else {
        console.log('SocketId and presence updated for device: ' + socket.uuid);
        callback({uuid: socket.uuid, status: 201});
      }

    });

  } else {

    if(socket.uuid){
      callback({uuid: socket.uuid, status: 401});
    } else {
      // auto-register device if UUID not provided on authentication
      require('./register')({"autoRegister":true, socketId: socket.socketid, online: true, timestamp: newTimestamp}, function(results){
        console.log('Device auto-registered: ' + results.uuid)
        console.log(results);
        callback({uuid: results.uuid, token: results.token, status: 201});
      });
    }

  }

};<|endoftext|>


<commit_before>// ==UserScript==
// @name        Destroy Spammer
// @namespace   https://github.com/Glorfindel83/
// @description Adds a 'Destroy spammer' link for moderator on user profiles with only deleted posts.
// @author      Glorfindel
// @version     0.1
// @match       *://*.stackexchange.com/users/*
// @match       *://*.stackoverflow.com/users/*
// @match       *://*.superuser.com/users/*
// @match       *://*.serverfault.com/users/*
// @match       *://*.askubuntu.com/users/*
// @match       *://*.stackapps.com/users/*
// @match       *://*.mathoverflow.net/users/*
// @grant       none
// ==/UserScript==
(function () {
  'use strict';
  // Determine user ID
  var userIDRegex = /\/users\/(\d+)\//g;
  var userID = userIDRegex.exec(document.location) [1];
  var moderatorLinkElement = $('a#user-moderator-link-' + userID);
  if (moderatorLinkElement.length == 0) // Current user is not a moderator - no action possible
    return;

  // Check for (deleted) questions and answers
  var questionsPanel = $('#user-panel-questions');
  var undeletedQuestions = questionsPanel.find('td.question-hyperlink').not('.deleted-answer').length; // yes, deleted-answer. Don't ask why.
  var deletedQuestions = questionsPanel.find('td.question-hyperlink.deleted-answer').length;
  if (undeletedQuestions > 0) // User has content - use the dialog instead
    return;
  var answersPanel = $('#user-panel-answers');
  var undeletedAnswers = answersPanel.find('td.answer-hyperlink').not('.deleted-answer').length;
  var deletedAnswers = answersPanel.find('td.answer-hyperlink.deleted-answer').length;
  if (undeletedAnswers > 0) // User has content - use the dialog instead
    return;
  if (deletedQuestions + deletedAnswers == 0) // User has no deleted content - use the dialog instead
    return;
  if (deletedQuestions + deletedAnswers > 4) // User has too much deleted content - use the dialog instead
    return;

  // Create Destroy link
  var destroyLink = document.createElement('a');
  destroyLink.appendChild(document.createTextNode('Destroy spammer'));
  destroyLink.onclick = function () {
    // 'Open' moderator menu
    $.get({
      url: 'https://apple.stackexchange.com/admin/users/' + userID + '/moderator-menu?_=',
      cache: false,
      success: function (html) {
        // Find key
        var fkey = ($($.parseHTML(html)).find('input[name=fkey]').attr('value'));

        // Ask for confirmation
        if (window.confirm('Are you sure?')) {
          $.post({
            url: 'https://apple.stackexchange.com/admin/users/' + userID + '/destroy',
            data: 'annotation=&deleteReasonDetails=&mod-actions=destroy&destroyReason=This+user+was+created+to+post+spam+or+nonsense+and+has+no+other+positive+participation&destroyReasonDetails=&fkey=' + fkey,
            success: function (data) {
              // Reload page
              window.location.reload();
            },
            error: function (jqXHR, textStatus, errorThrown) {
              console.log('Error: ' + textStatus + ' ' + errorThrown);
            }
          });
        }
      }
    });
  };

  // Add to document
  moderatorLinkElement.after(destroyLink);
}) ();
<commit_msg>Fetch `fkey` from localStorage<commit_after>// ==UserScript==
// @name        Destroy Spammer
// @namespace   https://github.com/Glorfindel83/
// @description Adds a 'Destroy spammer' link for moderator on user profiles with only deleted posts.
// @author      Glorfindel
// @version     0.2
// @match       *://*.stackexchange.com/users/*
// @match       *://*.stackoverflow.com/users/*
// @match       *://*.superuser.com/users/*
// @match       *://*.serverfault.com/users/*
// @match       *://*.askubuntu.com/users/*
// @match       *://*.stackapps.com/users/*
// @match       *://*.mathoverflow.net/users/*
// @grant       none
// ==/UserScript==
(function () {
  'use strict';
  // Determine user ID
  var userIDRegex = /\/users\/(\d+)\//g;
  var userID = userIDRegex.exec(document.location) [1];
  var moderatorLinkElement = $('a#user-moderator-link-' + userID);
  if (moderatorLinkElement.length == 0) // Current user is not a moderator - no action possible
    return;

  // Check for (deleted) questions and answers
  var questionsPanel = $('#user-panel-questions');
  var undeletedQuestions = questionsPanel.find('td.question-hyperlink').not('.deleted-answer').length; // yes, deleted-answer. Don't ask why.
  var deletedQuestions = questionsPanel.find('td.question-hyperlink.deleted-answer').length;
  if (undeletedQuestions > 0) // User has content - use the dialog instead
    return;
  var answersPanel = $('#user-panel-answers');
  var undeletedAnswers = answersPanel.find('td.answer-hyperlink').not('.deleted-answer').length;
  var deletedAnswers = answersPanel.find('td.answer-hyperlink.deleted-answer').length;
  if (undeletedAnswers > 0) // User has content - use the dialog instead
    return;
  if (deletedQuestions + deletedAnswers == 0) // User has no deleted content - use the dialog instead
    return;
  if (deletedQuestions + deletedAnswers > 4) // User has too much deleted content - use the dialog instead
    return;

  // Create Destroy link
  var destroyLink = document.createElement('a');
  var attribute = document.createAttribute("href");
  attribute.value = "#";
  destroyLink.setAttributeNode(attribute);
  destroyLink.appendChild(document.createTextNode('Destroy spammer'));
  destroyLink.onclick = function () {
    // Ask for confirmation
    if (window.confirm('Are you sure?')) {
      $.post({
        url: 'https://apple.stackexchange.com/admin/users/' + userID + '/destroy',
        data: 'annotation=&deleteReasonDetails=&mod-actions=destroy&destroyReason=This+user+was+created+to+post+spam+or+nonsense+and+has+no+other+positive+participation&destroyReasonDetails=&fkey=' + window.localStorage["se:fkey"].split(",")[0],
        success: function (data) {
          // Reload page
          window.location.reload();
        },
        error: function (jqXHR, textStatus, errorThrown) {
          console.log('Error: ' + textStatus + ' ' + errorThrown);
        }
      });
    }
  };

  // Add to document
  moderatorLinkElement.after(destroyLink);
}) ();
<|endoftext|>


<commit_before>'use strict';

var cacheTimes = require('../../web/config/cache-times');
var _ = require('lodash');
_.mixin(require("lodash-deep"));

module.exports = function(options){
  var seneca = this;
  var plugin = 'users-proxy';
  var version = '1.0';

  options = seneca.util.deepextend({
    prefix: '/api/'
  }, options);

  seneca.add({role: plugin, cmd: 'list'}, proxy);
  seneca.add({role: plugin, cmd: 'register'}, proxy);
  seneca.add({role: plugin, cmd: 'promote'}, proxy);
  seneca.add({role: plugin, cmd: 'get_users_by_emails'}, proxy);
  seneca.add({role: plugin, cmd: 'update'}, proxy);
  seneca.add({role: plugin, cmd: 'load'}, proxy);
  seneca.add({role: plugin, cmd: 'get_init_user_types'}, proxy);
  seneca.add({role: plugin, cmd: 'is_champion'}, proxy);
  seneca.add({role: plugin, cmd: 'reset_password'}, proxy);
  seneca.add({role: plugin, cmd: 'execute_reset'}, proxy);
  seneca.add({role: plugin, cmd: 'load_champions_for_user'}, proxy);
  seneca.add({role: plugin, cmd: 'load_dojo_admins_for_user'}, proxy);
  seneca.add({role: plugin, cmd: 'kpi_number_of_youths_registered'}, proxyNeedCDFAdmin);
  seneca.add({role: plugin, cmd: 'kpi_number_of_champions_and_mentors_registered'}, proxyNeedCDFAdmin);

  function proxy(args, done) {
    var user;
    var zenHostname = args.req$.headers.host || '127.0.0.1:8000';
    var locality = (args.req$ && args.req$.cookies.NG_TRANSLATE_LANG_KEY && args.req$.cookies.NG_TRANSLATE_LANG_KEY.replace(/\"/g, '')) || args.req$ && args.req$.headers['accept-language'];
    locality = formatLocaleCode(locality);
    if(args.req$.seneca.user) user = args.req$.seneca.user;
    seneca.act(seneca.util.argprops(
      {user:user, zenHostname: zenHostname, locality: locality, fatal$: false},
      args,
      {role: 'cd-users'}
    ), done);
  }

  function proxyNeedCDFAdmin(args, done) {
    if(!_.deepHas(args.req$, 'user.user') || !_.contains(args.req$.seneca.user.roles, 'cdf-admin')) return done(null, {ok: false, why: 'You must be a cdf admin to access this data'});
    return proxy(args, done);
  }

  function formatLocaleCode(code) {
    return code.slice(0, 3) + code.charAt(3).toUpperCase() + code.charAt(4).toUpperCase();
  }

  seneca.act({ role: 'web', use: {
    prefix: options.prefix+version+'/users',
    pin: {role: plugin,  cmd: '*'},
    map: {
      'list': {POST: true, alias: 'list'},
      'register': {POST: true, alias: 'register'},
      'promote': {PUT: true, alias: 'promote/:id'},
      'get_users_by_emails': {POST: true, alias: 'emails'},
      'update': {PUT: true, alias: 'update/:id'},
      'load': {GET: true, alias: 'load/:id'},
      'get_init_user_types': {GET: true, alias: 'init_user_types', expiresIn: cacheTimes.long},
      'is_champion': {POST: true, alias:'isChampion'},
      'reset_password': {POST: true, alias: 'reset_password'},
      'execute_reset': {POST: true, alias: 'execute_reset'},
      'load_champions_for_user': {GET: true, alias: 'champions_for_user/:userId'},
      'load_dojo_admins_for_user': {GET: true, alias: 'dojo_admins_for_user/:userId'},
      'kpi_number_of_youths_registered': {GET: true, alias: 'kpi/number_of_youths_registered'},
      'kpi_number_of_champions_and_mentors_registered': {GET: true, alias: 'kpi/number_of_champions_and_mentors_registered'}
    }
  }});

  return {
    name: plugin
  }

};
<commit_msg>add number of youth females registered kpi<commit_after>'use strict';

var cacheTimes = require('../../web/config/cache-times');
var _ = require('lodash');
_.mixin(require("lodash-deep"));

module.exports = function(options){
  var seneca = this;
  var plugin = 'users-proxy';
  var version = '1.0';

  options = seneca.util.deepextend({
    prefix: '/api/'
  }, options);

  seneca.add({role: plugin, cmd: 'list'}, proxy);
  seneca.add({role: plugin, cmd: 'register'}, proxy);
  seneca.add({role: plugin, cmd: 'promote'}, proxy);
  seneca.add({role: plugin, cmd: 'get_users_by_emails'}, proxy);
  seneca.add({role: plugin, cmd: 'update'}, proxy);
  seneca.add({role: plugin, cmd: 'load'}, proxy);
  seneca.add({role: plugin, cmd: 'get_init_user_types'}, proxy);
  seneca.add({role: plugin, cmd: 'is_champion'}, proxy);
  seneca.add({role: plugin, cmd: 'reset_password'}, proxy);
  seneca.add({role: plugin, cmd: 'execute_reset'}, proxy);
  seneca.add({role: plugin, cmd: 'load_champions_for_user'}, proxy);
  seneca.add({role: plugin, cmd: 'load_dojo_admins_for_user'}, proxy);
  seneca.add({role: plugin, cmd: 'kpi_number_of_youths_registered'}, proxyNeedCDFAdmin);
  seneca.add({role: plugin, cmd: 'kpi_number_of_champions_and_mentors_registered'}, proxyNeedCDFAdmin);
  seneca.add({role: plugin, cmd: 'kpi_number_of_youth_females_registered'}, proxyNeedCDFAdmin);

  function proxy(args, done) {
    var user;
    var zenHostname = args.req$.headers.host || '127.0.0.1:8000';
    var locality = (args.req$ && args.req$.cookies.NG_TRANSLATE_LANG_KEY && args.req$.cookies.NG_TRANSLATE_LANG_KEY.replace(/\"/g, '')) || args.req$ && args.req$.headers['accept-language'];
    locality = formatLocaleCode(locality);
    if(args.req$.seneca.user) user = args.req$.seneca.user;
    seneca.act(seneca.util.argprops(
      {user:user, zenHostname: zenHostname, locality: locality, fatal$: false},
      args,
      {role: 'cd-users'}
    ), done);
  }

  function proxyNeedCDFAdmin(args, done) {
    if(!_.deepHas(args.req$, 'user.user') || !_.contains(args.req$.seneca.user.roles, 'cdf-admin')) return done(null, {ok: false, why: 'You must be a cdf admin to access this data'});
    return proxy(args, done);
  }

  function formatLocaleCode(code) {
    return code.slice(0, 3) + code.charAt(3).toUpperCase() + code.charAt(4).toUpperCase();
  }

  seneca.act({ role: 'web', use: {
    prefix: options.prefix+version+'/users',
    pin: {role: plugin,  cmd: '*'},
    map: {
      'list': {POST: true, alias: 'list'},
      'register': {POST: true, alias: 'register'},
      'promote': {PUT: true, alias: 'promote/:id'},
      'get_users_by_emails': {POST: true, alias: 'emails'},
      'update': {PUT: true, alias: 'update/:id'},
      'load': {GET: true, alias: 'load/:id'},
      'get_init_user_types': {GET: true, alias: 'init_user_types', expiresIn: cacheTimes.long},
      'is_champion': {POST: true, alias:'isChampion'},
      'reset_password': {POST: true, alias: 'reset_password'},
      'execute_reset': {POST: true, alias: 'execute_reset'},
      'load_champions_for_user': {GET: true, alias: 'champions_for_user/:userId'},
      'load_dojo_admins_for_user': {GET: true, alias: 'dojo_admins_for_user/:userId'},
      'kpi_number_of_youths_registered': {GET: true, alias: 'kpi/number_of_youths_registered'},
      'kpi_number_of_champions_and_mentors_registered': {GET: true, alias: 'kpi/number_of_champions_and_mentors_registered'},
      'kpi_number_of_youth_females_registered': {GET: true, alias: 'kpi/number_of_youth_females_registered'}
    }
  }});

  return {
    name: plugin
  }

};
<|endoftext|>


<commit_before>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Tobias Koppers @sokra
 */

"use strict";

const { ConcatSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const Template = require("./Template");

const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json");

/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */
/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */

const wrapComment = str => {
	if (!str.includes("\n")) {
		return Template.toComment(str);
	}
	return `/*!\n * ${str
		.replace(/\*\//g, "* /")
		.split("\n")
		.join("\n * ")}\n */`;
};

class BannerPlugin {
	/**
	 * @param {BannerPluginArgument} options options object
	 */
	constructor(options) {
		if (arguments.length > 1) {
			throw new Error(
				"BannerPlugin only takes one argument (pass an options object)"
			);
		}

		validateOptions(schema, options, "Banner Plugin");

		if (typeof options === "string" || typeof options === "function") {
			options = {
				banner: options
			};
		}

		/** @type {BannerPluginOptions} */
		this.options = options;

		const bannerOption = options.banner;
		if (typeof bannerOption === "function") {
			const getBanner = bannerOption;
			this.banner = this.options.raw
				? getBanner
				: data => wrapComment(getBanner(data));
		} else {
			const banner = this.options.raw
				? bannerOption
				: wrapComment(bannerOption);
			this.banner = () => banner;
		}
	}

	apply(compiler) {
		const options = this.options;
		const banner = this.banner;
		const matchObject = ModuleFilenameHelpers.matchObject.bind(
			undefined,
			options
		);

		compiler.hooks.compilation.tap("BannerPlugin", compilation => {
			compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
				for (const chunk of chunks) {
					if (options.entryOnly && !chunk.canBeInitial()) {
						continue;
					}

					for (const file of chunk.files) {
						if (!matchObject(file)) {
							continue;
						}

						let basename;
						let query = "";
						let filename = file;
						const hash = compilation.hash;
						const querySplit = filename.indexOf("?");

						if (querySplit >= 0) {
							query = filename.substr(querySplit);
							filename = filename.substr(0, querySplit);
						}

						const lastSlashIndex = filename.lastIndexOf("/");

						if (lastSlashIndex === -1) {
							basename = filename;
						} else {
							basename = filename.substr(lastSlashIndex + 1);
						}

						const data = {
							hash,
							chunk,
							filename,
							basename,
							query
						};

						const comment = compilation.getPath(banner(data), data);

						compilation.assets[file] = new ConcatSource(
							comment,
							"\n",
							compilation.assets[file]
						);
					}
				}
			});
		});
	}
}

module.exports = BannerPlugin;
<commit_msg>refactor<commit_after>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Tobias Koppers @sokra
 */

"use strict";

const { ConcatSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const Template = require("./Template");

const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json");

/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */
/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */

const wrapComment = str => {
	if (!str.includes("\n")) {
		return Template.toComment(str);
	}
	return `/*!\n * ${str
		.replace(/\*\//g, "* /")
		.split("\n")
		.join("\n * ")}\n */`;
};

class BannerPlugin {
	/**
	 * @param {BannerPluginArgument} options options object
	 */
	constructor(options) {
		if (arguments.length > 1) {
			throw new Error(
				"BannerPlugin only takes one argument (pass an options object)"
			);
		}

		validateOptions(schema, options, "Banner Plugin");

		if (["string", "function"].indexOf(typeof options) !== -1) {
			options = {
				banner: options
			};
		}

		/** @type {BannerPluginOptions} */
		this.options = options;

		const bannerOption = options.banner;
		if (typeof bannerOption === "function") {
			const getBanner = bannerOption;
			this.banner = this.options.raw
				? getBanner
				: data => wrapComment(getBanner(data));
		} else {
			const banner = this.options.raw
				? bannerOption
				: wrapComment(bannerOption);
			this.banner = () => banner;
		}
	}

	apply(compiler) {
		const options = this.options;
		const banner = this.banner;
		const matchObject = ModuleFilenameHelpers.matchObject.bind(
			undefined,
			options
		);

		compiler.hooks.compilation.tap("BannerPlugin", compilation => {
			compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
				for (const chunk of chunks) {
					if (options.entryOnly && !chunk.canBeInitial()) {
						continue;
					}

					for (const file of chunk.files) {
						if (!matchObject(file)) {
							continue;
						}

						let basename;
						let query = "";
						let filename = file;
						const hash = compilation.hash;
						const querySplit = filename.indexOf("?");

						if (querySplit >= 0) {
							query = filename.substr(querySplit);
							filename = filename.substr(0, querySplit);
						}

						const lastSlashIndex = filename.lastIndexOf("/");

						if (lastSlashIndex === -1) {
							basename = filename;
						} else {
							basename = filename.substr(lastSlashIndex + 1);
						}

						const data = {
							hash,
							chunk,
							filename,
							basename,
							query
						};

						const comment = compilation.getPath(banner(data), data);

						compilation.assets[file] = new ConcatSource(
							comment,
							"\n",
							compilation.assets[file]
						);
					}
				}
			});
		});
	}
}

module.exports = BannerPlugin;
<|endoftext|>


<commit_before>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var url = require('url');
var querystring = require('querystring');

var logmagic = require('logmagic');
var request = require('request');

var misc = require('./misc');
var sprintf = require('./sprintf');

/**
 * PagerDuty Client.
 * @constructor
 * @param {Object} options The options.
 */
function PagerDuty(options, log) {
  var parsed = url.parse(options.url);

  // Inject auth into the URL
  delete parsed.host;
  parsed['auth'] = sprintf('%s:%s', options.username, options.password);

  this.url = options.url;
  this.authedURL = url.format(parsed);
  this.users = options.users;
  this.schedules = options.schedules;
  this.log = log || logmagic.local('pagerduty');
}

/**
 * Create a schedule override.
 */
PagerDuty.prototype.override = function(schedule, user, startTime, endTime, callback) {
  var self = this,
      scheduleId = this.schedules[schedule],
      userId = this.users[user],
      reqOpts;

  if (!scheduleId) {
    callback(new Error('Unconfigured schedule: ' + schedule));
    return;
  }

  if (!userId) {
    callback(new Error('Unconfigured user: ' + user));
    return;
  }

  reqOpts = {
    method: 'POST',
    uri: sprintf('%sapi/v1/schedules/%s/overrides', this.authedURL, scheduleId),
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      override: {
        start: startTime.toISOString(),
        end: endTime.toISOString(),
        user_id: userId
      }
    })
  };

  request(reqOpts, function(err, response, body) {
    var obj;

    if (err) {
      callback(err);
    } else if ([201, 200].indexOf(response.statusCode) === -1) {
      callback(new Error(sprintf('Received %s from %s', response.statusCode, self.url)));
    } else {
      try {
        obj = JSON.parse(body);
      } catch (e) {
        err = e;
      }
      callback(err, err ? null : obj.override);
    }
  });
};

/** PagerDuty Class */
exports.PagerDuty = PagerDuty;
<commit_msg>chore(pagerduty): Rejig pagerduty util to use an auth token in lieu of a username and password<commit_after>/*
 *  Copyright 2011 Rackspace
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

var url = require('url');
var querystring = require('querystring');

var logmagic = require('logmagic');
var request = require('request');

var misc = require('./misc');
var sprintf = require('./sprintf');

/**
 * PagerDuty Client.
 * @constructor
 * @param {Object} options The options.
 */
function PagerDuty(options, log) {
  var parsed = url.parse(options.url);
  this.url = options.url;
  this.users = options.users;
  this.schedules = options.schedules;
  this.log = log || logmagic.local('pagerduty');
  this.pagerduty_auth = sprintf('Token token=%s', options.apiKey);
}

/**
 * Create a schedule override.
 */
PagerDuty.prototype.override = function(schedule, user, startTime, endTime, callback) {
  var self = this,
      scheduleId = this.schedules[schedule],
      userId = this.users[user],
      reqOpts;

  if (!scheduleId) {
    callback(new Error('Unconfigured schedule: ' + schedule));
    return;
  }

  if (!userId) {
    callback(new Error('Unconfigured user: ' + user));
    return;
  }

  reqOpts = {
    method: 'POST',
    uri: sprintf('%sapi/v1/schedules/%s/overrides', this.url, scheduleId),
    headers: {
      'Content-Type': 'application/json',
      'Authorization': this.pagerduty_auth
    },
    body: JSON.stringify({
      override: {
        start: startTime.toISOString(),
        end: endTime.toISOString(),
        user_id: userId
      }
    })
  };

  request(reqOpts, function(err, response, body) {
    var obj;

    if (err) {
      callback(err);
    } else if ([201, 200].indexOf(response.statusCode) === -1) {
      callback(new Error(sprintf('Received %s from %s', response.statusCode, self.url)));
    } else {
      try {
        obj = JSON.parse(body);
      } catch (e) {
        err = e;
      }
      callback(err, err ? null : obj.override);
    }
  });
};

/** PagerDuty Class */
exports.PagerDuty = PagerDuty;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

utils.platform = (function () {
  let platform = {}

  const userAgent = (navigator.userAgent).toLowerCase()
  const language = navigator.language || navigator.browserLanguage

  const version = platform.version = (userAgent.match(/.*(?:rv|chrome|webkit|opera|ie)[/: ](.+?)([ );]|$)/) || [])[1]
  const webkitVersion = (userAgent.match(/webkit\/(.+?) /) || [])[1]

  platform.windows = platform.isWindows = !!/windows/.test(userAgent)
  platform.mac = platform.isMac = !!/macintosh/.test(userAgent) || (/mac os x/.test(userAgent) && !/like mac os x/.test(userAgent))
  platform.lion = platform.isLion = !!(/mac os x 10_7/.test(userAgent) && !/like mac os x 10_7/.test(userAgent))
  platform.iPhone = platform.isiPhone = !!/iphone/.test(userAgent)
  platform.iPod = platform.isiPod = !!/ipod/.test(userAgent)
  platform.iPad = platform.isiPad = !!/ipad/.test(userAgent)
  platform.iOS = platform.isiOS = platform.iPhone || platform.iPod || platform.iPad
  platform.android = platform.isAndroid = !!/android/.test(userAgent)
  platform.opera = /opera/.test(userAgent) ? version : 0
  platform.isOpera = !!platform.opera
  platform.msie = /msie/.test(userAgent) && !platform.opera ? version : 0
  platform.isIE = !!platform.msie
  platform.isIE8OrLower = !!(platform.msie && parseInt(platform.msie, 10) <= 8)
  platform.mozilla = /mozilla/.test(userAgent) && !/(compatible|webkit|msie)/.test(userAgent) ? version : 0
  platform.isMozilla = !!platform.mozilla
  platform.webkit = /webkit/.test(userAgent) ? webkitVersion : 0
  platform.isWebkit = !!platform.webkit
  platform.chrome = /chrome/.test(userAgent) ? version : 0
  platform.isChrome = !!platform.chrome
  platform.mobileSafari = /apple.*mobile/.test(userAgent) && platform.iOS ? webkitVersion : 0
  platform.isMobileSafari = !!platform.mobileSafari
  platform.iPadSafari = platform.iPad && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPadSafari = !!platform.iPadSafari
  platform.iPhoneSafari = platform.iPhone && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPhoneSafari = !!platform.iphoneSafari
  platform.iPodSafari = platform.iPod && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPodSafari = !!platform.iPodSafari
  platform.isiOSHomeScreen = platform.isMobileSafari && !/apple.*mobile.*safari/.test(userAgent)
  platform.safari = platform.webkit && !platform.chrome && !platform.iOS && !platform.android ? webkitVersion : 0
  platform.isSafari = !!platform.safari
  platform.language = language.split('-', 1)[0]
  platform.current =
    platform.msie ? 'msie' : platform.mozilla ? 'mozilla' : platform.chrome ? 'chrome' : platform.safari ? 'safari' : platform.opera ? 'opera' : platform.mobileSafari ? 'mobile-safari' : platform.android ? 'android' : 'unknown'

  function platformName (candidates) {
    for (let i = 0; i < candidates.length; i++) {
      if (candidates[i] in window) {
        return 'window.' + candidates[i]
      }
      if (candidates[i] in navigator) {
        return 'navigator.' + candidates[i]
      }
    }
    return undefined
  }

  platform.GUM = platformName(['getUserMedia', 'webkitGetUserMedia', 'mozGetUserMedia', 'msGetUserMedia', 'getGUM'])
  platform.PeerConnection = platformName(['webkitRTCPeerConnection', 'mozRTCPeerConnection', 'msPeerConnection'])
  platform.IceCandidate = platformName(['mozRTCIceCandidate', 'RTCIceCandidate'])
  platform.SessionDescription = platformName(['mozRTCSessionDescription', 'RTCSessionDescription'])
  platform.URL = platformName(['URL', 'webkitURL'])
  platform.AudioContext = platformName(['AudioContext', 'webkitAudioContext'])
  platform.OfflineAudioContext = platformName(['OfflineAudioContext', 'webkitOfflineAudioContext'])
  platform.MediaSource = platformName(['MediaSource', 'WebKitMediaSource'])

  platform.SpeechRecognition = platformName(['SpeechRecognition', 'webkitSpeechRecognition'])
  platform.SpeechGrammarList = platformName(['SpeechGrammarList', 'webkitSpeechGrammarList'])

  /*
   function findWebGLContextName (candidates) {
   var canvas = document.createElement('canvas')
   for (var i = 0; i < candidates.length; i++) {
   var name = candidates[i]
   try {
   if (canvas.getContext(name)) {
   return name
   }
   } catch (e) {}
   }
   return null
   }
   */

  platform.WebGL = 'webgl' // findWebGLContextName(["webgl", "experimental-webgl", "webkit-3d"]);
  platform.WebGL2 = 'webgl2' // findWebGLContextName(["webgl2", "experimental-webgl2"]);

  platform.captureStreamUntilEnded = 'captureStreamUntilEnded'
  if (platform.isMozilla) {
    platform.captureStreamUntilEnded = 'mozCaptureStreamUntilEnded'
  }

  platform.srcObject = 'srcObject'
  if (platform.isMozilla) {
    platform.srcObject = 'mozSrcObject'
  }

  return platform
})()
<commit_msg>Add platform.SpeechGrammar to platform object<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

utils.platform = (function () {
  let platform = {}

  const userAgent = (navigator.userAgent).toLowerCase()
  const language = navigator.language || navigator.browserLanguage

  const version = platform.version = (userAgent.match(/.*(?:rv|chrome|webkit|opera|ie)[/: ](.+?)([ );]|$)/) || [])[1]
  const webkitVersion = (userAgent.match(/webkit\/(.+?) /) || [])[1]

  platform.windows = platform.isWindows = !!/windows/.test(userAgent)
  platform.mac = platform.isMac = !!/macintosh/.test(userAgent) || (/mac os x/.test(userAgent) && !/like mac os x/.test(userAgent))
  platform.lion = platform.isLion = !!(/mac os x 10_7/.test(userAgent) && !/like mac os x 10_7/.test(userAgent))
  platform.iPhone = platform.isiPhone = !!/iphone/.test(userAgent)
  platform.iPod = platform.isiPod = !!/ipod/.test(userAgent)
  platform.iPad = platform.isiPad = !!/ipad/.test(userAgent)
  platform.iOS = platform.isiOS = platform.iPhone || platform.iPod || platform.iPad
  platform.android = platform.isAndroid = !!/android/.test(userAgent)
  platform.opera = /opera/.test(userAgent) ? version : 0
  platform.isOpera = !!platform.opera
  platform.msie = /msie/.test(userAgent) && !platform.opera ? version : 0
  platform.isIE = !!platform.msie
  platform.isIE8OrLower = !!(platform.msie && parseInt(platform.msie, 10) <= 8)
  platform.mozilla = /mozilla/.test(userAgent) && !/(compatible|webkit|msie)/.test(userAgent) ? version : 0
  platform.isMozilla = !!platform.mozilla
  platform.webkit = /webkit/.test(userAgent) ? webkitVersion : 0
  platform.isWebkit = !!platform.webkit
  platform.chrome = /chrome/.test(userAgent) ? version : 0
  platform.isChrome = !!platform.chrome
  platform.mobileSafari = /apple.*mobile/.test(userAgent) && platform.iOS ? webkitVersion : 0
  platform.isMobileSafari = !!platform.mobileSafari
  platform.iPadSafari = platform.iPad && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPadSafari = !!platform.iPadSafari
  platform.iPhoneSafari = platform.iPhone && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPhoneSafari = !!platform.iphoneSafari
  platform.iPodSafari = platform.iPod && platform.isMobileSafari ? webkitVersion : 0
  platform.isiPodSafari = !!platform.iPodSafari
  platform.isiOSHomeScreen = platform.isMobileSafari && !/apple.*mobile.*safari/.test(userAgent)
  platform.safari = platform.webkit && !platform.chrome && !platform.iOS && !platform.android ? webkitVersion : 0
  platform.isSafari = !!platform.safari
  platform.language = language.split('-', 1)[0]
  platform.current =
    platform.msie ? 'msie' : platform.mozilla ? 'mozilla' : platform.chrome ? 'chrome' : platform.safari ? 'safari' : platform.opera ? 'opera' : platform.mobileSafari ? 'mobile-safari' : platform.android ? 'android' : 'unknown'

  function platformName (candidates) {
    for (let i = 0; i < candidates.length; i++) {
      if (candidates[i] in window) {
        return 'window.' + candidates[i]
      }
      if (candidates[i] in navigator) {
        return 'navigator.' + candidates[i]
      }
    }
    return undefined
  }

  platform.GUM = platformName(['getUserMedia', 'webkitGetUserMedia', 'mozGetUserMedia', 'msGetUserMedia', 'getGUM'])
  platform.PeerConnection = platformName(['webkitRTCPeerConnection', 'mozRTCPeerConnection', 'msPeerConnection'])
  platform.IceCandidate = platformName(['mozRTCIceCandidate', 'RTCIceCandidate'])
  platform.SessionDescription = platformName(['mozRTCSessionDescription', 'RTCSessionDescription'])
  platform.URL = platformName(['URL', 'webkitURL'])
  platform.AudioContext = platformName(['AudioContext', 'webkitAudioContext'])
  platform.OfflineAudioContext = platformName(['OfflineAudioContext', 'webkitOfflineAudioContext'])
  platform.MediaSource = platformName(['MediaSource', 'WebKitMediaSource'])

  platform.SpeechRecognition = platformName(['SpeechRecognition', 'webkitSpeechRecognition'])
  platform.SpeechGrammarList = platformName(['SpeechGrammarList', 'webkitSpeechGrammarList'])
  platform.SpeechGrammar     = platformName(['SpeechGrammar'])

  /*
   function findWebGLContextName (candidates) {
   var canvas = document.createElement('canvas')
   for (var i = 0; i < candidates.length; i++) {
   var name = candidates[i]
   try {
   if (canvas.getContext(name)) {
   return name
   }
   } catch (e) {}
   }
   return null
   }
   */

  platform.WebGL = 'webgl' // findWebGLContextName(["webgl", "experimental-webgl", "webkit-3d"]);
  platform.WebGL2 = 'webgl2' // findWebGLContextName(["webgl2", "experimental-webgl2"]);

  platform.captureStreamUntilEnded = 'captureStreamUntilEnded'
  if (platform.isMozilla) {
    platform.captureStreamUntilEnded = 'mozCaptureStreamUntilEnded'
  }

  platform.srcObject = 'srcObject'
  if (platform.isMozilla) {
    platform.srcObject = 'mozSrcObject'
  }

  return platform
})()
<|endoftext|>


<commit_before>//Sequence object
var Sequence =
{
	//Complementary bases
	bases:
	{
		'N': 'N', 'n': 'n',
		'A': 'T', 'a': 't',
		'T': 'A', 't': 'a',
		'C': 'G', 'c': 'g',
		'G': 'C', 'g': 'c'
	},

	//Function to get the complementary base
	GetCBase: function(b){ return Sequence.bases[b]; },

	//Build the reverse complementary sequence
	Complement: function(seq)
	{
		//Reverse and get the complement sequence
		return seq.split('').reverse().map(Sequence.GetCBase).join('');
	}
};

//Exports to node
module.exports = Sequence;
<commit_msg>lib/utils/sequence.js: minor update<commit_after>//Sequence object
var Sequence = {};

//Complementary bases
Sequence.bases =
{
  'N': 'N', 'n': 'n',
  'A': 'T', 'a': 't',
  'T': 'A', 't': 'a',
  'C': 'G', 'c': 'g',
  'G': 'C', 'g': 'c'
};

//Function to get the complementary base
Sequence.getCBase = function(b){ return Sequence.bases[b]; },

//Build the reverse complementary sequence
Sequence.complement = function(seq)
{
  //Reverse and get the complement sequence
  return seq.split('').reverse().map(Sequence.getCBase).join('');
};

//Exports to node
module.exports = Sequence;
<|endoftext|>


<commit_before>var ReactReduxContext = require('react-redux').ReactReduxContext
var useContext = require('react').useContext
var useEffect = require('react').useEffect
var useState = require('react').useState

function add (store, subscriptions) {
  if (!store.subscriptions) store.subscriptions = { }
  if (!store.subscribers) store.subscribers = { }

  return Promise.all(subscriptions.map(function (i) {
    var subscription = i[0]
    var json = i[1]
    if (!store.subscribers[json]) store.subscribers[json] = 0
    store.subscribers[json] += 1
    if (store.subscribers[json] === 1) {
      var action = Object.assign({ type: 'logux/subscribe' }, subscription)
      store.subscriptions[json] = store.dispatch.sync(action)
    }
    return store.subscriptions[json]
  }))
}

function remove (store, subscriptions) {
  subscriptions.forEach(function (i) {
    var subscription = i[0]
    var json = i[1]
    store.subscribers[json] -= 1
    if (store.subscribers[json] === 0) {
      var action = Object.assign({ type: 'logux/unsubscribe' }, subscription)
      store.log.add(action, { sync: true })
      delete store.subscriptions[json]
    }
  })
}

/**
 * @typedef {object} Subscribe
 * @property {string} channel
 */

/**
 * @typedef {string|Subscribe} Channel
 */

/**
 * Hook to subscribe for channel during component render and unsubscribe
 * on component unmount.
 *
 * @param  {Channel[]} channels Channels to subscribe.
 * @param  {object}  [opts={}] Options.
 * @param  {Context} [opts.context] Context with the store.
 * @return {boolean} `true` during data loading.
 *
 * @example
 * import useSubscription from '@logux/redux/use-subscription'
 * import { useSelector } from 'react-redux'
 *
 * const UserPage = ({ userId }) => {
 *   const isSubscribing = useSubscription(`user/${ userId }`)
 *   const user = useSelector(state => state.users.find(i => i.id === userId))
 *   if (isSubscribing) {
 *     return <Loader />
 *   } else {
 *     return
{ user.name }

 *   }
 * }
 */
function useSubscription (channels, opts) {
  if (!opts) opts = { }

  var isSubscribing = useState(true)
  var store = useContext(opts.context || ReactReduxContext).store

  var subscriptions = channels.map(function (i) {
    var subscription = typeof i === 'string' ? { channel: i } : i
    return [subscription, JSON.stringify(subscription)]
  })

  var id = subscriptions.map(function (i) {
    return i[1]
  }).sort().join(' ')

  useEffect(function () {
    var updated = false
    add(store, subscriptions).then(function () {
      if (!updated) isSubscribing[1](false)
    })
    return function () {
      updated = true
      remove(store, subscriptions)
    }
  }, [id])

  return isSubscribing[0]
}

module.exports = useSubscription
<commit_msg>Fix JSDoc<commit_after>var ReactReduxContext = require('react-redux').ReactReduxContext
var useContext = require('react').useContext
var useEffect = require('react').useEffect
var useState = require('react').useState

function add (store, subscriptions) {
  if (!store.subscriptions) store.subscriptions = { }
  if (!store.subscribers) store.subscribers = { }

  return Promise.all(subscriptions.map(function (i) {
    var subscription = i[0]
    var json = i[1]
    if (!store.subscribers[json]) store.subscribers[json] = 0
    store.subscribers[json] += 1
    if (store.subscribers[json] === 1) {
      var action = Object.assign({ type: 'logux/subscribe' }, subscription)
      store.subscriptions[json] = store.dispatch.sync(action)
    }
    return store.subscriptions[json]
  }))
}

function remove (store, subscriptions) {
  subscriptions.forEach(function (i) {
    var subscription = i[0]
    var json = i[1]
    store.subscribers[json] -= 1
    if (store.subscribers[json] === 0) {
      var action = Object.assign({ type: 'logux/unsubscribe' }, subscription)
      store.log.add(action, { sync: true })
      delete store.subscriptions[json]
    }
  })
}

/**
 * @typedef {object} Subscribe
 * @property {string} channel
 */

/**
 * @typedef {string|Subscribe} Channel
 */

/**
 * Hook to subscribe for channel during component render and unsubscribe
 * on component unmount.
 *
 * @param  {Channel[]} channels Channels to subscribe.
 * @param  {object}  [opts={}] Options.
 * @param  {Context} [opts.context] Context with the store.
 * @return {boolean} `true` during data loading.
 *
 * @example
 * import useSubscription from '@logux/redux/use-subscription'
 * import { useSelector } from 'react-redux'
 *
 * const UserPage = ({ userId }) => {
 *   const isSubscribing = useSubscription([`user/${ userId }`])
 *   const user = useSelector(state => state.users.find(i => i.id === userId))
 *   if (isSubscribing) {
 *     return <Loader />
 *   } else {
 *     return
{ user.name }

 *   }
 * }
 */
function useSubscription (channels, opts) {
  if (!opts) opts = { }

  var isSubscribing = useState(true)
  var store = useContext(opts.context || ReactReduxContext).store

  var subscriptions = channels.map(function (i) {
    var subscription = typeof i === 'string' ? { channel: i } : i
    return [subscription, JSON.stringify(subscription)]
  })

  var id = subscriptions.map(function (i) {
    return i[1]
  }).sort().join(' ')

  useEffect(function () {
    var updated = false
    add(store, subscriptions).then(function () {
      if (!updated) isSubscribing[1](false)
    })
    return function () {
      updated = true
      remove(store, subscriptions)
    }
  }, [id])

  return isSubscribing[0]
}

module.exports = useSubscription
<|endoftext|>


<commit_before>const parseDiff = require('parse-diff')
const shouldExcludeFile = require('./should-exclude-file')
const getDiff = require('./get-diff')
const getDetails = require('./get-details')
const checkForBody = require('./check-for-body')
const defaultConfig = require('./default-config')
const generateLabel = require('./generate-label')

module.exports = async (context, handler) => {
  // Grab the config file
  const configFile = await context.config('config.yml')
  const config = configFile && configFile.todo ? Object.assign({}, defaultConfig, configFile.todo) : defaultConfig

  // Ensure that all the labels we need are present
  const labels = await generateLabel(context, config)

  // Get the diff for this commit or PR
  const diff = await getDiff(context)

  // RegEx that matches lines with the configured keywords
  const regex = new RegExp(`.+()\\s(?<keyword>${config.keywords.join('|')})\\s(?<title>.*)`)

  // Parse the diff as files
  const files = parseDiff(diff)

  for (const file of files) {
    if (shouldExcludeFile(context.log, file.to, config.exclude)) continue

    // Loop through every chunk in the file
    for (const chunk of file.chunks) {
      // Chunks can have multiple changes
      for (const indexStr in chunk.changes) {
        const index = parseInt(indexStr, 10)
        const change = chunk.changes[index]

        // Attempt to find a matching line: TODO Something something
        const matches = regex.exec(change.content)
        if (!matches) continue

        const { title, keyword } = matches.groups

        const deets = getDetails({ context, config, chunk, line: change.ln || change.ln2 })

        await handler({
          title,
          bodyComment: checkForBody(chunk.changes, index, config),
          config,
          keyword,
          filename: file.to,
          chunk,
          index,
          labels,
          ...deets
        })
      }
    }
  }
}
<commit_msg>Fix a bug<commit_after>const parseDiff = require('parse-diff')
const shouldExcludeFile = require('./should-exclude-file')
const getDiff = require('./get-diff')
const getDetails = require('./get-details')
const checkForBody = require('./check-for-body')
const defaultConfig = require('./default-config')
const generateLabel = require('./generate-label')

module.exports = async (context, handler) => {
  // Grab the config file
  const configFile = await context.config('config.yml')
  const config = configFile && configFile.todo ? Object.assign({}, defaultConfig, configFile.todo) : defaultConfig
  const keywords = Array.isArray(config.keyword) ? config.keyword : [config.keyword]

  // Ensure that all the labels we need are present
  const labels = await generateLabel(context, config)

  // Get the diff for this commit or PR
  const diff = await getDiff(context)

  // RegEx that matches lines with the configured keywords
  const regex = new RegExp(`.+()\\s(?<keyword>${keywords.join('|')})\\s(?<title>.*)`)

  // Parse the diff as files
  const files = parseDiff(diff)

  for (const file of files) {
    if (shouldExcludeFile(context.log, file.to, config.exclude)) continue

    // Loop through every chunk in the file
    for (const chunk of file.chunks) {
      // Chunks can have multiple changes
      for (const indexStr in chunk.changes) {
        const index = parseInt(indexStr, 10)
        const change = chunk.changes[index]

        // Attempt to find a matching line: TODO Something something
        const matches = regex.exec(change.content)
        if (!matches) continue

        const { title, keyword } = matches.groups

        const deets = getDetails({ context, config, chunk, line: change.ln || change.ln2 })

        await handler({
          title,
          bodyComment: checkForBody(chunk.changes, index, config),
          config,
          keyword,
          filename: file.to,
          chunk,
          index,
          labels,
          ...deets
        })
      }
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

class Confirmation {
  constructor(data) {
    this.key = data.key;
    this.id = data.id;
    this.description = data.description;
    this.tradeId = data.tradeId;
  }
}
<commit_msg>Added documentation:<commit_after>'use strict';

/**
 * This class exists solely to have a centralized set of values for each confirmation
 * Hence why there is nothing but a constructor... :D
 */
class Confirmation {
  constructor(data) {
    this.key = data.key;
    this.id = data.id;
    this.description = data.description;
    this.tradeId = data.tradeId;
  }
}
<|endoftext|>