<commit_before>var express           = require('express');
var mongoose          = require('mongoose');
var bodyParser        = require('body-parser');
var FileStreamRotator = require('file-stream-rotator');
var fs                = require('fs');
var morgan            = require('morgan');

var routes = require('./routes/routes');
var logDirectory = __dirname + '/logs';

/**
 * Express Setup
 */
var app = express();

// ensure log directory exists
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);

// var accessLogStream = fs.createWriteStream(__dirname + '/access.log',{flags: 'a'});

// create a rotating write stream
var accessLogStream = FileStreamRotator.getStream({
  filename: logDirectory + '/access-%DATE%.log',
  frequency: 'daily',
  verbose: false
});

// configure app to use bodyParser() to get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Toggle tools and logging based on enviroment setting
if (app.get('env') == 'development') {
  // To output objects for debugging
  // console.log("/ request: " + util.inspect(request, false, null));
  var util = require('util');
  app.use(morgan('dev', {stream: accessLogStream}));
}
else if (app.get('env') == 'production') {
  app.use(morgan('common', {
    skip: function(req, res) { return res.statusCode < 400 },
    stream: accessLogStream
  }));
}

// REGISTER ROUTES
// =============================================================================
// All of routes will be prefixed with /api
app.use('/api', routes);

// Assign to module to allow testing vs binding to a port - via
module.exports = app;
<commit_msg>Require util module for both development and test node enviroments<commit_after>var express           = require('express');
var mongoose          = require('mongoose');
var bodyParser        = require('body-parser');
var FileStreamRotator = require('file-stream-rotator');
var fs                = require('fs');
var morgan            = require('morgan');

var routes = require('./routes/routes');
var logDirectory = __dirname + '/logs';

/**
 * Express Setup
 */
var app = express();

// ensure log directory exists
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);

// var accessLogStream = fs.createWriteStream(__dirname + '/access.log',{flags: 'a'});

// create a rotating write stream
var accessLogStream = FileStreamRotator.getStream({
  filename: logDirectory + '/access-%DATE%.log',
  frequency: 'daily',
  verbose: false
});

// configure app to use bodyParser() to get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Toggle tools and logging based on enviroment setting
if (app.get('env') == 'development' || app.get('env') == 'test') {
  // To output objects for debugging
  // console.log("/ request: " + util.inspect(request, false, null));
  var util = require('util');
  app.use(morgan('dev', {stream: accessLogStream}));
}
else if (app.get('env') == 'production') {
  app.use(morgan('common', {
    skip: function(req, res) { return res.statusCode < 400 },
    stream: accessLogStream
  }));
}

// REGISTER ROUTES
// =============================================================================
// All of routes will be prefixed with /api
app.use('/api', routes);

// Assign to module to allow testing vs binding to a port - via
module.exports = app;
<|endoftext|>


<commit_before>/*var io = require('socket.io-client');

console.log('connecting')
var socket = io.connect('http://192.168.56.101:3000');

socket.on('cpu-ip', function(msg){
console.log(msg)
});*/

var requestsHandledPerInterval = 20

function calculateOptimalServers(redisClient, timeInterval, seriesTag, callback){
    redisClient.get(seriesTag + ":requests:" + timeInterval, function(err, value){
        console.log(value);
        var optimalServers = Math.ceil(value / requestsHandledPerInterval);
        callback(timeInterval, optimalServers);
    });
}

function createEmitOptimal(io){
    return function(timeInterval, optimalServers){
        io.emit('optimal-servers', JSON.stringify({"timeInterval": timeInterval, "optimalServers": optimalServers}));
    }
}

module.exports = function(redisClient, timeInterval, io){
    for(var i = 0; i < 1000000; i += 10000){
        calculateOptimalServers(redisClient, i, "training", createEmitOptimal(io));
    }

    /*var prevInterval = timeInterval - (10 * 1000);
    //Calculate true optimal for previous timeframe
    redisClient.get("testing:requests:" + prevInterval, function(err,value){
    var optimalServers = Math.ceil(value / requestsHandledPerInterval);
    io.emit('optimal-servers', JSON.stringify({"timeInterval": timeInterval, "optimalServers": optimalServers}))
});*/
}
<commit_msg>Removed debug code<commit_after>/*var io = require('socket.io-client');

console.log('connecting')
var socket = io.connect('http://192.168.56.101:3000');

socket.on('cpu-ip', function(msg){
console.log(msg)
});*/

var requestsHandledPerInterval = 20

function calculateOptimalServers(redisClient, timeInterval, seriesTag, callback){
    redisClient.get(seriesTag + ":requests:" + timeInterval, function(err, value){
        var optimalServers = Math.ceil(value / requestsHandledPerInterval);
        callback(timeInterval, optimalServers);
    });
}

function createEmitOptimal(io){
    return function(timeInterval, optimalServers){
        io.emit('optimal-servers', JSON.stringify({"timeInterval": timeInterval, "optimalServers": optimalServers}));
    }
}

module.exports = function(redisClient, timeInterval, io){
    for(var i = 0; i < 1000000; i += 10000){
        calculateOptimalServers(redisClient, i, "training", createEmitOptimal(io));
    }

    /*var prevInterval = timeInterval - (10 * 1000);
    //Calculate true optimal for previous timeframe
    redisClient.get("testing:requests:" + prevInterval, function(err,value){
    var optimalServers = Math.ceil(value / requestsHandledPerInterval);
    io.emit('optimal-servers', JSON.stringify({"timeInterval": timeInterval, "optimalServers": optimalServers}))
});*/
}
<|endoftext|>


<commit_before>'use strict'

var Packet = require('aedes-packet')
var Redis = require('ioredis')
var through = require('through2')
var throughv = require('throughv')
var msgpack = require('msgpack-lite')
var pump = require('pump')
var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')
var Qlobber = require('qlobber').Qlobber
var qlobberOpts = {
  separator: '/',
  wildcard_one: '+',
  wildcard_some:  '#'
}
var offlineClientsCountKey = 'counter:offline:clients'
var offlineSubscriptionsCountKey = 'counter:offline:subscriptions'
var newSubTopic = 'SYS$/newsub'
var rmSubTopic = 'SYS$/rmsub'

function RedisPersistence (opts) {
  if (!(this instanceof RedisPersistence)) {
    return new RedisPersistence(opts)
  }

  this._db = new Redis(opts)
  this._sub = new Redis(opts)
  this._pipeline = null

  var that = this
  this._decodeAndAugment = function decodeAndAugment (chunk, enc, cb) {
    that._getPipeline().getBuffer(chunk, function (err, result) {
      var decoded
      if (result) {
        decoded = msgpack.decode(result)
      }
      cb(err, decoded)
    })
  }
  this._matcher = null
  this._ready = false
  this._destroyed = false
  this._setup()

  this._sub.subscribe(newSubTopic)
  this._sub.on('messageBuffer', function (channel, buf) {
    console.log('new message on', channel)
    if (channel === newSubTopic) {
      var decoded = msgpack.decode(buf)
      that._matcher.add(decoded.topic, decoded)
    } else if (channel === rmSubTopic) {
      var decoded = msgpack.decode(buf)
      that._matcher
        .match(decoded.topic)
        .filter(matching, decoded.topic)
        .forEach(rmSub, that._matcher)
    }
  })
}

function matching (sub) {
  return sub.topic === this
}

function rmSub (sub) {
  this.remove(sub.topic, sub)
}

inherits(RedisPersistence, EventEmitter)

RedisPersistence.prototype._getPipeline = function() {
  if (!this._pipeline) {
    this._pipeline = this._db.pipeline()
    process.nextTick(execPipeline, this)
  }
  return this._pipeline
}

function execPipeline (that) {
  that._pipeline.exec()
  that._pipeline = null
}

RedisPersistence.prototype.storeRetained = function (packet, cb) {
  var key = 'retained:' + packet.topic
  if (packet.payload.length === 0) {
    this._db.del(key, cb)
  } else {
    this._db.set(key, msgpack.encode(packet), cb)
  }
}

function checkAndSplit (prefix, pattern) {
  var qlobber = new Qlobber(qlobberOpts)
  qlobber.add(pattern, true)

  // TODO use ctor
  var instance = through.obj(splitArray)

  instance._qlobber = qlobber
  instance._prefix = prefix

  return instance
}

function splitArray (keys, enc, cb) {
  var prefix = this._prefix.length
  for (var i = 0, l = keys.length; i < l; i++) {
    var key = keys[i].slice(prefix)
    if (this._qlobber.match(key).length > 0) {
      this.push(keys[i])
    }
  }
  cb()
}

RedisPersistence.prototype.createRetainedStream = function (pattern) {
  return this._db.scanStream({
    match: 'retained:' + pattern.split(/[#+]/)[0] + '*',
    count: 100
  }).pipe(checkAndSplit('retained:', pattern))
    .pipe(throughv.obj(this._decodeAndAugment))
}

function asKeyValuePair (acc, sub) {
  acc[sub.topic] = sub.qos
  return acc
}

function Sub (clientId, topic, qos) {
  this.clientId = clientId
  this.topic = topic
  this.qos = qos
}

RedisPersistence.prototype.addSubscriptions = function (client, subs, cb) {
  var multi = this._db.multi()

  var clientSubKey = "client:sub:" + client.id
  var that = this

  var toStore = subs.reduce(asKeyValuePair, {})
  multi.exists(clientSubKey)
  multi.hmset(clientSubKey, toStore)

  var count = 0

  subs.forEach(function (sub) {
    if (sub.qos > 0) {
      var subClientKey = 'sub:client:' + sub.topic
      var encoded = msgpack.encode(new Sub(client.id, sub.topic, sub.qos))
      multi.hset(subClientKey, client.id, encoded)
      multi.publish(newSubTopic, encoded)
      count++
    }
  })

  multi.exec(function (err, results) {
    var existed = results.length > 0 && results[0][1] > 0
    var pipeline = that._getPipeline()
    if (!existed)
      pipeline.incr(offlineClientsCountKey)

    pipeline.incrby(offlineSubscriptionsCountKey, count)
    cb(err, client)
  })
}

RedisPersistence.prototype.removeSubscriptions = function (client, subs, cb) {
  var clientSubKey = "client:sub:" + client.id

  var that = this
  var multi = this._db.multi()
  multi.hgetall(clientSubKey)

  subs.reduce(function (multi, sub) {
    var subClientKey = 'sub:client:' + sub.topic
    multi.hdel(subClientKey, client.id)
    multi.publish(rmSubTopic, msgpack.encode({
      topic: sub.topic,
      clientId: client.id
    }))
    return multi.hdel(clientSubKey, sub)
  }, multi)

  multi.exec(function (err, results) {
    if (err) { return cb(err) }

    var prev = 0
    var skipped = 0
    for (var i = 1; i < results.length; i += 3) {
      if (results[i] === '0') {
        skipped++
      }
    }
    var pipeline = that._getPipeline()
    pipeline.decrby(offlineSubscriptionsCountKey, subs.length - skipped)

    cb(null, client)
  })
}

RedisPersistence.prototype.subscriptionsByClient = function (client, cb) {
  var pipeline = this._getPipeline()

  var clientSubKey = "client:sub:" + client.id
  var that = this

  pipeline.hgetall(clientSubKey, function (err, subs) {
    var toReturn = Object.keys(subs).map(function (sub) {
      return {
        topic: sub,
        qos: parseInt(this[sub])
      }
    }, subs)
    cb(err, toReturn.length > 0 ? toReturn : null, client)
  })
}

RedisPersistence.prototype.countOffline = function (cb) {
  var pipeline = this._getPipeline()
  var subsCount = -1
  var clientsCount = -1
  pipeline.get(offlineSubscriptionsCountKey, function (err, count) {
    if (err) { return cb(err) }

    subsCount = parseInt(count)

    if (clientsCount >= 0)
      cb(null, subsCount, clientsCount)
  })
  pipeline.get(offlineClientsCountKey, function (err, count) {
    if (err) { return cb(err) }

    clientsCount = parseInt(count)

    if (subsCount >= 0)
      cb(null, subsCount, clientsCount)
  })
}

RedisPersistence.prototype.subscriptionsByTopic = function (topic, cb) {
  if (!this._ready) {
    this.once('ready', this.subscriptionsByTopic.bind(this, topic, cb))
    return this
  }

  var result = this._matcher.match(topic)

  cb(null, result)
}

RedisPersistence.prototype._setup = function () {
  if (this._ready) {
    return
  }

  var that = this
  var prefix = 'sub:client:'

  this._matcher = new Qlobber(qlobberOpts)

  var scanStream = this._db.scanStream({
    match: prefix + '*',
    count: 100
  })
  var splitStream = through.obj(split)
  var hgetallStream = throughv.obj(function (chunk, enc, cb) {
    var pipeline = that._getPipeline()
    pipeline.hgetallBuffer(chunk, cb)
  }, function (cb) {
    that._ready = true
    that.emit('ready')
  })
  .on('data', function (all) {
    Object.keys(all).forEach(insert, all)
  })

  pump(scanStream, splitStream, hgetallStream, function (err) {
    if (that._destroyed) {
      return
    }

    if (err) {
      that.emit('error', err)
    }
  })

  function insert (key) {
    var decoded = msgpack.decode(this[key])
    decoded.clientId = key

    that._matcher.add(decoded.topic, decoded)
  }
}

RedisPersistence.prototype.cleanSubscriptions = function (client, cb) {
  var clientSubKey = "client:sub:" + client.id
  var pipeline = this._getPipeline()
  var that = this
  pipeline.hgetallBuffer(clientSubKey, function (err, subs) {
    if (err) { return cb(err) }

    var multi = that._db.multi()

    multi.del(clientSubKey)

    Object.keys(subs).forEach(function (topic) {
      var subClientKey = 'sub:client:' + topic
      multi.hdel(subClientKey, client.id)
      multi.publish(rmSubTopic, msgpack.encode({
        topic: topic,
        clientId: client.id
      }))
    })

    multi.exec(function (err) {
      cb(err, client)
    })
  })
}

RedisPersistence.prototype.outgoingEnqueue = function (sub, packet, cb) {
  var key = 'outgoing:' + sub.clientId + ':' + packet.brokerId + ':' + packet.brokerCounter
  this._getPipeline().set(key, msgpack.encode(new Packet(packet)), cb)
}

function updateWithBrokerData (that, client, packet, cb) {
  var prekey = 'outgoing:' + client.id + ':' + packet.brokerId + ':' + packet.brokerCounter
  var postkey = 'outgoing-id:' + client.id + ':' + packet.messageId

  that._db.getBuffer(prekey, function (err, buf) {
    if (err || !buf) { return }
    var decoded = msgpack.decode(buf)
    if (decoded.messageId > 0) {
      var todel = 'outgoing-id:' + client.id + ':' + decoded.messageId
      that._getPipeline().del(todel)
    }
  })

  var multi = that._db.multi()
  multi.set(postkey, msgpack.encode(packet))
  multi.set(prekey, msgpack.encode(packet))

  multi.exec(function (err, results) {
    if (err) { return cb(err, client, packet) }

    if (results[0][1] !== 'OK') {
      cb(new Error('no such packet'), client, packet)
    } else {
      cb(null, client, packet)
    }
  })
}

function augmentWithBrokerData (that, client, packet, cb) {
  var postkey = 'outgoing-id:' + client.id + ':' + packet.messageId
  that._getPipeline().getBuffer(postkey, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no suck packet')) }
    var decoded = msgpack.decode(buf)
    packet.brokerId = decoded.brokerId
    packet.brokerCounter = decoded.brokerCounter
    cb(null)
  })
}

RedisPersistence.prototype.outgoingUpdate = function (client, packet, cb) {
  var that = this
  if (packet.brokerId) {
    updateWithBrokerData(this, client, packet, cb)
  } else {
    augmentWithBrokerData(this, client, packet, function (err) {
      if (err) { return cb(err, client, packet) }

      updateWithBrokerData(that, client, packet, cb)
    })
  }
}

RedisPersistence.prototype.outgoingClearMessageId = function (client, packet, cb) {
  var that = this
  var key = 'outgoing-id:' + client.id + ':' + packet.messageId
  this._getPipeline().getBuffer(key, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no suck packet')) }

    var packet = msgpack.decode(buf)
    var prekey = 'outgoing:' + client.id + ':' + packet.brokerId + ':' + packet.brokerCounter
    var multi = that._db.multi()
    multi.del(key)
    multi.del(prekey)
    multi.exec(function (err) {
      cb(err, client)
    })
  })
}

function split (keys, enc, cb) {
  for (var i = 0, l = keys.length; i < l; i++) {
    this.push(keys[i])
  }
  cb()
}

RedisPersistence.prototype.outgoingStream = function (client) {
  return this._db.scanStream({
    match: 'outgoing:' + client.id + ':*',
    count: 16
  }).pipe(through.obj(split))
    .pipe(throughv.obj(this._decodeAndAugment))
}

RedisPersistence.prototype.incomingStorePacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  var newp = new Packet(packet)
  newp.messageId = packet.messageId
  this._getPipeline().set(key, msgpack.encode(newp), cb)
}

RedisPersistence.prototype.incomingGetPacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  this._getPipeline().getBuffer(key, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no such packet')) }
    cb(null, msgpack.decode(buf), client)
  })
}

RedisPersistence.prototype.incomingDelPacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  this._getPipeline().del(key, cb)
}

RedisPersistence.prototype.putWill = function (client, packet, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  packet.clientId = client.id
  packet.brokerId = this.broker.id
  this._getPipeline().setBuffer(key, msgpack.encode(packet), function (err) {
    cb(err, client)
  })
}

RedisPersistence.prototype.getWill = function (client, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  this._getPipeline().getBuffer(key, function (err, packet) {
    if (err) { return cb(err) }

    var result = null

    if (packet) {
      result = msgpack.decode(packet)
    }

    cb(null, result, client)
  })
}

RedisPersistence.prototype.delWill = function (client, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  var result = null
  var pipeline = this._getPipeline()

  pipeline.getBuffer(key, function (err, packet) {
    if (err) { return cb(err) }

    if (packet) {
      result = msgpack.decode(packet)
    }
  })

  pipeline.del(key, function (err) {
    cb(err, result, client)
  })
}

RedisPersistence.prototype.streamWill = function (brokers) {
  return this._db.scanStream({
    match: 'will:*',
    count: 100
  })
  .pipe(through.obj(function (chunk, enc, cb) {
    for (var i = 0, l = chunk.length; i < l; i++) {
      if (!brokers || !brokers[chunk[i].split(':')[1]]) {
        this.push(chunk[i])
      }
    }
    cb()
  }))
  .pipe(throughv.obj(this._decodeAndAugment))
}

RedisPersistence.prototype.destroy = function (cb) {
  this._destroyed = true
  this._db.disconnect()
  this._sub.disconnect()
  if (cb) {
    cb(null)
  }
}

module.exports = RedisPersistence
<commit_msg>Use util.inherits.<commit_after>'use strict'

var Packet = require('aedes-packet')
var Redis = require('ioredis')
var through = require('through2')
var throughv = require('throughv')
var msgpack = require('msgpack-lite')
var pump = require('pump')
var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits
var Qlobber = require('qlobber').Qlobber
var qlobberOpts = {
  separator: '/',
  wildcard_one: '+',
  wildcard_some:  '#'
}
var offlineClientsCountKey = 'counter:offline:clients'
var offlineSubscriptionsCountKey = 'counter:offline:subscriptions'
var newSubTopic = 'SYS$/newsub'
var rmSubTopic = 'SYS$/rmsub'

function RedisPersistence (opts) {
  if (!(this instanceof RedisPersistence)) {
    return new RedisPersistence(opts)
  }

  this._db = new Redis(opts)
  this._sub = new Redis(opts)
  this._pipeline = null

  var that = this
  this._decodeAndAugment = function decodeAndAugment (chunk, enc, cb) {
    that._getPipeline().getBuffer(chunk, function (err, result) {
      var decoded
      if (result) {
        decoded = msgpack.decode(result)
      }
      cb(err, decoded)
    })
  }
  this._matcher = null
  this._ready = false
  this._destroyed = false
  this._setup()

  this._sub.subscribe(newSubTopic)
  this._sub.on('messageBuffer', function (channel, buf) {
    console.log('new message on', channel)
    if (channel === newSubTopic) {
      var decoded = msgpack.decode(buf)
      that._matcher.add(decoded.topic, decoded)
    } else if (channel === rmSubTopic) {
      var decoded = msgpack.decode(buf)
      that._matcher
        .match(decoded.topic)
        .filter(matching, decoded.topic)
        .forEach(rmSub, that._matcher)
    }
  })
}

function matching (sub) {
  return sub.topic === this
}

function rmSub (sub) {
  this.remove(sub.topic, sub)
}

inherits(RedisPersistence, EventEmitter)

RedisPersistence.prototype._getPipeline = function() {
  if (!this._pipeline) {
    this._pipeline = this._db.pipeline()
    process.nextTick(execPipeline, this)
  }
  return this._pipeline
}

function execPipeline (that) {
  that._pipeline.exec()
  that._pipeline = null
}

RedisPersistence.prototype.storeRetained = function (packet, cb) {
  var key = 'retained:' + packet.topic
  if (packet.payload.length === 0) {
    this._db.del(key, cb)
  } else {
    this._db.set(key, msgpack.encode(packet), cb)
  }
}

function checkAndSplit (prefix, pattern) {
  var qlobber = new Qlobber(qlobberOpts)
  qlobber.add(pattern, true)

  // TODO use ctor
  var instance = through.obj(splitArray)

  instance._qlobber = qlobber
  instance._prefix = prefix

  return instance
}

function splitArray (keys, enc, cb) {
  var prefix = this._prefix.length
  for (var i = 0, l = keys.length; i < l; i++) {
    var key = keys[i].slice(prefix)
    if (this._qlobber.match(key).length > 0) {
      this.push(keys[i])
    }
  }
  cb()
}

RedisPersistence.prototype.createRetainedStream = function (pattern) {
  return this._db.scanStream({
    match: 'retained:' + pattern.split(/[#+]/)[0] + '*',
    count: 100
  }).pipe(checkAndSplit('retained:', pattern))
    .pipe(throughv.obj(this._decodeAndAugment))
}

function asKeyValuePair (acc, sub) {
  acc[sub.topic] = sub.qos
  return acc
}

function Sub (clientId, topic, qos) {
  this.clientId = clientId
  this.topic = topic
  this.qos = qos
}

RedisPersistence.prototype.addSubscriptions = function (client, subs, cb) {
  var multi = this._db.multi()

  var clientSubKey = "client:sub:" + client.id
  var that = this

  var toStore = subs.reduce(asKeyValuePair, {})
  multi.exists(clientSubKey)
  multi.hmset(clientSubKey, toStore)

  var count = 0

  subs.forEach(function (sub) {
    if (sub.qos > 0) {
      var subClientKey = 'sub:client:' + sub.topic
      var encoded = msgpack.encode(new Sub(client.id, sub.topic, sub.qos))
      multi.hset(subClientKey, client.id, encoded)
      multi.publish(newSubTopic, encoded)
      count++
    }
  })

  multi.exec(function (err, results) {
    var existed = results.length > 0 && results[0][1] > 0
    var pipeline = that._getPipeline()
    if (!existed)
      pipeline.incr(offlineClientsCountKey)

    pipeline.incrby(offlineSubscriptionsCountKey, count)
    cb(err, client)
  })
}

RedisPersistence.prototype.removeSubscriptions = function (client, subs, cb) {
  var clientSubKey = "client:sub:" + client.id

  var that = this
  var multi = this._db.multi()
  multi.hgetall(clientSubKey)

  subs.reduce(function (multi, sub) {
    var subClientKey = 'sub:client:' + sub.topic
    multi.hdel(subClientKey, client.id)
    multi.publish(rmSubTopic, msgpack.encode({
      topic: sub.topic,
      clientId: client.id
    }))
    return multi.hdel(clientSubKey, sub)
  }, multi)

  multi.exec(function (err, results) {
    if (err) { return cb(err) }

    var prev = 0
    var skipped = 0
    for (var i = 1; i < results.length; i += 3) {
      if (results[i] === '0') {
        skipped++
      }
    }
    var pipeline = that._getPipeline()
    pipeline.decrby(offlineSubscriptionsCountKey, subs.length - skipped)

    cb(null, client)
  })
}

RedisPersistence.prototype.subscriptionsByClient = function (client, cb) {
  var pipeline = this._getPipeline()

  var clientSubKey = "client:sub:" + client.id
  var that = this

  pipeline.hgetall(clientSubKey, function (err, subs) {
    var toReturn = Object.keys(subs).map(function (sub) {
      return {
        topic: sub,
        qos: parseInt(this[sub])
      }
    }, subs)
    cb(err, toReturn.length > 0 ? toReturn : null, client)
  })
}

RedisPersistence.prototype.countOffline = function (cb) {
  var pipeline = this._getPipeline()
  var subsCount = -1
  var clientsCount = -1
  pipeline.get(offlineSubscriptionsCountKey, function (err, count) {
    if (err) { return cb(err) }

    subsCount = parseInt(count)

    if (clientsCount >= 0)
      cb(null, subsCount, clientsCount)
  })
  pipeline.get(offlineClientsCountKey, function (err, count) {
    if (err) { return cb(err) }

    clientsCount = parseInt(count)

    if (subsCount >= 0)
      cb(null, subsCount, clientsCount)
  })
}

RedisPersistence.prototype.subscriptionsByTopic = function (topic, cb) {
  if (!this._ready) {
    this.once('ready', this.subscriptionsByTopic.bind(this, topic, cb))
    return this
  }

  var result = this._matcher.match(topic)

  cb(null, result)
}

RedisPersistence.prototype._setup = function () {
  if (this._ready) {
    return
  }

  var that = this
  var prefix = 'sub:client:'

  this._matcher = new Qlobber(qlobberOpts)

  var scanStream = this._db.scanStream({
    match: prefix + '*',
    count: 100
  })
  var splitStream = through.obj(split)
  var hgetallStream = throughv.obj(function (chunk, enc, cb) {
    var pipeline = that._getPipeline()
    pipeline.hgetallBuffer(chunk, cb)
  }, function (cb) {
    that._ready = true
    that.emit('ready')
  })
  .on('data', function (all) {
    Object.keys(all).forEach(insert, all)
  })

  pump(scanStream, splitStream, hgetallStream, function (err) {
    if (that._destroyed) {
      return
    }

    if (err) {
      that.emit('error', err)
    }
  })

  function insert (key) {
    var decoded = msgpack.decode(this[key])
    decoded.clientId = key

    that._matcher.add(decoded.topic, decoded)
  }
}

RedisPersistence.prototype.cleanSubscriptions = function (client, cb) {
  var clientSubKey = "client:sub:" + client.id
  var pipeline = this._getPipeline()
  var that = this
  pipeline.hgetallBuffer(clientSubKey, function (err, subs) {
    if (err) { return cb(err) }

    var multi = that._db.multi()

    multi.del(clientSubKey)

    Object.keys(subs).forEach(function (topic) {
      var subClientKey = 'sub:client:' + topic
      multi.hdel(subClientKey, client.id)
      multi.publish(rmSubTopic, msgpack.encode({
        topic: topic,
        clientId: client.id
      }))
    })

    multi.exec(function (err) {
      cb(err, client)
    })
  })
}

RedisPersistence.prototype.outgoingEnqueue = function (sub, packet, cb) {
  var key = 'outgoing:' + sub.clientId + ':' + packet.brokerId + ':' + packet.brokerCounter
  this._getPipeline().set(key, msgpack.encode(new Packet(packet)), cb)
}

function updateWithBrokerData (that, client, packet, cb) {
  var prekey = 'outgoing:' + client.id + ':' + packet.brokerId + ':' + packet.brokerCounter
  var postkey = 'outgoing-id:' + client.id + ':' + packet.messageId

  that._db.getBuffer(prekey, function (err, buf) {
    if (err || !buf) { return }
    var decoded = msgpack.decode(buf)
    if (decoded.messageId > 0) {
      var todel = 'outgoing-id:' + client.id + ':' + decoded.messageId
      that._getPipeline().del(todel)
    }
  })

  var multi = that._db.multi()
  multi.set(postkey, msgpack.encode(packet))
  multi.set(prekey, msgpack.encode(packet))

  multi.exec(function (err, results) {
    if (err) { return cb(err, client, packet) }

    if (results[0][1] !== 'OK') {
      cb(new Error('no such packet'), client, packet)
    } else {
      cb(null, client, packet)
    }
  })
}

function augmentWithBrokerData (that, client, packet, cb) {
  var postkey = 'outgoing-id:' + client.id + ':' + packet.messageId
  that._getPipeline().getBuffer(postkey, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no suck packet')) }
    var decoded = msgpack.decode(buf)
    packet.brokerId = decoded.brokerId
    packet.brokerCounter = decoded.brokerCounter
    cb(null)
  })
}

RedisPersistence.prototype.outgoingUpdate = function (client, packet, cb) {
  var that = this
  if (packet.brokerId) {
    updateWithBrokerData(this, client, packet, cb)
  } else {
    augmentWithBrokerData(this, client, packet, function (err) {
      if (err) { return cb(err, client, packet) }

      updateWithBrokerData(that, client, packet, cb)
    })
  }
}

RedisPersistence.prototype.outgoingClearMessageId = function (client, packet, cb) {
  var that = this
  var key = 'outgoing-id:' + client.id + ':' + packet.messageId
  this._getPipeline().getBuffer(key, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no suck packet')) }

    var packet = msgpack.decode(buf)
    var prekey = 'outgoing:' + client.id + ':' + packet.brokerId + ':' + packet.brokerCounter
    var multi = that._db.multi()
    multi.del(key)
    multi.del(prekey)
    multi.exec(function (err) {
      cb(err, client)
    })
  })
}

function split (keys, enc, cb) {
  for (var i = 0, l = keys.length; i < l; i++) {
    this.push(keys[i])
  }
  cb()
}

RedisPersistence.prototype.outgoingStream = function (client) {
  return this._db.scanStream({
    match: 'outgoing:' + client.id + ':*',
    count: 16
  }).pipe(through.obj(split))
    .pipe(throughv.obj(this._decodeAndAugment))
}

RedisPersistence.prototype.incomingStorePacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  var newp = new Packet(packet)
  newp.messageId = packet.messageId
  this._getPipeline().set(key, msgpack.encode(newp), cb)
}

RedisPersistence.prototype.incomingGetPacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  this._getPipeline().getBuffer(key, function (err, buf) {
    if (err) { return cb(err) }
    if (!buf) { return cb(new Error('no such packet')) }
    cb(null, msgpack.decode(buf), client)
  })
}

RedisPersistence.prototype.incomingDelPacket = function (client, packet, cb) {
  var key = 'incoming:' + client.id + ':' + packet.messageId
  this._getPipeline().del(key, cb)
}

RedisPersistence.prototype.putWill = function (client, packet, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  packet.clientId = client.id
  packet.brokerId = this.broker.id
  this._getPipeline().setBuffer(key, msgpack.encode(packet), function (err) {
    cb(err, client)
  })
}

RedisPersistence.prototype.getWill = function (client, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  this._getPipeline().getBuffer(key, function (err, packet) {
    if (err) { return cb(err) }

    var result = null

    if (packet) {
      result = msgpack.decode(packet)
    }

    cb(null, result, client)
  })
}

RedisPersistence.prototype.delWill = function (client, cb) {
  var key = 'will:' + this.broker.id + ':' + client.id
  var result = null
  var pipeline = this._getPipeline()

  pipeline.getBuffer(key, function (err, packet) {
    if (err) { return cb(err) }

    if (packet) {
      result = msgpack.decode(packet)
    }
  })

  pipeline.del(key, function (err) {
    cb(err, result, client)
  })
}

RedisPersistence.prototype.streamWill = function (brokers) {
  return this._db.scanStream({
    match: 'will:*',
    count: 100
  })
  .pipe(through.obj(function (chunk, enc, cb) {
    for (var i = 0, l = chunk.length; i < l; i++) {
      if (!brokers || !brokers[chunk[i].split(':')[1]]) {
        this.push(chunk[i])
      }
    }
    cb()
  }))
  .pipe(throughv.obj(this._decodeAndAugment))
}

RedisPersistence.prototype.destroy = function (cb) {
  this._destroyed = true
  this._db.disconnect()
  this._sub.disconnect()
  if (cb) {
    cb(null)
  }
}

module.exports = RedisPersistence
<|endoftext|>


<commit_before>/**
 * peter-piper.js
 * ==============
 *
 * Count the number of times a capital `P` or lowercase `p` shows up in the
 * Peter Piper tongue twister.
 *
 * Hint
 * ----
 * Read the 'References' section in the README, which contains links to some
 * JavaScript methods and language features that might be helpful.
 */

var peterpiper = '';
peterpiper += "Peter Piper picked a peck of pickled peppers.";
peterpiper += "A peck of pickled peppers Peter Piper picked.";
peterpiper += "If Peter Piper picked a peck of pickled peppers,";
peterpiper += "Where's the peck of pickled peppers Peter Piper picked?";

var counter = 0;

// TODO: Count the number of times an uppercase P or lowercase p character
//       occurs in the `peterpiper` string.

console.log("There are " + counter + " P's in Peter Piper.");
<commit_msg>Complete implemention of peter-piper.js<commit_after>/**
 * peter-piper.js
 * ==============
 *
 * Count the number of times a capital `P` or lowercase `p` shows up in the
 * Peter Piper tongue twister.
 *
 * Hint
 * ----
 * Read the 'References' section in the README, which contains links to some
 * JavaScript methods and language features that might be helpful.
 */

var peterpiper = '';
peterpiper += "Peter Piper picked a peck of pickled peppers.";
peterpiper += "A peck of pickled peppers Peter Piper picked.";
peterpiper += "If Peter Piper picked a peck of pickled peppers,";
peterpiper += "Where's the peck of pickled peppers Peter Piper picked?";

var counter = 0;

// TODO: Count the number of times an uppercase P or lowercase p character
//       occurs in the `peterpiper` string.
for (var i = 0; i < peterpiper.length; i++) {

    if (peterpiper[ i ].toLowerCase() === 'p') {
        counter++
    }
}
console.log("There are " + counter + " P's in Peter Piper.");
<|endoftext|>


<commit_before>/**
    Framework for building object relational database apps
    Copyright (C) 2016  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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/>.
**/

(function (exports) {
  exports.execute = function (obj) {
    var afterCurrentUser, getEveryone,
      createEveryone, grantEveryoneGlobal, doneGrants, user,
      datasource = require("../server/datasource"),
      c = 0;

    afterCurrentUser = function (err, resp) {
      if (err) {
        obj.callback(err);
        return;
      }

      user = resp.rows[0].current_user;
      getEveryone();
    };

    // Create Everyone role
    getEveryone = function (err) {
      if (err) {
        obj.callback(err);
        return;
      }

      datasource.request({
        name: "Role",
        method: "GET",
        user: user,
        id: "everyone",
        client: obj.client,
        callback: createEveryone
      }, true);
    };

    createEveryone = function (err, resp) {
      if (err) {
        obj.callback(err);
        return;
      }

      if (!resp) {
        datasource.request({
          name: "Role",
          method: "POST",
          user: user,
          data: {
            id: "everyone",
            name: "Everyone",
            description: "All users",
            members: [
              {member: user}
            ]
          },
          client: obj.client,
          callback: grantEveryoneGlobal
        }, true);
        return;
      }

      // Done
      obj.callback(null, true);
    };

    grantEveryoneGlobal = function (err) {
      var req, reqRole, reqLog, reqForm, reqWidget;

      req = function () {
        return {
          method: "PUT",
          name: "saveAuthorization",
          user: user,
          data: {
            id: "role",
            role: "everyone",
            actions: {
              canCreate: true,
              canRead: true,
              canUpdate: true,
              canDelete: true
            }
          },
          client: obj.client,
          callback: doneGrants
        };
      };

      if (err) {
        obj.callback(err);
        return;
      }

      /* Grant everyone access to system objects */
      reqRole = req();
      datasource.request(reqRole);
      reqLog = req();
      reqLog.data.id = "log";
      datasource.request(reqLog);
      reqForm = req();
      reqForm.data.id = "form";
      datasource.request(reqForm);
      reqWidget = req();
      reqWidget.data.id = "relation_widget";
      datasource.request(reqWidget);
    };

    doneGrants = function (err) {
      if (err) {
        obj.callback(err);
        return;
      }

      c += 1;
      if (c < 4) { return; }

      obj.callback(null, true);
    };

    obj.client.query("SELECT CURRENT_USER", afterCurrentUser);
  };
}(exports));
<commit_msg>Let tables be seen<commit_after>/**
    Framework for building object relational database apps
    Copyright (C) 2016  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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/>.
**/

(function (exports) {
  exports.execute = function (obj) {
    var afterCurrentUser, getEveryone,
      createEveryone, grantEveryoneGlobal, doneGrants, user,
      datasource = require("../server/datasource"),
      c = 0;

    afterCurrentUser = function (err, resp) {
      if (err) {
        obj.callback(err);
        return;
      }

      user = resp.rows[0].current_user;
      getEveryone();
    };

    // Create Everyone role
    getEveryone = function (err) {
      if (err) {
        obj.callback(err);
        return;
      }

      datasource.request({
        name: "Role",
        method: "GET",
        user: user,
        id: "everyone",
        client: obj.client,
        callback: createEveryone
      }, true);
    };

    createEveryone = function (err, resp) {
      if (err) {
        obj.callback(err);
        return;
      }

      if (!resp) {
        datasource.request({
          name: "Role",
          method: "POST",
          user: user,
          data: {
            id: "everyone",
            name: "Everyone",
            description: "All users",
            members: [
              {member: user}
            ]
          },
          client: obj.client,
          callback: grantEveryoneGlobal
        }, true);
        return;
      }

      // Done
      obj.callback(null, true);
    };

    grantEveryoneGlobal = function (err) {
      var req, reqRole, reqLog, reqForm, reqWidget, reqTable;

      req = function () {
        return {
          method: "PUT",
          name: "saveAuthorization",
          user: user,
          data: {
            id: "role",
            role: "everyone",
            actions: {
              canCreate: true,
              canRead: true,
              canUpdate: true,
              canDelete: true
            }
          },
          client: obj.client,
          callback: doneGrants
        };
      };

      if (err) {
        obj.callback(err);
        return;
      }

      /* Grant everyone access to system objects */
      reqRole = req();
      datasource.request(reqRole);
      reqLog = req();
      reqLog.data.id = "log";
      datasource.request(reqLog);
      reqForm = req();
      reqForm.data.id = "form";
      datasource.request(reqForm);
      reqTable = req();
      reqTable.data.id = "table";
      datasource.request(reqTable);
      reqWidget = req();
      reqWidget.data.id = "relation_widget";
      datasource.request(reqWidget);
    };

    doneGrants = function (err) {
      if (err) {
        obj.callback(err);
        return;
      }

      c += 1;
      if (c < 5) { return; }

      obj.callback(null, true);
    };

    obj.client.query("SELECT CURRENT_USER", afterCurrentUser);
  };
}(exports));
<|endoftext|>


<commit_before>var $ = require('jquery');
var avalon = require('avalon');
require('mmState');
var toastr = require('/vendor/toastr');
var bootbox = require('bootbox.js/bootbox');

function getThemeColorFromCss(n) {
    var t = $("<\/span>").hide().appendTo("body"), i;
    return t.addClass(n),
    i = t.css("color"),
    t.remove(),
    i
}
function InitiateSideMenu() {
    $(".sidebar-toggler").on("click", function() {
        return $("#sidebar").toggleClass("hide"),
        $(".sidebar-toggler").toggleClass("active"),
        !1
    });
    var isMenuCompacted = $("#sidebar").hasClass("menu-compact");
    $("#sidebar-collapse").on("click", function() {
        $("#sidebar").is(":visible") || $("#sidebar").toggleClass("hide");
        $("#sidebar").toggleClass("menu-compact");
        $(".sidebar-collapse").toggleClass("active");
        isMenuCompacted = $("#sidebar").hasClass("menu-compact");
        isMenuCompacted && $(".open > .submenu").removeClass("open")
    });
    $(".sidebar-menu").on("click", function(e) {
        var $btnItem = $(e.target).closest("a"), eleTitle, r, f;
        if ($btnItem && $btnItem.length != 0) {
            if (!$btnItem.hasClass("menu-dropdown"))
                return isMenuCompacted && $btnItem.get(0).parentNode.parentNode == this && (eleTitle = $btnItem.find(".menu-text").get(0),
                e.target != eleTitle && !$.contains(eleTitle, e.target)) ? !1 : void 0;
            if (r = $btnItem.next().get(0),
            !$(r).is(":visible")) {
                if (f = $(r.parentNode).closest("ul"),
                isMenuCompacted && f.hasClass("sidebar-menu"))
                    return;
                f.find("> .open > .submenu").each(function() {
                    this == r || $(this.parentNode).hasClass("active") || $(this).slideUp(200).parent().removeClass("open")
                })
            }
            return isMenuCompacted && $(r.parentNode.parentNode).hasClass("sidebar-menu") ? !1 : ($(r).slideToggle(200).parent().toggleClass("open"),
            !1)
        }
    })
}
function InitiateWidgets() {
    $('.widget-buttons *[data-toggle="maximize"]').on("click", function(n) {
        n.preventDefault();
        var t = $(this).parents(".widget").eq(0)
          , i = $(this).find("i").eq(0)
          , r = "fa-compress"
          , u = "fa-expand";
        t.hasClass("maximized") ? (i && i.addClass(u).removeClass(r),
        t.removeClass("maximized"),
        t.find(".widget-body").css("height", "auto")) : (i && i.addClass(r).removeClass(u),
        t.addClass("maximized"),
        maximize(t))
    });
    $('.widget-buttons *[data-toggle="collapse"]').on("click", function(n) {
        n.preventDefault();
        var t = $(this).parents(".widget").eq(0)
          , r = t.find(".widget-body")
          , i = $(this).find("i")
          , u = "fa-plus"
          , f = "fa-minus"
          , e = 300;
        t.hasClass("collapsed") ? (i && i.addClass(f).removeClass(u),
        t.removeClass("collapsed"),
        r.slideUp(0, function() {
            r.slideDown(e)
        })) : (i && i.addClass(u).removeClass(f),
        r.slideUp(200, function() {
            t.addClass("collapsed")
        }))
    });
    $('.widget-buttons *[data-toggle="dispose"]').on("click", function(n) {
        n.preventDefault();
        var i = $(this)
          , t = i.parents(".widget").eq(0);
        t.hide(300, function() {
            t.remove()
        })
    })
}
function maximize(n) {
    if (n) {
        var t = $(window).height()
          , i = n.find(".widget-header").height();
        n.find(".widget-body").height(t - i)
    }
}
function scrollTo(n, t) {
    var i = n && n.size() > 0 ? n.offset().top : 0;
    jQuery("html,body").animate({
        scrollTop: i + (t ? t : 0)
    }, "slow")
}
function Notify(n, t, i, r, u, f) {
    toastr.options.positionClass = "toast-" + t;
    toastr.options.extendedTimeOut = 0;
    toastr.options.timeOut = i;
    toastr.options.closeButton = f;
    toastr.options.iconClass = u + " toast-" + r;
    toastr.custom(n)
}
function InitiateSettings() {
    readCookie("navbar-fixed-top") != null && readCookie("navbar-fixed-top") == "true" && ($("#checkbox_fixednavbar").prop("checked", !0),
    $(".navbar").addClass("navbar-fixed-top"));
    readCookie("sidebar-fixed") != null && readCookie("sidebar-fixed") == "true" && ($("#checkbox_fixedsidebar").prop("checked", !0),
    $(".page-sidebar").addClass("sidebar-fixed"));
    readCookie("breadcrumbs-fixed") != null && readCookie("breadcrumbs-fixed") == "true" && ($("#checkbox_fixedbreadcrumbs").prop("checked", !0),
    $(".page-breadcrumbs").addClass("breadcrumbs-fixed"));
    readCookie("page-header-fixed") != null && readCookie("page-header-fixed") == "true" && ($("#checkbox_fixedheader").prop("checked", !0),
    $(".page-header").addClass("page-header-fixed"));
    $("#checkbox_fixednavbar").change(function() {
        $(".navbar").toggleClass("navbar-fixed-top");
        $("#checkbox_fixedsidebar").is(":checked") && ($("#checkbox_fixedsidebar").prop("checked", !1),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixedbreadcrumbs").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedbreadcrumbs").prop("checked", !1),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedsidebar").change(function() {
        $(".page-sidebar").toggleClass("sidebar-fixed");
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        $("#checkbox_fixedbreadcrumbs").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedbreadcrumbs").prop("checked", !1),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedbreadcrumbs").change(function() {
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed");
        $("#checkbox_fixedsidebar").is(":checked") || ($("#checkbox_fixedsidebar").prop("checked", !0),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedheader").change(function() {
        $(".page-header").toggleClass("page-header-fixed");
        $("#checkbox_fixedbreadcrumbs").is(":checked") || ($("#checkbox_fixedbreadcrumbs").prop("checked", !0),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedsidebar").is(":checked") || ($("#checkbox_fixedsidebar").prop("checked", !0),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        setCookiesForFixedSettings()
    })
}
function setCookiesForFixedSettings() {
    createCookie("navbar-fixed-top", $("#checkbox_fixednavbar").is(":checked"), 100);
    createCookie("sidebar-fixed", $("#checkbox_fixedsidebar").is(":checked"), 100);
    createCookie("breadcrumbs-fixed", $("#checkbox_fixedbreadcrumbs").is(":checked"), 100);
    createCookie("page-header-fixed", $("#checkbox_fixedheader").is(":checked"), 100)
}
function getcolor(n) {
    switch (n) {
    case "themeprimary":
        return themeprimary;
    case "themesecondary":
        return themesecondary;
    case "themethirdcolor":
        return themethirdcolor;
    case "themefourthcolor":
        return themefourthcolor;
    case "themefifthcolor":
        return themefifthcolor;
    default:
        return n
    }
}
function switchClasses(n, t) {
    var u = document.getElementsByClassName(n), r;
    for (i = u.length - 1; i >= 0; i--)
        hasClass(u[i], "dropdown-menu") || (addClass(u[i], n + "-temp"),
        removeClass(u[i], n));
    for (r = document.getElementsByClassName(t),
    i = r.length - 1; i >= 0; i--)
        hasClass(r[i], "dropdown-menu") || (addClass(r[i], n),
        removeClass(r[i], t));
    for (tempClasses = document.getElementsByClassName(n + "-temp"),
    i = tempClasses.length - 1; i >= 0; i--)
        hasClass(tempClasses[i], "dropdown-menu") || (addClass(tempClasses[i], t),
        removeClass(tempClasses[i], n + "-temp"))
}
function addClass(n, t) {
    var i = n.className;
    i && (i += " ");
    n.className = i + t
}
function removeClass(n, t) {
    var i = " " + n.className + " ";
    n.className = i.replace(" " + t, "").replace(/^\s+/g, "").replace(/\s+$/g, "")
}
function hasClass(n, t) {
    var i = " " + n.className + " "
      , r = " " + t + " ";
    return i.indexOf(r) != -1
}
var themeprimary = getThemeColorFromCss("themeprimary"), themesecondary = getThemeColorFromCss("themesecondary"), themethirdcolor = getThemeColorFromCss("themethirdcolor"), themefourthcolor = getThemeColorFromCss("themefourthcolor"), themefifthcolor = getThemeColorFromCss("themefifthcolor"), rtlchanger, popovers, hoverpopovers;

// 覆写require.async,改写为promise
var require_async = require.async;
window.require_async = require_async;
require.async = function(n, part, onerror) {
    if (typeof part == 'function') {
        return require_async.call(require, n, part, onerror);
    } else {
        return function () {
            return new Promise(function(rs, rj) {
                require_async(n, function(m) {
                    rs(part ? m[part] : m);
                }, function() {
                    rj();
                });
            });
        }
    }
}

// 实现bootbox.stateDialog
bootbox.stateDialog = function (options) {
    var tempCallback;
    if (options.buttons) {
        for (var i in options.buttons) {
            var btn = options.buttons[i];
            if (options.buttons.hasOwnProperty(i)) {
                btn.tempCallback = btn.callback;
                btn.callback = (function (btn) {
                    return function () {
                        var skip;
                        btn.tempCallback && (skip = btn.tempCallback(function () {
                            avalon.router.go(options.parentStateName);
                            bootbox.hideAll();
                        }) !== false);
                        !skip && avalon.router.go(options.parentStateName, {}, { reload: true });
                        return skip;
                    }
                }(btn));
            }
        }
    }
    if (options.onEscape || true) {
        tempCallback = options.onEscape;
        options.onEscape = function () {
            tempCallback && tempCallback();
            //avalon.router.go(options.parentStateName, {}, { reload: true });
        }
    }
    var el_dialog = bootbox.dialog(options);
    avalon.scan(el_dialog[0]);
    return el_dialog;
}

exports.init = function () {
    $(window).load(function() {
        setTimeout(function() {
            $(".loading-container").addClass("loading-inactive")
        }, 0)
    });
    $("#fullscreen-toggler").on("click", function() {
        var n = document.documentElement;
        $("body").hasClass("full-screen") ? ($("body").removeClass("full-screen"),
        $("#fullscreen-toggler").removeClass("active"),
        document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen && document.webkitExitFullscreen()) : ($("body").addClass("full-screen"),
        $("#fullscreen-toggler").addClass("active"),
        n.requestFullscreen ? n.requestFullscreen() : n.mozRequestFullScreen ? n.mozRequestFullScreen() : n.webkitRequestFullscreen ? n.webkitRequestFullscreen() : n.msRequestFullscreen && n.msRequestFullscreen())
    });
    popovers = $("[data-toggle=popover]");
    $.each(popovers, function() {
        $(this).popover({
            html: !0,
            template: '

<\/div>
Popover right<\/h3>
<\/div><\/div>'
        })
    });
    hoverpopovers = $("[data-toggle=popover-hover]");
    $.each(hoverpopovers, function() {
        $(this).popover({
            html: !0,
            template: '

<\/div>
Popover right<\/h3>
<\/div><\/div>',
            trigger: "hover"
        })
    });
    $("[data-toggle=tooltip]").tooltip({
        html: !0
    });
    InitiateWidgets();
}
exports.initHeader = function () {
    $("#skin-changer li a").click(function() {
        createCookie("current-skin", $(this).attr("rel"), 10);
        window.location.reload()
    });
    $("#btn-setting").on("click", function() {
        $(".navbar-account").toggleClass("setting-open")
    });
    InitiateSettings();
}
exports.initSidebar = function () {
    rtlchanger = document.getElementById("rtl-changer");
    location.pathname != "/index-rtl-fa.html" && location.pathname != "/index-rtl-ar.html" && (readCookie("rtl-support") ? (switchClasses("pull-right", "pull-left"),
    switchClasses("databox-right", "databox-left"),
    switchClasses("item-right", "item-left"),
    $(".navbar-brand small img").attr("src", "/static/beyond/img/logo-rtl.png"),
    rtlchanger != null && (document.getElementById("rtl-changer").checked = !0)) : rtlchanger != null && (rtlchanger.checked = !1),
    rtlchanger != null && (rtlchanger.onchange = function() {
        this.checked ? createCookie("rtl-support", "true", 10) : eraseCookie("rtl-support");
        setTimeout(function() {
            window.location.reload()
        }, 600)
    }
    ));
    InitiateSideMenu();
}

exports.showLoading = function () {
    $(".loading-container").removeClass("loading-inactive");
}

exports.hideLoading = function () {
    $(".loading-container").addClass("loading-inactive");
}

exports.Notify = Notify;<commit_msg>种子：处理异步加载js模块的错误情况<commit_after>var $ = require('jquery');
var avalon = require('avalon');
require('mmState');
var toastr = require('/vendor/toastr');
var bootbox = require('bootbox.js/bootbox');

function getThemeColorFromCss(n) {
    var t = $("<\/span>").hide().appendTo("body"), i;
    return t.addClass(n),
    i = t.css("color"),
    t.remove(),
    i
}
function InitiateSideMenu() {
    $(".sidebar-toggler").on("click", function() {
        return $("#sidebar").toggleClass("hide"),
        $(".sidebar-toggler").toggleClass("active"),
        !1
    });
    var isMenuCompacted = $("#sidebar").hasClass("menu-compact");
    $("#sidebar-collapse").on("click", function() {
        $("#sidebar").is(":visible") || $("#sidebar").toggleClass("hide");
        $("#sidebar").toggleClass("menu-compact");
        $(".sidebar-collapse").toggleClass("active");
        isMenuCompacted = $("#sidebar").hasClass("menu-compact");
        isMenuCompacted && $(".open > .submenu").removeClass("open")
    });
    $(".sidebar-menu").on("click", function(e) {
        var $btnItem = $(e.target).closest("a"), eleTitle, r, f;
        if ($btnItem && $btnItem.length != 0) {
            if (!$btnItem.hasClass("menu-dropdown"))
                return isMenuCompacted && $btnItem.get(0).parentNode.parentNode == this && (eleTitle = $btnItem.find(".menu-text").get(0),
                e.target != eleTitle && !$.contains(eleTitle, e.target)) ? !1 : void 0;
            if (r = $btnItem.next().get(0),
            !$(r).is(":visible")) {
                if (f = $(r.parentNode).closest("ul"),
                isMenuCompacted && f.hasClass("sidebar-menu"))
                    return;
                f.find("> .open > .submenu").each(function() {
                    this == r || $(this.parentNode).hasClass("active") || $(this).slideUp(200).parent().removeClass("open")
                })
            }
            return isMenuCompacted && $(r.parentNode.parentNode).hasClass("sidebar-menu") ? !1 : ($(r).slideToggle(200).parent().toggleClass("open"),
            !1)
        }
    })
}
function InitiateWidgets() {
    $('.widget-buttons *[data-toggle="maximize"]').on("click", function(n) {
        n.preventDefault();
        var t = $(this).parents(".widget").eq(0)
          , i = $(this).find("i").eq(0)
          , r = "fa-compress"
          , u = "fa-expand";
        t.hasClass("maximized") ? (i && i.addClass(u).removeClass(r),
        t.removeClass("maximized"),
        t.find(".widget-body").css("height", "auto")) : (i && i.addClass(r).removeClass(u),
        t.addClass("maximized"),
        maximize(t))
    });
    $('.widget-buttons *[data-toggle="collapse"]').on("click", function(n) {
        n.preventDefault();
        var t = $(this).parents(".widget").eq(0)
          , r = t.find(".widget-body")
          , i = $(this).find("i")
          , u = "fa-plus"
          , f = "fa-minus"
          , e = 300;
        t.hasClass("collapsed") ? (i && i.addClass(f).removeClass(u),
        t.removeClass("collapsed"),
        r.slideUp(0, function() {
            r.slideDown(e)
        })) : (i && i.addClass(u).removeClass(f),
        r.slideUp(200, function() {
            t.addClass("collapsed")
        }))
    });
    $('.widget-buttons *[data-toggle="dispose"]').on("click", function(n) {
        n.preventDefault();
        var i = $(this)
          , t = i.parents(".widget").eq(0);
        t.hide(300, function() {
            t.remove()
        })
    })
}
function maximize(n) {
    if (n) {
        var t = $(window).height()
          , i = n.find(".widget-header").height();
        n.find(".widget-body").height(t - i)
    }
}
function scrollTo(n, t) {
    var i = n && n.size() > 0 ? n.offset().top : 0;
    jQuery("html,body").animate({
        scrollTop: i + (t ? t : 0)
    }, "slow")
}
function Notify(n, t, i, r, u, f) {
    toastr.options.positionClass = "toast-" + t;
    toastr.options.extendedTimeOut = 0;
    toastr.options.timeOut = i;
    toastr.options.closeButton = f;
    toastr.options.iconClass = u + " toast-" + r;
    toastr.custom(n)
}
function InitiateSettings() {
    readCookie("navbar-fixed-top") != null && readCookie("navbar-fixed-top") == "true" && ($("#checkbox_fixednavbar").prop("checked", !0),
    $(".navbar").addClass("navbar-fixed-top"));
    readCookie("sidebar-fixed") != null && readCookie("sidebar-fixed") == "true" && ($("#checkbox_fixedsidebar").prop("checked", !0),
    $(".page-sidebar").addClass("sidebar-fixed"));
    readCookie("breadcrumbs-fixed") != null && readCookie("breadcrumbs-fixed") == "true" && ($("#checkbox_fixedbreadcrumbs").prop("checked", !0),
    $(".page-breadcrumbs").addClass("breadcrumbs-fixed"));
    readCookie("page-header-fixed") != null && readCookie("page-header-fixed") == "true" && ($("#checkbox_fixedheader").prop("checked", !0),
    $(".page-header").addClass("page-header-fixed"));
    $("#checkbox_fixednavbar").change(function() {
        $(".navbar").toggleClass("navbar-fixed-top");
        $("#checkbox_fixedsidebar").is(":checked") && ($("#checkbox_fixedsidebar").prop("checked", !1),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixedbreadcrumbs").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedbreadcrumbs").prop("checked", !1),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedsidebar").change(function() {
        $(".page-sidebar").toggleClass("sidebar-fixed");
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        $("#checkbox_fixedbreadcrumbs").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedbreadcrumbs").prop("checked", !1),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedbreadcrumbs").change(function() {
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed");
        $("#checkbox_fixedsidebar").is(":checked") || ($("#checkbox_fixedsidebar").prop("checked", !0),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        $("#checkbox_fixedheader").is(":checked") && !$(this).is(":checked") && ($("#checkbox_fixedheader").prop("checked", !1),
        $(".page-header").toggleClass("page-header-fixed"));
        setCookiesForFixedSettings()
    });
    $("#checkbox_fixedheader").change(function() {
        $(".page-header").toggleClass("page-header-fixed");
        $("#checkbox_fixedbreadcrumbs").is(":checked") || ($("#checkbox_fixedbreadcrumbs").prop("checked", !0),
        $(".page-breadcrumbs").toggleClass("breadcrumbs-fixed"));
        $("#checkbox_fixedsidebar").is(":checked") || ($("#checkbox_fixedsidebar").prop("checked", !0),
        $(".page-sidebar").toggleClass("sidebar-fixed"));
        $("#checkbox_fixednavbar").is(":checked") || ($("#checkbox_fixednavbar").prop("checked", !0),
        $(".navbar").toggleClass("navbar-fixed-top"));
        setCookiesForFixedSettings()
    })
}
function setCookiesForFixedSettings() {
    createCookie("navbar-fixed-top", $("#checkbox_fixednavbar").is(":checked"), 100);
    createCookie("sidebar-fixed", $("#checkbox_fixedsidebar").is(":checked"), 100);
    createCookie("breadcrumbs-fixed", $("#checkbox_fixedbreadcrumbs").is(":checked"), 100);
    createCookie("page-header-fixed", $("#checkbox_fixedheader").is(":checked"), 100)
}
function getcolor(n) {
    switch (n) {
    case "themeprimary":
        return themeprimary;
    case "themesecondary":
        return themesecondary;
    case "themethirdcolor":
        return themethirdcolor;
    case "themefourthcolor":
        return themefourthcolor;
    case "themefifthcolor":
        return themefifthcolor;
    default:
        return n
    }
}
function switchClasses(n, t) {
    var u = document.getElementsByClassName(n), r;
    for (i = u.length - 1; i >= 0; i--)
        hasClass(u[i], "dropdown-menu") || (addClass(u[i], n + "-temp"),
        removeClass(u[i], n));
    for (r = document.getElementsByClassName(t),
    i = r.length - 1; i >= 0; i--)
        hasClass(r[i], "dropdown-menu") || (addClass(r[i], n),
        removeClass(r[i], t));
    for (tempClasses = document.getElementsByClassName(n + "-temp"),
    i = tempClasses.length - 1; i >= 0; i--)
        hasClass(tempClasses[i], "dropdown-menu") || (addClass(tempClasses[i], t),
        removeClass(tempClasses[i], n + "-temp"))
}
function addClass(n, t) {
    var i = n.className;
    i && (i += " ");
    n.className = i + t
}
function removeClass(n, t) {
    var i = " " + n.className + " ";
    n.className = i.replace(" " + t, "").replace(/^\s+/g, "").replace(/\s+$/g, "")
}
function hasClass(n, t) {
    var i = " " + n.className + " "
      , r = " " + t + " ";
    return i.indexOf(r) != -1
}
var themeprimary = getThemeColorFromCss("themeprimary"), themesecondary = getThemeColorFromCss("themesecondary"), themethirdcolor = getThemeColorFromCss("themethirdcolor"), themefourthcolor = getThemeColorFromCss("themefourthcolor"), themefifthcolor = getThemeColorFromCss("themefifthcolor"), rtlchanger, popovers, hoverpopovers;

// 覆写require.async,改写为promise
var require_async = require.async;
window.require_async = require_async;
require.async = function(n, part, onerror) {
    if (typeof part == 'function') {
        return require_async.call(require, n, part, onerror);
    } else {
        return function () {
            return new Promise(function(rs, rj) {
                require_async(n, function(m) {
                    rs(part ? m[part] : m);
                }, rj);
            });
        }
    }
}

// 实现bootbox.stateDialog
bootbox.stateDialog = function (options) {
    var tempCallback;
    if (options.buttons) {
        for (var i in options.buttons) {
            var btn = options.buttons[i];
            if (options.buttons.hasOwnProperty(i)) {
                btn.tempCallback = btn.callback;
                btn.callback = (function (btn) {
                    return function () {
                        var skip;
                        btn.tempCallback && (skip = btn.tempCallback(function () {
                            avalon.router.go(options.parentStateName);
                            bootbox.hideAll();
                        }) !== false);
                        !skip && avalon.router.go(options.parentStateName, {}, { reload: true });
                        return skip;
                    }
                }(btn));
            }
        }
    }
    if (options.onEscape || true) {
        tempCallback = options.onEscape;
        options.onEscape = function () {
            tempCallback && tempCallback();
            //avalon.router.go(options.parentStateName, {}, { reload: true });
        }
    }
    var el_dialog = bootbox.dialog(options);
    avalon.scan(el_dialog[0]);
    return el_dialog;
}

exports.init = function () {
    $(window).load(function() {
        setTimeout(function() {
            $(".loading-container").addClass("loading-inactive")
        }, 0)
    });
    $("#fullscreen-toggler").on("click", function() {
        var n = document.documentElement;
        $("body").hasClass("full-screen") ? ($("body").removeClass("full-screen"),
        $("#fullscreen-toggler").removeClass("active"),
        document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen && document.webkitExitFullscreen()) : ($("body").addClass("full-screen"),
        $("#fullscreen-toggler").addClass("active"),
        n.requestFullscreen ? n.requestFullscreen() : n.mozRequestFullScreen ? n.mozRequestFullScreen() : n.webkitRequestFullscreen ? n.webkitRequestFullscreen() : n.msRequestFullscreen && n.msRequestFullscreen())
    });
    popovers = $("[data-toggle=popover]");
    $.each(popovers, function() {
        $(this).popover({
            html: !0,
            template: '

<\/div>
Popover right<\/h3>
<\/div><\/div>'
        })
    });
    hoverpopovers = $("[data-toggle=popover-hover]");
    $.each(hoverpopovers, function() {
        $(this).popover({
            html: !0,
            template: '

<\/div>
Popover right<\/h3>
<\/div><\/div>',
            trigger: "hover"
        })
    });
    $("[data-toggle=tooltip]").tooltip({
        html: !0
    });
    InitiateWidgets();
}
exports.initHeader = function () {
    $("#skin-changer li a").click(function() {
        createCookie("current-skin", $(this).attr("rel"), 10);
        window.location.reload()
    });
    $("#btn-setting").on("click", function() {
        $(".navbar-account").toggleClass("setting-open")
    });
    InitiateSettings();
}
exports.initSidebar = function () {
    rtlchanger = document.getElementById("rtl-changer");
    location.pathname != "/index-rtl-fa.html" && location.pathname != "/index-rtl-ar.html" && (readCookie("rtl-support") ? (switchClasses("pull-right", "pull-left"),
    switchClasses("databox-right", "databox-left"),
    switchClasses("item-right", "item-left"),
    $(".navbar-brand small img").attr("src", "/static/beyond/img/logo-rtl.png"),
    rtlchanger != null && (document.getElementById("rtl-changer").checked = !0)) : rtlchanger != null && (rtlchanger.checked = !1),
    rtlchanger != null && (rtlchanger.onchange = function() {
        this.checked ? createCookie("rtl-support", "true", 10) : eraseCookie("rtl-support");
        setTimeout(function() {
            window.location.reload()
        }, 600)
    }
    ));
    InitiateSideMenu();
}

exports.showLoading = function () {
    $(".loading-container").removeClass("loading-inactive");
}

exports.hideLoading = function () {
    $(".loading-container").addClass("loading-inactive");
}

exports.Notify = Notify;<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define(function(require, exports/*, module*/) {

"use strict";

// Dependencies
const React = require("react");

// Firebug SDK
const { Reps } = require("reps/reps");
const { Str } = require("reps/core/string");
const { TreeView } = require("reps/tree-view");
const { createFactories } = require("reps/rep-utils");

// WebSockets Monitor
const { selectFrame } = require("../actions/selection");
const { getOpCodeLabel } = require("./frame-utils");
const { NoServiceWarning } = createFactories(require("./no-service-warning"));

// Shortcuts
const { div, span } = React.DOM;

/**
 * @template This template represents a list of frames displayed
 * inside the frame bubble content.
 */
var FrameList = React.createClass({
/** @lends FrameList */

  displayName: "FrameList",

  getInitialState: function() {
    return { data: [] };
  },

  componentDidUpdate: function() {
    var bubble = document.querySelector(".frameBubble.selected");
    if (bubble) {
      this.ensureVisible(bubble);
    }
  },

  ensureVisible: function(bubble) {
    var content = document.querySelector(".mainPanelContent");

    if (bubble.offsetTop < content.scrollTop) {
      content.scrollTop = bubble.offsetTop - 45; // minus padding
    }

    if (bubble.offsetTop + bubble.offsetHeight > content.scrollTop + content.clientHeight) {
      content.scrollTop = bubble.offsetTop + bubble.offsetHeight - content.clientHeight;
    }
  },

  render: function() {
    var { frames, summary, filter } = this.props.frames;
    frames = filter.frames || frames;
    summary = filter.summary || summary;

    var output = [];

    // If the underlying nsIWebSocketEventService service isn't
    // available in the platform display a warning.
    if (!this.props.wsServiceAvailable) {
      output.push(NoServiceWarning({}));
    }

    // Render number of removed frames from the list if any.
    var removedFrames = summary.frameCount - frames.length;
    if (removedFrames > 0) {
      output.push(FrameLimit({
        key: "frame-limit",
        removedFrames: removedFrames
      }));
    }

    // Render all frames.
    for (var i in frames) {
      var frame = frames[i];
      output.push(this.getFrameTag(frame)({
        key: "frame-" + frame.id,
        frame: frame,
        selection: this.props.selection,
        dispatch: this.props.dispatch
      }));
    }

    // Render summary at the end (if there are any frames displayed).
    if (frames.length > 0) {
      output.push(FrameSummary({
        key: "frame-summary",
        summary: summary
      }));
    }

    return (
      div({className: "frameList"},
        div({}, output)
      )
    );
  },

  getFrameTag: function(frame) {
    switch (frame.type) {
    case "event":
      return EventBubble;
    case "frame":
      return FrameBubble;
    }
  }
});

/**
 * This template is responsible for rendering a frame with
 * related information. It looks like a chat message
 * bubble in standard chat UI applications.
 */
var FrameBubble = React.createFactory(React.createClass({
/** @lends FrameBubble */

  displayName: "FrameBubble",

  /**
   * Frames need to be re-rendered only if the selection changes.
   * This is an optimization that makes the list rendering a lot faster.
   */
  shouldComponentUpdate: function(nextProps, nextState) {
    return this.props.frame == nextProps.selection ||
      this.props.frame == this.props.selection;
  },

  render: function() {
    var frame = this.props.frame;
    var data = frame.data;

    var type = frame.sent ? "send" : "receive";
    var size = Str.formatSize(data.payload.length);
    var payload = Str.cropString(data.payload, 50);
    var time = new Date(data.timeStamp / 1000);
    var timeText = time.getHours() + ":" + time.getMinutes() +
      ":" + time.getSeconds() + "." + time.getMilliseconds();

    // Error frames have its own styling
    var classNames = ["frameBubble", type];
    if (frame.error) {
      classNames.push("error");
    }

    // Selected frames are highlighted
    if (this.props.selection == frame) {
      classNames.push("selected");
    }

    // Render inline frame preview. There is just one preview displayed
    var preview;

    if (!preview && frame.socketIo) {
      preview = TreeView({
        key: "preview-socketio",
        data: {"Socket IO": frame.socketIo},
        mode: "tiny"
      });
    }

    if (!preview && frame.sockJs) {
      preview = TreeView({
        key: "preview-sockjs",
        data: {"SockJS": frame.sockJs},
        mode: "tiny"
      });
    }

    if (!preview && frame.json) {
      preview = TreeView({
        key: "preview-json",
        data: {"JSON": frame.json},
        mode: "tiny"
      });
    }

    var label = (type == "send") ?
      Locale.$STR("websocketmonitor.label.sent") :
      Locale.$STR("websocketmonitor.label.received");

    return (
      div({className: classNames.join(" "), onClick: this.onClick},
        div({className: "frameBox"},
          div({className: "frameContent"},
            div({className: "body"},
              span({className: "text"}, label),
              span({className: "type"}, getOpCodeLabel(frame)),
              div({className: "payload"},
                Str.cropString(data.payload)
              ),
              div({className: "preview"},
                preview
              ),
              div({},
                span({className: "info"}, timeText + ", " + size)
              )
            ),
            div({className: "boxArrow"})
          )
        )
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    var target = event.target;

    event.stopPropagation();
    event.preventDefault();

    // If a 'memberLabel' is clicked inside the inline preview
    // tree, let's process it by the tree, so expansion and
    // collapsing works. Otherwise just select the frame.
    if (!target.classList.contains("memberLabel")) {
      if (this.props.frame != this.props.selection) {
        this.props.dispatch(selectFrame(this.props.frame));
      }
    }
  },
}));

/**
 * Template for WS events (connect and disconnect) displayed in the
 * frame list (list view)
 */
var EventBubble = React.createFactory(React.createClass({
/** @lends FrameBubble */

  displayName: "FrameBubble",

  /**
   * Frames need to be re-rendered only if the selection changes.
   * This is an optimization that makes the list rendering a lot faster.
   */
  shouldComponentUpdate: function(nextProps, nextState) {
    return this.props.frame == nextProps.selection ||
      this.props.frame == this.props.selection;
  },

  // Event Handlers

  onClick: function(event) {
    var target = event.target;

    event.stopPropagation();
    event.preventDefault();

    // If a 'memberLabel' is clicked inside the inline preview
    // tree, let's process it by the tree, so expansion and
    // collapsing works. Otherwise just select the frame.
    if (!target.classList.contains("memberLabel")) {
      if (this.props.frame != this.props.selection) {
        this.props.dispatch(selectFrame(this.props.frame));
      }
    }
  },

  render: function() {
    var frame = this.props.frame;

    // Frame classes
    var classNames = ["frameBubble", "eventBubble", frame.type];
    if (this.props.selection == frame) {
      classNames.push("selected");
    }

    var label = frame.uri ?
      Locale.$STR("websocketmonitor.event.connected") :
      Locale.$STR("websocketmonitor.event.disconnected");

    var uri = frame.uri ? frame.uri :
      Locale.$STR("websocketmonitor.event.code") + " " + frame.code;

    var socketIdLabel = Locale.$STR("websocketmonitor.SocketID") +
      ": " + frame.webSocketSerialID;

    return (
      div({className: classNames.join(" "), onClick: this.onClick},
        div({className: "frameBox"},
          div({className: "frameContent"},
            div({className: "body"},
              div({className: "text"}, label),
              div({className: "uri"}, uri),
              div({className: "socketId"}, socketIdLabel)
            )
          )
        )
      )
    );
  }
}));

/**
 * @template This template is responsible for rendering a message
 * at the top of the frame list that informs the user about reaching
 * the maximum limit of displayed frames. The message also displays
 * number of frames removed from the list.
 */
var FrameLimit = React.createFactory(React.createClass({
/** @lends FrameLimit */

  displayName: "FrameLimit",

  render: function() {
    var { removedFrames } = this.props;

    // Render summary info
    return (
      div({className: "frameLimit"},
        span({className: "text"},
          Locale.$STRP("websocketmonitor.limit.removedFrames", [removedFrames])
        )
      )
    );
  }
}));

/**
 * @template This template is responsible for rendering frame summary
 * information. It displays number of sent and received packets
 * and total amount of sent and received data.
 */
var FrameSummary = React.createFactory(React.createClass({
/** @lends FrameSummary */

  displayName: "FrameSummary",

  render: function() {
    var { summary } = this.props;

    return (
      div({className: "frameSummary"},
        div({className: "text"},
          Locale.$STRP("websocketmonitor.summary.frameCount", [summary.frameCount])
        ),
        div({className: "separator"}),
        div({className: "text"},
          Str.formatSize(summary.totalSize)
        ),
        div({className: "separator"}),
        div({className: "time"},
          Str.formatTime((summary.endTime - summary.startTime) / 1000)
        )
      )
    );
  }
}));

// Exports from this module
exports.FrameList = FrameList;
});
<commit_msg>Also only show relevant data in chat view<commit_after>/* See license.txt for terms of usage */

define(function(require, exports/*, module*/) {

"use strict";

// Dependencies
const React = require("react");

// Firebug SDK
const { Reps } = require("reps/reps");
const { Str } = require("reps/core/string");
const { TreeView } = require("reps/tree-view");
const { createFactories } = require("reps/rep-utils");

// WebSockets Monitor
const { selectFrame } = require("../actions/selection");
const { getOpCodeLabel } = require("./frame-utils");
const { NoServiceWarning } = createFactories(require("./no-service-warning"));

// Shortcuts
const { div, span } = React.DOM;

/**
 * @template This template represents a list of frames displayed
 * inside the frame bubble content.
 */
var FrameList = React.createClass({
/** @lends FrameList */

  displayName: "FrameList",

  getInitialState: function() {
    return { data: [] };
  },

  componentDidUpdate: function() {
    var bubble = document.querySelector(".frameBubble.selected");
    if (bubble) {
      this.ensureVisible(bubble);
    }
  },

  ensureVisible: function(bubble) {
    var content = document.querySelector(".mainPanelContent");

    if (bubble.offsetTop < content.scrollTop) {
      content.scrollTop = bubble.offsetTop - 45; // minus padding
    }

    if (bubble.offsetTop + bubble.offsetHeight > content.scrollTop + content.clientHeight) {
      content.scrollTop = bubble.offsetTop + bubble.offsetHeight - content.clientHeight;
    }
  },

  render: function() {
    var { frames, summary, filter } = this.props.frames;
    frames = filter.frames || frames;
    summary = filter.summary || summary;

    var output = [];

    // If the underlying nsIWebSocketEventService service isn't
    // available in the platform display a warning.
    if (!this.props.wsServiceAvailable) {
      output.push(NoServiceWarning({}));
    }

    // Render number of removed frames from the list if any.
    var removedFrames = summary.frameCount - frames.length;
    if (removedFrames > 0) {
      output.push(FrameLimit({
        key: "frame-limit",
        removedFrames: removedFrames
      }));
    }

    // Render all frames.
    for (var i in frames) {
      var frame = frames[i];
      output.push(this.getFrameTag(frame)({
        key: "frame-" + frame.id,
        frame: frame,
        selection: this.props.selection,
        dispatch: this.props.dispatch
      }));
    }

    // Render summary at the end (if there are any frames displayed).
    if (frames.length > 0) {
      output.push(FrameSummary({
        key: "frame-summary",
        summary: summary
      }));
    }

    return (
      div({className: "frameList"},
        div({}, output)
      )
    );
  },

  getFrameTag: function(frame) {
    switch (frame.type) {
    case "event":
      return EventBubble;
    case "frame":
      return FrameBubble;
    }
  }
});

/**
 * This template is responsible for rendering a frame with
 * related information. It looks like a chat message
 * bubble in standard chat UI applications.
 */
var FrameBubble = React.createFactory(React.createClass({
/** @lends FrameBubble */

  displayName: "FrameBubble",

  /**
   * Frames need to be re-rendered only if the selection changes.
   * This is an optimization that makes the list rendering a lot faster.
   */
  shouldComponentUpdate: function(nextProps, nextState) {
    return this.props.frame == nextProps.selection ||
      this.props.frame == this.props.selection;
  },

  render: function() {
    var frame = this.props.frame;
    var data = frame.data;

    var type = frame.sent ? "send" : "receive";
    var size = Str.formatSize(data.payload.length);
    var payload = Str.cropString(data.payload, 50);
    var time = new Date(data.timeStamp / 1000);
    var timeText = time.getHours() + ":" + time.getMinutes() +
      ":" + time.getSeconds() + "." + time.getMilliseconds();

    // Error frames have its own styling
    var classNames = ["frameBubble", type];
    if (frame.error) {
      classNames.push("error");
    }

    // Selected frames are highlighted
    if (this.props.selection == frame) {
      classNames.push("selected");
    }

    // Render inline frame preview. There is just one preview displayed
    var preview;

    if (!preview && frame.socketIo) {
      preview = TreeView({
        key: "preview-socketio",
        // We only show the data that is deemed interesting for the user in the
        // inline previews, not the socketIO metadata
        data: {"Socket IO": frame.socketIo.data},
        mode: "tiny"
      });
    }

    if (!preview && frame.sockJs) {
      preview = TreeView({
        key: "preview-sockjs",
        data: {"SockJS": frame.sockJs},
        mode: "tiny"
      });
    }

    if (!preview && frame.json) {
      preview = TreeView({
        key: "preview-json",
        data: {"JSON": frame.json},
        mode: "tiny"
      });
    }

    var label = (type == "send") ?
      Locale.$STR("websocketmonitor.label.sent") :
      Locale.$STR("websocketmonitor.label.received");

    return (
      div({className: classNames.join(" "), onClick: this.onClick},
        div({className: "frameBox"},
          div({className: "frameContent"},
            div({className: "body"},
              span({className: "text"}, label),
              span({className: "type"}, getOpCodeLabel(frame)),
              div({className: "payload"},
                Str.cropString(data.payload)
              ),
              div({className: "preview"},
                preview
              ),
              div({},
                span({className: "info"}, timeText + ", " + size)
              )
            ),
            div({className: "boxArrow"})
          )
        )
      )
    );
  },

  // Event Handlers

  onClick: function(event) {
    var target = event.target;

    event.stopPropagation();
    event.preventDefault();

    // If a 'memberLabel' is clicked inside the inline preview
    // tree, let's process it by the tree, so expansion and
    // collapsing works. Otherwise just select the frame.
    if (!target.classList.contains("memberLabel")) {
      if (this.props.frame != this.props.selection) {
        this.props.dispatch(selectFrame(this.props.frame));
      }
    }
  },
}));

/**
 * Template for WS events (connect and disconnect) displayed in the
 * frame list (list view)
 */
var EventBubble = React.createFactory(React.createClass({
/** @lends FrameBubble */

  displayName: "FrameBubble",

  /**
   * Frames need to be re-rendered only if the selection changes.
   * This is an optimization that makes the list rendering a lot faster.
   */
  shouldComponentUpdate: function(nextProps, nextState) {
    return this.props.frame == nextProps.selection ||
      this.props.frame == this.props.selection;
  },

  // Event Handlers

  onClick: function(event) {
    var target = event.target;

    event.stopPropagation();
    event.preventDefault();

    // If a 'memberLabel' is clicked inside the inline preview
    // tree, let's process it by the tree, so expansion and
    // collapsing works. Otherwise just select the frame.
    if (!target.classList.contains("memberLabel")) {
      if (this.props.frame != this.props.selection) {
        this.props.dispatch(selectFrame(this.props.frame));
      }
    }
  },

  render: function() {
    var frame = this.props.frame;

    // Frame classes
    var classNames = ["frameBubble", "eventBubble", frame.type];
    if (this.props.selection == frame) {
      classNames.push("selected");
    }

    var label = frame.uri ?
      Locale.$STR("websocketmonitor.event.connected") :
      Locale.$STR("websocketmonitor.event.disconnected");

    var uri = frame.uri ? frame.uri :
      Locale.$STR("websocketmonitor.event.code") + " " + frame.code;

    var socketIdLabel = Locale.$STR("websocketmonitor.SocketID") +
      ": " + frame.webSocketSerialID;

    return (
      div({className: classNames.join(" "), onClick: this.onClick},
        div({className: "frameBox"},
          div({className: "frameContent"},
            div({className: "body"},
              div({className: "text"}, label),
              div({className: "uri"}, uri),
              div({className: "socketId"}, socketIdLabel)
            )
          )
        )
      )
    );
  }
}));

/**
 * @template This template is responsible for rendering a message
 * at the top of the frame list that informs the user about reaching
 * the maximum limit of displayed frames. The message also displays
 * number of frames removed from the list.
 */
var FrameLimit = React.createFactory(React.createClass({
/** @lends FrameLimit */

  displayName: "FrameLimit",

  render: function() {
    var { removedFrames } = this.props;

    // Render summary info
    return (
      div({className: "frameLimit"},
        span({className: "text"},
          Locale.$STRP("websocketmonitor.limit.removedFrames", [removedFrames])
        )
      )
    );
  }
}));

/**
 * @template This template is responsible for rendering frame summary
 * information. It displays number of sent and received packets
 * and total amount of sent and received data.
 */
var FrameSummary = React.createFactory(React.createClass({
/** @lends FrameSummary */

  displayName: "FrameSummary",

  render: function() {
    var { summary } = this.props;

    return (
      div({className: "frameSummary"},
        div({className: "text"},
          Locale.$STRP("websocketmonitor.summary.frameCount", [summary.frameCount])
        ),
        div({className: "separator"}),
        div({className: "text"},
          Str.formatSize(summary.totalSize)
        ),
        div({className: "separator"}),
        div({className: "time"},
          Str.formatTime((summary.endTime - summary.startTime) / 1000)
        )
      )
    );
  }
}));

// Exports from this module
exports.FrameList = FrameList;
});
<|endoftext|>