<commit_before>var duplexify = require('duplexify')
var abstract = require('abstract-leveldown')
var util = require('util')
var eos = require('end-of-stream')
var streams = require('./streams')

var noop = function () {}

var decodeError = function (err) {
  return err ? new Error(err) : null
}

var decodeValue = function (val, enc) {
  if (!val) return undefined
  return (enc === 'utf8' || enc === 'utf-8') ? val.toString() : val
}

var Multilevel = function (path, opts) {
  if (!(this instanceof Multilevel)) return new Multilevel(path, opts)
  abstract.AbstractLevelDOWN.call(this, path)

  if (!opts) opts = {}

  this._retry = !!opts.retry
  this._requests = []
  this._iterators = []
  this._flush = []
  this._encode = null
}

util.inherits(Multilevel, abstract.AbstractLevelDOWN)

var gc = function (list, i) {
  list[i] = null
  while (list.length && !list[list.length - 1]) list.pop()
}

Multilevel.prototype._pbs = function (encode, decode) {
  this._encode = encode

  for (var i = 0; i < this._requests.length; i++) {
    var req = this._requests[i]
    if (!req) continue

    switch (req.method) {
      case 'put':
      encode.puts(req)
      break

      case 'get':
      encode.gets(req)
      break

      case 'del':
      encode.deletes(req)
      break

      case 'batch':
      encode.batches(req)
      break
    }
  }

  for (var j = 0; j < this._iterators.length; j++) {
    var ite = this._iterators[j]
    if (!ite) continue
    ite.options = ite.self._options
    encode.iterators(ite)
  }

  var self = this

  decode.callbacks(function (callback, cb) {
    var req = self._requests[callback.id]
    if (!req) return cb()
    gc(self._requests, callback.id)
    self._flushMaybe()
    req.cb(decodeError(callback.error), decodeValue(callback.value, req.valueEncoding))
    cb()
  })

  decode.iterators(function (ite, cb) {
    var req = self._iterators[ite.id]
    if (!req) return cb()
    req.pending.push(ite)
    if (req.cb) req.self.next(req.cb)
    cb()
  })

  eos(encode, function () {
    self._encode = null

    if (self._retry) return

    for (var i = 0; i < self._requests.length; i++) {
      var req = self._requests[i]
      if (req) req.cb(new Error('Connection to leader lost'))
    }

    for (var j = 0; j < self._iterators.length; j++) {
      var ite = self._iterators[j]
      if (ite) {
        if (ite.cb) ite.cb(new Error('Connection to leader lost'))
        else ite.self.end()
      }
    }

    self._requests = []
    self._iterators = []
    self._flushMaybe()
  })

  return null
}

Multilevel.prototype.createRpcStream = function (opts) {
  if (opts && opts.encode && opts.decode) return this._pbs(opts.encode, opts.decode)
  var encode = streams.Client.encode()
  var decode = streams.Server.decode()
  this._pbs(encode, decode)
  return duplexify(decode, encode)
}

Multilevel.prototype.isFlushed = function () {
  return !this._requests.length && !this._iterators.length
}

// to allow someone using multileveldown to detect
// when it is safe to shutdown the pipeline
Multilevel.prototype.flush = function (cb) {
  if (this.isFlushed()) return cb()
  this._flush.push(cb)
}

Multilevel.prototype._flushMaybe = function () {
  if (!this.isFlushed()) return
  while (this._flush.length) this._flush.shift()()
}

var nextId = function (list) {
  var id = list.indexOf(null)
  if (id === -1) id = list.push(null) - 1
  return id
}

Multilevel.prototype._put = function (key, value, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'put',
    id: id,
    key: key,
    value: value,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) if (this._encode) this._encode.puts(req)
}

Multilevel.prototype._get = function (key, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'get',
    id: id,
    key: key,
    valueEncoding: opts.valueEncoding,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.gets(req)
}

Multilevel.prototype._del = function (key, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'del',
    id: id,
    key: key,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.deletes(req)
}

Multilevel.prototype._batch = function (batch, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'batch',
    id: id,
    ops: batch,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.batches(req)
}

var Iterator = function (parent, opts) {
  this._id = nextId(parent._iterators)
  this._parent = parent
  this._keyEncoding = opts.keyEncoding
  this._valueEncoding = opts.valueEncoding
  this._options = opts

  var req = {
    id: this._id,
    batch: 32,
    pending: [],
    self: this,
    prev: null,
    options: opts,
    cb: null
  }

  this._read = 0
  this._ack = Math.floor(req.batch / 2)
  this._req = req
  this._parent._iterators[this._id] = req
  if (this._parent._encode) this._parent._encode.iterators(req)
}

Iterator.prototype.next = function (cb) {
  var req = this._req
  req.cb = null

  if (req.pending.length) {
    this._read++
    if (this._read >= this._ack) {
      this._read = 0
      this._req.options = null
      if (this._parent._encode) this._parent._encode.iterators(this._req)
    }

    var next = req.pending.shift()
    if (next.error) return cb(decodeError(next.error))
    if (!next.key && !next.value) return cb()
    this._options.gt = next.key
    if (this._options.limit > 0) this._options.limit--
    return cb(undefined, decodeValue(next.key, this._keyEncoding), decodeValue(next.value, this._valueEncoding))
  }

  req.cb = cb
}

Iterator.prototype.end = function (cb) {
  this._req.batch = 0
  if (this._parent._encode) this._parent._encode.iterators(this._req)
  gc(this._parent._iterators, this._id)
  this._parent._flushMaybe()
  cb()
}

Multilevel.prototype._iterator = function (opts) {
  return new Iterator(this, opts)
}

module.exports = Multilevel
<commit_msg>destroy encoder on close<commit_after>var duplexify = require('duplexify')
var abstract = require('abstract-leveldown')
var util = require('util')
var eos = require('end-of-stream')
var streams = require('./streams')

var noop = function () {}

var decodeError = function (err) {
  return err ? new Error(err) : null
}

var decodeValue = function (val, enc) {
  if (!val) return undefined
  return (enc === 'utf8' || enc === 'utf-8') ? val.toString() : val
}

var Multilevel = function (path, opts) {
  if (!(this instanceof Multilevel)) return new Multilevel(path, opts)
  abstract.AbstractLevelDOWN.call(this, path)

  if (!opts) opts = {}

  this._retry = !!opts.retry
  this._requests = []
  this._iterators = []
  this._flush = []
  this._encode = null
}

util.inherits(Multilevel, abstract.AbstractLevelDOWN)

var gc = function (list, i) {
  list[i] = null
  while (list.length && !list[list.length - 1]) list.pop()
}

Multilevel.prototype._pbs = function (encode, decode) {
  this._encode = encode

  for (var i = 0; i < this._requests.length; i++) {
    var req = this._requests[i]
    if (!req) continue

    switch (req.method) {
      case 'put':
      encode.puts(req)
      break

      case 'get':
      encode.gets(req)
      break

      case 'del':
      encode.deletes(req)
      break

      case 'batch':
      encode.batches(req)
      break
    }
  }

  for (var j = 0; j < this._iterators.length; j++) {
    var ite = this._iterators[j]
    if (!ite) continue
    ite.options = ite.self._options
    encode.iterators(ite)
  }

  var self = this

  decode.callbacks(function (callback, cb) {
    var req = self._requests[callback.id]
    if (!req) return cb()
    gc(self._requests, callback.id)
    self._flushMaybe()
    req.cb(decodeError(callback.error), decodeValue(callback.value, req.valueEncoding))
    cb()
  })

  decode.iterators(function (ite, cb) {
    var req = self._iterators[ite.id]
    if (!req) return cb()
    req.pending.push(ite)
    if (req.cb) req.self.next(req.cb)
    cb()
  })

  eos(encode, function () {
    self._encode = null
    if (self._retry) return
    self._clearRequests()
    self._flushMaybe()
  })

  return null
}

Multilevel.prototype._clearRequests = function () {
  for (var i = 0; i < this._requests.length; i++) {
    var req = this._requests[i]
    if (req) req.cb(new Error('Connection to leader lost'))
  }

  for (var j = 0; j < this._iterators.length; j++) {
    var ite = this._iterators[j]
    if (ite) {
      if (ite.cb) ite.cb(new Error('Connection to leader lost'))
      else ite.self.end()
    }
  }

  this._requests = []
  this._iterators = []
}

Multilevel.prototype.createRpcStream = function (opts) {
  if (opts && opts.encode && opts.decode) return this._pbs(opts.encode, opts.decode)
  var encode = streams.Client.encode()
  var decode = streams.Server.decode()
  this._pbs(encode, decode)
  return duplexify(decode, encode)
}

Multilevel.prototype.isFlushed = function () {
  return !this._requests.length && !this._iterators.length
}

// to allow someone using multileveldown to detect
// when it is safe to shutdown the pipeline
Multilevel.prototype.flush = function (cb) {
  if (this.isFlushed()) return cb()
  this._flush.push(cb)
}

Multilevel.prototype._flushMaybe = function () {
  if (!this.isFlushed()) return
  while (this._flush.length) this._flush.shift()()
}

var nextId = function (list) {
  var id = list.indexOf(null)
  if (id === -1) id = list.push(null) - 1
  return id
}

Multilevel.prototype._put = function (key, value, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'put',
    id: id,
    key: key,
    value: value,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) if (this._encode) this._encode.puts(req)
}

Multilevel.prototype._get = function (key, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'get',
    id: id,
    key: key,
    valueEncoding: opts.valueEncoding,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.gets(req)
}

Multilevel.prototype._del = function (key, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'del',
    id: id,
    key: key,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.deletes(req)
}

Multilevel.prototype._batch = function (batch, opts, cb) {
  var id = nextId(this._requests)
  var req = {
    method: 'batch',
    id: id,
    ops: batch,
    cb: cb || noop
  }

  this._requests[id] = req
  if (this._encode) this._encode.batches(req)
}

Multilevel.prototype._close = function (cb) {
  if (this._encode) this._encode.destroy()
  this._clearRequests()
  cb()
}

var Iterator = function (parent, opts) {
  this._id = nextId(parent._iterators)
  this._parent = parent
  this._keyEncoding = opts.keyEncoding
  this._valueEncoding = opts.valueEncoding
  this._options = opts

  var req = {
    id: this._id,
    batch: 32,
    pending: [],
    self: this,
    prev: null,
    options: opts,
    cb: null
  }

  this._read = 0
  this._ack = Math.floor(req.batch / 2)
  this._req = req
  this._parent._iterators[this._id] = req
  if (this._parent._encode) this._parent._encode.iterators(req)
}

Iterator.prototype.next = function (cb) {
  var req = this._req
  req.cb = null

  if (req.pending.length) {
    this._read++
    if (this._read >= this._ack) {
      this._read = 0
      this._req.options = null
      if (this._parent._encode) this._parent._encode.iterators(this._req)
    }

    var next = req.pending.shift()
    if (next.error) return cb(decodeError(next.error))
    if (!next.key && !next.value) return cb()
    this._options.gt = next.key
    if (this._options.limit > 0) this._options.limit--
    return cb(undefined, decodeValue(next.key, this._keyEncoding), decodeValue(next.value, this._valueEncoding))
  }

  req.cb = cb
}

Iterator.prototype.end = function (cb) {
  this._req.batch = 0
  if (this._parent._encode) this._parent._encode.iterators(this._req)
  gc(this._parent._iterators, this._id)
  this._parent._flushMaybe()
  cb()
}

Multilevel.prototype._iterator = function (opts) {
  return new Iterator(this, opts)
}

module.exports = Multilevel
<|endoftext|>


<commit_before>slate.configAll({
  defaultToCurrentScreen: true,
});

// monitors
var internal = '1440x900';
var cinema   = '2560x1440';
var monitors = [internal, cinema];

// layouts
var oneMonitor  = 'one-monitor';
var twoMonitors = 'two-monitors';

// aliases to give us a DSL-like feel
var up          = 'up';
var right       = 'right';
var down        = 'down';
var left        = 'left';
var topRight    = 'top-right';
var bottomRight = 'bottom-right';
var bottomLeft  = 'bottom-left';
var topLeft     = 'top-left';
var second      = seconds = 1000;

// operations for layouts
var hideSpotify  = slate.operation('hide', { app: 'Spotify' });
var focusITerm   = slate.operation('focus', { app: 'iTerm' });
var focusTextual = slate.operation('focus', { app: 'Textual' });

function positionChrome(window) {
  var app = window.app();
  if (slate.screenCount() === 1) {
    window.doOperation(move(0).screen(internal));
  } else {
    if (typeof app.bundleIdentifier === 'function' &&
        app.bundleIdentifier() === 'com.google.Chrome.canary') {
      window.doOperation(push(left, 1 / 2).screen(cinema));
    } else {
      window.doOperation(push(right, 1 / 2).screen(cinema));
    }
  }
}

slate.layout('one-monitor', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusITerm] },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  iTerm: {
    operations: [move(0).screen(internal)],
    repeat: true,
    'sort-title': true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.layout('two-monitors', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusTextual, focusITerm] },
  iTerm: {
    operations: [
      push(left, 1 / 2).screen(cinema),
      push(right, 1 / 2).screen(cinema),
    ],
    repeat: true,
    'sort-title': true,
  },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.default([internal], oneMonitor);
slate.default([internal, cinema], twoMonitors);

function handleEvent(app, window) {
  if (!window) {
    return;
  }

  switch (app.name()) {
    case 'Google Chrome':
      positionChrome(window);
      break;
    case 'iTerm':
      if (slate.screenCount() === 1) {
        window.doOperation(move(0).screen(window.screen()));
      } else {
        window.doOperation(push(left, 1 / 2).screen(window.screen()));
      }
      break;
    case 'Textual':
      window.doOperation(move(0).screen(internal));
      break;
  }
}

slate.on('windowOpened', function(event, window) {
  handleEvent(window.app(), window);
});

slate.on('appOpened', function(event, app) {
  handleEvent(app, app.mainWindow());
});

slate.bindAll({
  'up:ctrl;alt': chain([
    push(up, 1 / 2),
    push(up, 1 / 3),
    push(up, 2 / 3),
  ]),
  'right:ctrl;alt': chain([
    push(right, 1 / 2),
    push(right, 1 / 3),
    push(right, 2 / 3),
  ]),
  'down:ctrl;alt': chain([
    push(down, 1 / 2),
    push(down, 1 / 3),
    push(down, 2 / 3),
  ]),
  'left:ctrl;alt': chain([
    push(left, 1 / 2),
    push(left, 1 / 3),
    push(left, 2 / 3),
  ]),

  'up:ctrl;alt;cmd': chain([
    corner(topLeft),
    corner(topRight),
    corner(bottomRight),
    corner(bottomLeft),
  ]),

  'down:ctrl;alt;cmd': chain([
    move(0),     // full screen
    move(1 / 4), // centered, big
    move(1 / 3), // centered, small
  ]),

  'left:ctrl;alt;cmd':  focus('left'),
  'right:ctrl;alt;cmd': focus('right'),

  // for testing layouts
  'f1:ctrl;alt;cmd': layout(oneMonitor),
  'f2:ctrl;alt;cmd': layout(twoMonitors),
});

/**
 * Push window to the edge of the screen
 *
 * @param {string} direction direction the window should be pushed
 * @param {number} ratio proportion of the screen that the window should take up
 */
function push(direction, ratio) {
  var denominator = 1 / ratio;
  var numerator   = ratio * denominator;
  var axis        = (direction === 'up' || direction === 'down' ? 'Y' : 'X');

  numerator = (numerator === 1 ? '' : numerator + '*');
  denominator = '/' + denominator;

  return operation('push', {
    direction: direction,
    style: 'bar-resize:' + numerator + 'screenSize' + axis + denominator,
  });
}

/**
 * Place window in a corner of the screen
 *
 * @param {string} position The corner (topLeft, bottomRight etc) into which to
 * move
 */
function corner(position) {
  return operation('corner', {
    direction: position,
    height:    'screenSizeY/2',
    width:     'screenSizeX/2',
  });
}

/**
 * Move window to the center of the screen
 *
 * @param {number} insetRatio How far in from the edges of the screen the window
 * should be placed, as a proportion of the available space
 */
function move(insetRatio) {
  var denominator    = insetRatio ? 1 / insetRatio : 0;
  var numerator      = insetRatio * denominator;
  var insetX         = denominator ? '+screenSizeX/' + denominator : '';
  var insetY         = denominator ? '+screenSizeY/' + denominator : '';
  var modifier       = 1 / (1 - 2 * insetRatio);
  var modifierString = modifier === 1 ? '' : '/' + modifier;

  return operation('move', {
    height: 'screenSizeY' + modifierString,
    width:  'screenSizeX' + modifierString,
    x:      'screenOriginX' + insetX,
    y:      'screenOriginY' + insetY,
  });
}

/**
 * Switch focus to the next window in a given direction
 *
 * @param {string} direction The direction (eg. left, right) in which to move
 * focus.
 */
function focus(direction) {
  return slate.operation('focus', { direction: direction });
}

/**
 * Activate a named layout
 *
 * @param {string} name The layout to be activated
 */
function layout(name) {
  return slate.operation('layout', { name: name });
}

/**
 * Return a wrapper for a Slate operation initialized with the requested
 * arguments.
 *
 * This is a crude "proxy" object which forwards the documented `run()` and
 * `dup()` methods to the underlying Slate operation, and additionally adds a
 * `screen()` method that can be used to target an operation to a particular
 * screen.
 *
 */
function operation() {
  var op = slate.operation.apply(slate, arguments);

  return {
    // documented
    run: op.run.bind(op),
    dup: op.dup.bind(op),

    // add-ons
    screen: function(screen) { return op.dup({ screen: screen }); },
  };
}

/**
 * Given a screen, returns the next screen among the predefined list of screens
 *
 * @param {object} screen The current screen object, as provided by Slate
 * @returns {string} A screen identifier corresponding to the next screen
 */
function nextScreen(screen) {
  var dimensions  = screen.rect();
  var description = dimensions.width + 'x' + dimensions.height;
  var nextIndex   = monitors.indexOf(description) + 1;

  return monitors[nextIndex % monitors.length];
}

var lastSeenChain;
var lastSeenWindow;

/**
 * Chain an array of operations
 *
 * Unlike the built-in `chain()` method, this implements two additional
 * behaviors:
 *
 * - chains always start on the screen the window is currently on
 * - a chain will be reset after 1 second of inactivity, or on switching from
 *   one chain to another, or on switching from one app to another, or from one
 *   window to another
 *
 * @param {array} functions The operations (as functions) to be chained
 * @returns {function} A function that will return operations in chained order,
 * suitable for passing to `slate.bind()`.
 */
function chain(functions) {
  var lastSeenAt;
  var sequenceNumber;
  var resetChainAfter = 1 * second;

  return function(window) {
    var screen = window.screen();
    var id     = fingerprint(window);
    var now    = Date.now();
    if (lastSeenChain !== functions ||
        lastSeenAt < now - resetChainAfter ||
        !_.isEqual(lastSeenWindow, id)) {
      lastSeenChain = functions;
      sequenceNumber = 0;
    } else {
      if (sequenceNumber && !((sequenceNumber + 1) % functions.length)) {
        screen = nextScreen(screen); // at end of sequence; time to swap
      }
      sequenceNumber++;
    }
    lastSeenAt = now;

    var operation = functions[sequenceNumber % functions.length];
    window.doOperation(operation.screen(screen));
    lastSeenWindow = fingerprint(window);
  };
}

/**
 * Returns a fingerprint that can be used to (heuristically) compare one window
 * to another.
 *
 * The OS X accessibility APIs don't expose window identity information, so we
 * have to infer it from geometry (origin, dimensions) and app ownership. Note
 * that we special-case iTerm and don't include the title in the fingerprint for
 * its windows because it has a habit of dynamically changing titles
 * (temporarily annotating with column and row count information), and it is not
 * a race that we can reliably win.
 *
 * @see http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
 *
 * @param {object} window A Slate Window instance.
 * @returns {object} A an object that can be compared for equality with
 * `_.isEqual()`.
 */
function fingerprint(window) {
  var rect = window.rect();

  return {
    x:       rect.x,
    y:       rect.y,
    width:   rect.width,
    height:  rect.height,
    title:   window.app().name() === 'iTerm' ? 'iTerm' : window.title(),
    pid:     window.pid(),
  };
}

slate.log('finished loading config');
<commit_msg>Slate: only position first Chrome window<commit_after>slate.configAll({
  defaultToCurrentScreen: true,
});

// monitors
var internal = '1440x900';
var cinema   = '2560x1440';
var monitors = [internal, cinema];

// layouts
var oneMonitor  = 'one-monitor';
var twoMonitors = 'two-monitors';

// aliases to give us a DSL-like feel
var up          = 'up';
var right       = 'right';
var down        = 'down';
var left        = 'left';
var topRight    = 'top-right';
var bottomRight = 'bottom-right';
var bottomLeft  = 'bottom-left';
var topLeft     = 'top-left';
var second      = seconds = 1000;

// operations for layouts
var hideSpotify  = slate.operation('hide', { app: 'Spotify' });
var focusITerm   = slate.operation('focus', { app: 'iTerm' });
var focusTextual = slate.operation('focus', { app: 'Textual' });

function positionChrome(window) {
  if (window.hidden()) {
    return;
  }

  // only operate on first window; Chrome usually does something intelligent
  // with the rest
  var app = window.app();
  var windowCount = 0;
  app.eachWindow(function(w) {
    // for each new window we open, we actually get called twice; once with an
    // empty title (which we ignore) and once with the real thing
    if (w.title() !== '' && !w.hidden()) {
      windowCount++;
    }
  });
  if (windowCount > 1) {
    return;
  }

  if (slate.screenCount() === 1) {
    window.doOperation(move(0).screen(internal));
  } else {
    if (typeof app.bundleIdentifier === 'function' &&
        app.bundleIdentifier() === 'com.google.Chrome.canary') {
      window.doOperation(push(left, 1 / 2).screen(cinema));
    } else {
      window.doOperation(push(right, 1 / 2).screen(cinema));
    }
  }
}

slate.layout('one-monitor', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusITerm] },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  iTerm: {
    operations: [move(0).screen(internal)],
    repeat: true,
    'sort-title': true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.layout('two-monitors', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusTextual, focusITerm] },
  iTerm: {
    operations: [
      push(left, 1 / 2).screen(cinema),
      push(right, 1 / 2).screen(cinema),
    ],
    repeat: true,
    'sort-title': true,
  },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.default([internal], oneMonitor);
slate.default([internal, cinema], twoMonitors);

function handleEvent(app, window) {
  if (!window) {
    return;
  }

  switch (app.name()) {
    case 'Google Chrome':
      positionChrome(window);
      break;
    case 'iTerm':
      if (slate.screenCount() === 1) {
        window.doOperation(move(0).screen(window.screen()));
      } else {
        window.doOperation(push(left, 1 / 2).screen(window.screen()));
      }
      break;
    case 'Textual':
      window.doOperation(move(0).screen(internal));
      break;
  }
}

slate.on('windowOpened', function(event, window) {
  handleEvent(window.app(), window);
});

slate.on('appOpened', function(event, app) {
  handleEvent(app, app.mainWindow());
});

slate.bindAll({
  'up:ctrl;alt': chain([
    push(up, 1 / 2),
    push(up, 1 / 3),
    push(up, 2 / 3),
  ]),
  'right:ctrl;alt': chain([
    push(right, 1 / 2),
    push(right, 1 / 3),
    push(right, 2 / 3),
  ]),
  'down:ctrl;alt': chain([
    push(down, 1 / 2),
    push(down, 1 / 3),
    push(down, 2 / 3),
  ]),
  'left:ctrl;alt': chain([
    push(left, 1 / 2),
    push(left, 1 / 3),
    push(left, 2 / 3),
  ]),

  'up:ctrl;alt;cmd': chain([
    corner(topLeft),
    corner(topRight),
    corner(bottomRight),
    corner(bottomLeft),
  ]),

  'down:ctrl;alt;cmd': chain([
    move(0),     // full screen
    move(1 / 4), // centered, big
    move(1 / 3), // centered, small
  ]),

  'left:ctrl;alt;cmd':  focus('left'),
  'right:ctrl;alt;cmd': focus('right'),

  // for testing layouts
  'f1:ctrl;alt;cmd': layout(oneMonitor),
  'f2:ctrl;alt;cmd': layout(twoMonitors),
});

/**
 * Push window to the edge of the screen
 *
 * @param {string} direction direction the window should be pushed
 * @param {number} ratio proportion of the screen that the window should take up
 */
function push(direction, ratio) {
  var denominator = 1 / ratio;
  var numerator   = ratio * denominator;
  var axis        = (direction === 'up' || direction === 'down' ? 'Y' : 'X');

  numerator = (numerator === 1 ? '' : numerator + '*');
  denominator = '/' + denominator;

  return operation('push', {
    direction: direction,
    style: 'bar-resize:' + numerator + 'screenSize' + axis + denominator,
  });
}

/**
 * Place window in a corner of the screen
 *
 * @param {string} position The corner (topLeft, bottomRight etc) into which to
 * move
 */
function corner(position) {
  return operation('corner', {
    direction: position,
    height:    'screenSizeY/2',
    width:     'screenSizeX/2',
  });
}

/**
 * Move window to the center of the screen
 *
 * @param {number} insetRatio How far in from the edges of the screen the window
 * should be placed, as a proportion of the available space
 */
function move(insetRatio) {
  var denominator    = insetRatio ? 1 / insetRatio : 0;
  var numerator      = insetRatio * denominator;
  var insetX         = denominator ? '+screenSizeX/' + denominator : '';
  var insetY         = denominator ? '+screenSizeY/' + denominator : '';
  var modifier       = 1 / (1 - 2 * insetRatio);
  var modifierString = modifier === 1 ? '' : '/' + modifier;

  return operation('move', {
    height: 'screenSizeY' + modifierString,
    width:  'screenSizeX' + modifierString,
    x:      'screenOriginX' + insetX,
    y:      'screenOriginY' + insetY,
  });
}

/**
 * Switch focus to the next window in a given direction
 *
 * @param {string} direction The direction (eg. left, right) in which to move
 * focus.
 */
function focus(direction) {
  return slate.operation('focus', { direction: direction });
}

/**
 * Activate a named layout
 *
 * @param {string} name The layout to be activated
 */
function layout(name) {
  return slate.operation('layout', { name: name });
}

/**
 * Return a wrapper for a Slate operation initialized with the requested
 * arguments.
 *
 * This is a crude "proxy" object which forwards the documented `run()` and
 * `dup()` methods to the underlying Slate operation, and additionally adds a
 * `screen()` method that can be used to target an operation to a particular
 * screen.
 *
 */
function operation() {
  var op = slate.operation.apply(slate, arguments);

  return {
    // documented
    run: op.run.bind(op),
    dup: op.dup.bind(op),

    // add-ons
    screen: function(screen) { return op.dup({ screen: screen }); },
  };
}

/**
 * Given a screen, returns the next screen among the predefined list of screens
 *
 * @param {object} screen The current screen object, as provided by Slate
 * @returns {string} A screen identifier corresponding to the next screen
 */
function nextScreen(screen) {
  var dimensions  = screen.rect();
  var description = dimensions.width + 'x' + dimensions.height;
  var nextIndex   = monitors.indexOf(description) + 1;

  return monitors[nextIndex % monitors.length];
}

var lastSeenChain;
var lastSeenWindow;

/**
 * Chain an array of operations
 *
 * Unlike the built-in `chain()` method, this implements two additional
 * behaviors:
 *
 * - chains always start on the screen the window is currently on
 * - a chain will be reset after 1 second of inactivity, or on switching from
 *   one chain to another, or on switching from one app to another, or from one
 *   window to another
 *
 * @param {array} functions The operations (as functions) to be chained
 * @returns {function} A function that will return operations in chained order,
 * suitable for passing to `slate.bind()`.
 */
function chain(functions) {
  var lastSeenAt;
  var sequenceNumber;
  var resetChainAfter = 1 * second;

  return function(window) {
    var screen = window.screen();
    var id     = fingerprint(window);
    var now    = Date.now();
    if (lastSeenChain !== functions ||
        lastSeenAt < now - resetChainAfter ||
        !_.isEqual(lastSeenWindow, id)) {
      lastSeenChain = functions;
      sequenceNumber = 0;
    } else {
      if (sequenceNumber && !((sequenceNumber + 1) % functions.length)) {
        screen = nextScreen(screen); // at end of sequence; time to swap
      }
      sequenceNumber++;
    }
    lastSeenAt = now;

    var operation = functions[sequenceNumber % functions.length];
    window.doOperation(operation.screen(screen));
    lastSeenWindow = fingerprint(window);
  };
}

/**
 * Returns a fingerprint that can be used to (heuristically) compare one window
 * to another.
 *
 * The OS X accessibility APIs don't expose window identity information, so we
 * have to infer it from geometry (origin, dimensions) and app ownership. Note
 * that we special-case iTerm and don't include the title in the fingerprint for
 * its windows because it has a habit of dynamically changing titles
 * (temporarily annotating with column and row count information), and it is not
 * a race that we can reliably win.
 *
 * @see http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
 *
 * @param {object} window A Slate Window instance.
 * @returns {object} A an object that can be compared for equality with
 * `_.isEqual()`.
 */
function fingerprint(window) {
  var rect = window.rect();

  return {
    x:       rect.x,
    y:       rect.y,
    width:   rect.width,
    height:  rect.height,
    title:   window.app().name() === 'iTerm' ? 'iTerm' : window.title(),
    pid:     window.pid(),
  };
}

slate.log('finished loading config');
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Fri Jul 29 2016 14:01:07 GMT+1000 (AEST)
var webpackConfig = require('./webpack.config.js');

module.exports = function(config) {
  config.set({
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'spec/helpers/**/*.js',
      'http://cdn.jsdelivr.net/g/lodash@2.4.2(lodash.underscore.min.js),handlebarsjs@1.3.0,jquery@2.2.4,momentjs@2.9.0,bootstrap@2.3.2',
      'http://assets.zendesk.com/apps/sdk/2.0/zaf_sdk.js',
      'spec/**/*_spec.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'spec/helpers/**/*.js': ['webpack'],
      'spec/**/*_spec.js': ['webpack']
    },

    webpack: {
      // karma watches the test entry points
      // (you don't need to specify the entry option)
      // webpack watches dependencies

      // webpack configuration
      module: webpackConfig.module,
      resolveLoader: webpackConfig.resolveLoader,
      resolve: webpackConfig.resolve,
      externals: webpackConfig.externals
    },

    webpackServer: {
      noInfo: true // Suppress all webpack messages, except errors
    },

    webpackMiddleware: {
      // webpack-dev-middleware configuration
      // i. e.
      stats: 'errors-only'
    },

    plugins: [
      require("karma-webpack"),
      require("karma-jasmine"),
      require("karma-phantomjs-launcher"),
      require("karma-chrome-launcher")
    ],

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['dots'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantonJS_without_security'],

    customLaunchers: {
      // CRUFT: needed to load zaf_sdk with crossorigin=anonymous
      Chrome_without_security: {
        base: 'Chrome',
        flags: ['--disable-web-security']
      },
      PhantonJS_without_security: {
        base: 'PhantomJS',
        flags: ['--web-security=false']
      }
    },

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<commit_msg>PhantomJS doesn't care about security<commit_after>// Karma configuration
// Generated on Fri Jul 29 2016 14:01:07 GMT+1000 (AEST)
var webpackConfig = require('./webpack.config.js');

module.exports = function(config) {
  config.set({
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'spec/helpers/**/*.js',
      'http://cdn.jsdelivr.net/g/lodash@2.4.2(lodash.underscore.min.js),handlebarsjs@1.3.0,jquery@2.2.4,momentjs@2.9.0,bootstrap@2.3.2',
      'http://assets.zendesk.com/apps/sdk/2.0/zaf_sdk.js',
      'spec/**/*_spec.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'spec/helpers/**/*.js': ['webpack'],
      'spec/**/*_spec.js': ['webpack']
    },

    webpack: {
      // karma watches the test entry points
      // (you don't need to specify the entry option)
      // webpack watches dependencies

      // webpack configuration
      module: webpackConfig.module,
      resolveLoader: webpackConfig.resolveLoader,
      resolve: webpackConfig.resolve,
      externals: webpackConfig.externals
    },

    webpackServer: {
      noInfo: true // Suppress all webpack messages, except errors
    },

    webpackMiddleware: {
      // webpack-dev-middleware configuration
      // i. e.
      stats: 'errors-only'
    },

    plugins: [
      require("karma-webpack"),
      require("karma-jasmine"),
      require("karma-phantomjs-launcher"),
      require("karma-chrome-launcher")
    ],

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['dots'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],

    customLaunchers: {
      // CRUFT: needed to load zaf_sdk with crossorigin=anonymous
      Chrome_without_security: {
        base: 'Chrome',
        flags: ['--disable-web-security']
      }
    },

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<|endoftext|>


<commit_before>import User from '../models/user.model';

/**
 * Authenticate user inputed username and password
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.authenticate = (req, res, next) => {

};

/**
 * Change user password
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.changePwd = (req, res, next) => {

};

/**
 * Fetch user profile information
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.getProfile = (req, res, next) => {

};

/**
 * Update user profile
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.updateProfile = (req, res, next) => {

};
<commit_msg>Adds initial user controller<commit_after>import User from '../models/user.model';

/**
 * Authenticate user inputed username and password
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.authenticate = (req, res, next) => {
  // todo - coming soon
  let _reqPayload = req.body;
  res.status(200).json(_reqPayload);
};

/**
 * Change user password
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.changePwd = (req, res, next) => {
  // todo - coming soon
};

/**
 * Add user profile information
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.setProfile = (req, res, next) => {
  // todo - coming soon
};

/**
 * Fetch user profile information
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.getProfile = (req, res, next) => {
  // todo - coming soon
};

/**
 * Update user profile
 * @param {Object} req - request object
 * @param {Object} res - response object
 * @param {Function} next - next() function
 */
exports.updateProfile = (req, res, next) => {
  // todo - coming soon
};
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * 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.
 *
 */

/* <video id="video2" autoplay width="640px" height="480px"
						poster="img/webrtc.png"></video>
*/

var ws = new WebSocket('wss://' + location.host + '/call');
var mainVideo;
var otherVideos;
var mainWebRtcPeer;
var otherWebRtcPeers;
var newVideoId;

window.onload = function() {
	console = new Console();
	mainVideo = document.getElementById('mainVideo');
	otherVideos = document.getElementById('student-cams');
	otherVideos = [];
	otherWebRtcPeers = [];
	newVideoId = 0;

	disableStopButton();
	disableRecordButton();
}

window.onbeforeunload = function() {
	ws.close();
}

ws.onmessage = function(message) {
	var parsedMessage = JSON.parse(message.data);
	console.info('Received message: ' + message.data);

	switch (parsedMessage.id) {
		case 'addTeacherResponse':
			addTeacherResponse(parsedMessage);
			break;
		case 'addStudentToTeacher':
			addStudentToTeacher(parsedMessage);
			break;
		case 'removeStudentToTeacher':
			removeStudentToTeacher(parsedMessage);
			break;
		case 'addStudentResponse':
			addStudentResponse(parsedMessage);
			break;
		case 'removeStudentResponse':
			removeStudentResponse(parsedMessage);
			break;
		case 'iceCandidate':
			mainWebRtcPeer.addIceCandidate(parsedMessage.candidate, function(error) {
				if (error)
					return console.error('Error adding candidate: ' + error);
			});
			break;
		case 'stopCommunication':
			dispose();
			break;
		default:
			console.error('Unrecognized message', parsedMessage);
	}
}

function addTeacher() {
	if (!mainWebRtcPeer) {
		showSpinner(mainVideo);

		var options = {
			localVideo : mainVideo,
			onicecandidate : onIceCandidate
		}
		mainWebRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options,
				function(error) {
					if (error) {
						return console.error(error);
					}
					mainWebRtcPeer.generateOffer(onOfferTeacher);
				});

		enableStopButton();
		//enableButton('#record', 'record()');
	}
}

function onOfferTeacher(error, offerSdp) {
	if (error)
		return console.error('Error generating the offer');
	console.info('Invoking SDP offer callback function ' + location.host);
	var message = {
		id : 'addTeacher',
		sdpOffer : offerSdp
	}
	sendMessage(message);
}

function addTeacherResponse(message) {
	if (message.response != 'accepted') {
		var errorMsg = message.message ? message.message : 'Unknow error';
		console.info('Call not accepted for the following reason: ' + errorMsg);
		dispose();
	} else {
		mainWebRtcPeer.processAnswer(message.sdpAnswer, function(error) {
			if (error)
				return console.error(error);
		});
	}
}

function addStudentToTeacher(parsedMessage) {
	// add student id to list with corresponding video id
	// add video to videos list
}

function removeStudentToTeacher(parsedMessage) {
	// remove student id to list
	// remove video to videos list
}

function addStudent() {
	if (!mainWebRtcPeer) {
		showSpinner(mainVideo);
		addVideoPlayer(newVideoId);
		var tempPlayer = document.getElementById("cam-"+newVideoId);
		showSpinner(tempPlayer)
		var options = {
			remoteVideo : mainVideo,
			localVideo: tempPlayer,
			onicecandidate : onIceCandidate
		}
		mainWebRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options,
				function(error) {
					if (error) {
						return console.error(error);
					}
					this.generateOffer(onOfferStudent);
				});
		enableStopButton();

		newVideoId = newVideoId + 1;
	}
}

function onOfferStudent(error, offerSdp) {
	if (error)
		return console.error('Error generating the offer');
	console.info('Invoking SDP offer callback function ' + location.host);
	var message = {
		id : 'addStudent',
		sdpOffer : offerSdp
	}
	sendMessage(message);
}

function addStudentResponse(message) {
	if (message.response != 'accepted') {
		var errorMsg = message.message ? message.message : 'Unknow error';
		console.info('Call not accepted for the following reason: ' + errorMsg);
		dispose();
	} else {
		mainWebRtcPeer.processAnswer(message.sdpAnswer, function(error) {
			if (error)
				return console.error(error);
		});
	}
}

function removeStudentResponse(parsedMessage) {
	// purge students list
	// remove own video and display "disconnected in teacher video"
}

function onIceCandidate(candidate) {
	console.log("Local candidate" + JSON.stringify(candidate));

	var message = {
		id : 'onIceCandidate',
		candidate : candidate
	};
	sendMessage(message);
}

function stop() {
	var message = {
		id : 'stop'
	}
	sendMessage(message);
	dispose();
}

function dispose() {
	if (mainWebRtcPeer) {
		mainWebRtcPeer.dispose();
		mainWwebRtcPeer = null;
	}
	hideSpinner(mainVideo);

	disableStopButton();
}

function disableStopButton() {
	enableButton('#teacher', 'addTeacher()');
	enableButton('#student', 'addStudent()');
	disableButton('#stop');
}

function disableRecordButton() {
	disableButton('#record');
}

function enableStopButton() {
	disableButton('#teacher');
	disableButton('#student');
	enableButton('#stop', 'stop()');
}

function disableButton(id) {
	$(id).attr('disabled', true);
	$(id).removeAttr('onclick');
}

function enableButton(id, functionName) {
	$(id).attr('disabled', false);
	$(id).attr('onclick', functionName);
}

function addVideoPlayer(playerID) {
	console.log(otherVideos);
	otherVideos.appendChild("
<video id='cam-" + playerID + "' autoplay width='640px'" +
		"height='480px' poster='img/webrtc.png'></video>
")

}

function removeVideoPlayer(playerID) {
	// remove player from student players list by playerID
}

function sendMessage(message) {
	var jsonMessage = JSON.stringify(message);
	console.log('Senging message: ' + jsonMessage);
	ws.send(jsonMessage);
}

function showSpinner() {
	for (var i = 0; i < arguments.length; i++) {
		arguments[i].poster = './img/transparent-1px.png';
		arguments[i].style.background = 'center transparent url("./img/spinner.gif") no-repeat';
	}
}

function hideSpinner() {
	for (var i = 0; i < arguments.length; i++) {
		arguments[i].src = '';
		arguments[i].poster = './img/webrtc.png';
		arguments[i].style.background = '';
	}
}

/**
 * Lightbox utility (to display media pipeline image in a modal dialog)
 */
$(document).delegate('*[data-toggle="lightbox"]', 'click', function(event) {
	event.preventDefault();
	$(this).ekkoLightbox();
});
<commit_msg>quickfix<commit_after>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * 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.
 *
 */

/* <video id="video2" autoplay width="640px" height="480px"
						poster="img/webrtc.png"></video>
*/

var ws = new WebSocket('wss://' + location.host + '/call');
var mainVideo;
var otherVideos;
var otherVideosList;
var mainWebRtcPeer;
var otherWebRtcPeers;
var newVideoId;

window.onload = function() {
	console = new Console();
	mainVideo = document.getElementById('mainVideo');
	otherVideos = document.getElementById('student-cams');
	otherVideosList = [];
	otherWebRtcPeers = [];
	newVideoId = 0;

	disableStopButton();
	disableRecordButton();
}

window.onbeforeunload = function() {
	ws.close();
}

ws.onmessage = function(message) {
	var parsedMessage = JSON.parse(message.data);
	console.info('Received message: ' + message.data);

	switch (parsedMessage.id) {
		case 'addTeacherResponse':
			addTeacherResponse(parsedMessage);
			break;
		case 'addStudentToTeacher':
			addStudentToTeacher(parsedMessage);
			break;
		case 'removeStudentToTeacher':
			removeStudentToTeacher(parsedMessage);
			break;
		case 'addStudentResponse':
			addStudentResponse(parsedMessage);
			break;
		case 'removeStudentResponse':
			removeStudentResponse(parsedMessage);
			break;
		case 'iceCandidate':
			mainWebRtcPeer.addIceCandidate(parsedMessage.candidate, function(error) {
				if (error)
					return console.error('Error adding candidate: ' + error);
			});
			break;
		case 'stopCommunication':
			dispose();
			break;
		default:
			console.error('Unrecognized message', parsedMessage);
	}
}

function addTeacher() {
	if (!mainWebRtcPeer) {
		showSpinner(mainVideo);

		var options = {
			localVideo : mainVideo,
			onicecandidate : onIceCandidate
		}
		mainWebRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options,
				function(error) {
					if (error) {
						return console.error(error);
					}
					mainWebRtcPeer.generateOffer(onOfferTeacher);
				});

		enableStopButton();
		//enableButton('#record', 'record()');
	}
}

function onOfferTeacher(error, offerSdp) {
	if (error)
		return console.error('Error generating the offer');
	console.info('Invoking SDP offer callback function ' + location.host);
	var message = {
		id : 'addTeacher',
		sdpOffer : offerSdp
	}
	sendMessage(message);
}

function addTeacherResponse(message) {
	if (message.response != 'accepted') {
		var errorMsg = message.message ? message.message : 'Unknow error';
		console.info('Call not accepted for the following reason: ' + errorMsg);
		dispose();
	} else {
		mainWebRtcPeer.processAnswer(message.sdpAnswer, function(error) {
			if (error)
				return console.error(error);
		});
	}
}

function addStudentToTeacher(parsedMessage) {
	// add student id to list with corresponding video id
	// add video to videos list
}

function removeStudentToTeacher(parsedMessage) {
	// remove student id to list
	// remove video to videos list
}

function addStudent() {
	if (!mainWebRtcPeer) {
		showSpinner(mainVideo);
		addVideoPlayer(newVideoId);
		var tempPlayer = document.getElementById("cam-"+newVideoId);
		showSpinner(tempPlayer)
		var options = {
			remoteVideo : mainVideo,
			localVideo: tempPlayer,
			onicecandidate : onIceCandidate
		}
		mainWebRtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options,
				function(error) {
					if (error) {
						return console.error(error);
					}
					this.generateOffer(onOfferStudent);
				});
		enableStopButton();

		newVideoId = newVideoId + 1;
	}
}

function onOfferStudent(error, offerSdp) {
	if (error)
		return console.error('Error generating the offer');
	console.info('Invoking SDP offer callback function ' + location.host);
	var message = {
		id : 'addStudent',
		sdpOffer : offerSdp
	}
	sendMessage(message);
}

function addStudentResponse(message) {
	if (message.response != 'accepted') {
		var errorMsg = message.message ? message.message : 'Unknow error';
		console.info('Call not accepted for the following reason: ' + errorMsg);
		dispose();
	} else {
		mainWebRtcPeer.processAnswer(message.sdpAnswer, function(error) {
			if (error)
				return console.error(error);
		});
	}
}

function removeStudentResponse(parsedMessage) {
	// purge students list
	// remove own video and display "disconnected in teacher video"
}

function onIceCandidate(candidate) {
	console.log("Local candidate" + JSON.stringify(candidate));

	var message = {
		id : 'onIceCandidate',
		candidate : candidate
	};
	sendMessage(message);
}

function stop() {
	var message = {
		id : 'stop'
	}
	sendMessage(message);
	dispose();
}

function dispose() {
	if (mainWebRtcPeer) {
		mainWebRtcPeer.dispose();
		mainWwebRtcPeer = null;
	}
	hideSpinner(mainVideo);

	disableStopButton();
}

function disableStopButton() {
	enableButton('#teacher', 'addTeacher()');
	enableButton('#student', 'addStudent()');
	disableButton('#stop');
}

function disableRecordButton() {
	disableButton('#record');
}

function enableStopButton() {
	disableButton('#teacher');
	disableButton('#student');
	enableButton('#stop', 'stop()');
}

function disableButton(id) {
	$(id).attr('disabled', true);
	$(id).removeAttr('onclick');
}

function enableButton(id, functionName) {
	$(id).attr('disabled', false);
	$(id).attr('onclick', functionName);
}

function addVideoPlayer(playerID) {
	console.log(otherVideos);
	otherVideos.appendChild("
<video id='cam-" + playerID + "' autoplay width='640px'" +
		"height='480px' poster='img/webrtc.png'></video>
")

}

function removeVideoPlayer(playerID) {
	// remove player from student players list by playerID
}

function sendMessage(message) {
	var jsonMessage = JSON.stringify(message);
	console.log('Senging message: ' + jsonMessage);
	ws.send(jsonMessage);
}

function showSpinner() {
	for (var i = 0; i < arguments.length; i++) {
		arguments[i].poster = './img/transparent-1px.png';
		arguments[i].style.background = 'center transparent url("./img/spinner.gif") no-repeat';
	}
}

function hideSpinner() {
	for (var i = 0; i < arguments.length; i++) {
		arguments[i].src = '';
		arguments[i].poster = './img/webrtc.png';
		arguments[i].style.background = '';
	}
}

/**
 * Lightbox utility (to display media pipeline image in a modal dialog)
 */
$(document).delegate('*[data-toggle="lightbox"]', 'click', function(event) {
	event.preventDefault();
	$(this).ekkoLightbox();
});
<|endoftext|>


<commit_before>#! /usr/bin/env node

// Requires
var Q = require('q');
var _ = require('lodash');
var path = require('path');
var prog = require('commander');

var fs = require('fs');

var pkg = require('../package.json');
var generate = require("../lib/generate");
var parse = require("../lib/parse");
var generators = require("../lib/generate").generators;

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

var logError = function(err) {
    console.log(err.message || err);
    return Q.reject(err);
};

// General options
prog
.version(pkg.version)
.option('-d, --dir <source_directory>', 'Source directory of book, containing Markdown files');

var buildFunc;
prog
.command('build [source_dir]')
.description('Build a gitbook from a directory')
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-g, --generator <name>', 'Change generator, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-i, --intro <intro>', 'Description of the book to generate')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(buildFunc = function(dir, options) {
    dir = dir || process.cwd();
    outputDir = options.output || path.join(dir, '_book');

    console.log('Starting build ...');
    // Get repo's URL
    return utils.gitURL(dir)
    .then(function(url) {
        // Get ID of repo
        return utils.githubID(url);
    }, function(err) {
        return null;
    })
    .then(function(repoID) {
        var githubID = options.github || repoID;

        if(!githubID) {
            throw new Error('Needs a githubID (username/repo). Either set repo origin to a github repo or use the -g flag');
        }

        var parts = githubID.split('/', 2);
        var user = parts[0], repo = parts[1];

        var title = options.title || utils.titleCase(repo);

        return generate.folder(
            {
                input: dir,
                output: outputDir,
                title: title,
                description: options.intro,
                github: githubID,
                generator: options.generator,
                theme: options.theme
            }
        );
    })
    .then(function(output) {
        console.log("Successfuly built !");
    }, logError)
    .then(_.constant(outputDir));
});

prog
.command('serve [source_dir]')
.description('Build then serve a gitbook from a directory')
.option('-p, --port <port>', 'Port for server to listen on', 4000)
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-g, --generator <name>', 'Change generator, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(function(dir, options) {
    buildFunc(dir, options)
    .then(function(outputDir) {
        console.log();
        console.log('Starting server ...');
        return utils.serveDir(outputDir, options.port)
        .fail(logError);
    })
    .then(function() {
        console.log('Serving book on http://localhost:'+options.port);
        console.log();
        console.log('Press CTRL+C to quit ...');
    });
});

// Parse and fallback to help if no args
if(_.isEmpty(prog.parse(process.argv).args) && process.argv.length === 2) {
    prog.help();
}
<commit_msg>Change option for changing generator to format<commit_after>#! /usr/bin/env node

// Requires
var Q = require('q');
var _ = require('lodash');
var path = require('path');
var prog = require('commander');

var fs = require('fs');

var pkg = require('../package.json');
var generate = require("../lib/generate");
var parse = require("../lib/parse");
var generators = require("../lib/generate").generators;

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

var logError = function(err) {
    console.log(err.message || err);
    return Q.reject(err);
};

// General options
prog
.version(pkg.version)
.option('-d, --dir <source_directory>', 'Source directory of book, containing Markdown files');

var buildFunc;
prog
.command('build [source_dir]')
.description('Build a gitbook from a directory')
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-i, --intro <intro>', 'Description of the book to generate')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(buildFunc = function(dir, options) {
    dir = dir || process.cwd();
    outputDir = options.output || path.join(dir, '_book');

    console.log('Starting build ...');
    // Get repo's URL
    return utils.gitURL(dir)
    .then(function(url) {
        // Get ID of repo
        return utils.githubID(url);
    }, function(err) {
        return null;
    })
    .then(function(repoID) {
        var githubID = options.github || repoID;

        if(!githubID) {
            throw new Error('Needs a githubID (username/repo). Either set repo origin to a github repo or use the -g flag');
        }

        var parts = githubID.split('/', 2);
        var user = parts[0], repo = parts[1];

        var title = options.title || utils.titleCase(repo);

        return generate.folder(
            {
                input: dir,
                output: outputDir,
                title: title,
                description: options.intro,
                github: githubID,
                generator: options.format,
                theme: options.theme
            }
        );
    })
    .then(function(output) {
        console.log("Successfuly built !");
    }, logError)
    .then(_.constant(outputDir));
});

prog
.command('serve [source_dir]')
.description('Build then serve a gitbook from a directory')
.option('-p, --port <port>', 'Port for server to listen on', 4000)
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(function(dir, options) {
    buildFunc(dir, options)
    .then(function(outputDir) {
        console.log();
        console.log('Starting server ...');
        return utils.serveDir(outputDir, options.port)
        .fail(logError);
    })
    .then(function() {
        console.log('Serving book on http://localhost:'+options.port);
        console.log();
        console.log('Press CTRL+C to quit ...');
    });
});

// Parse and fallback to help if no args
if(_.isEmpty(prog.parse(process.argv).args) && process.argv.length === 2) {
    prog.help();
}
<|endoftext|>


<commit_before>// Karma configuration

// base path, that will be used to resolve files and exclude
basePath = '';

// list of files / patterns to load in the browser
files = [
  JASMINE,
  JASMINE_ADAPTER,
  'test/components/angular/angular.js',
  'test/components/angular-mocks/angular-mocks.js',

  'src/scripts/*.js',
  'src/scripts/**/*.js',

  'test/spec/**/*.js'
];

// list of files to exclude
exclude = [];

// test results reporter to use
// possible values: dots || progress || growl
reporters = ['progress'];

// web server port
port = 8080;

// cli runner port
runnerPort = 9100;

// enable / disable colors in the output (reporters and logs)
colors = true;

// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;

// enable / disable watching file and executing tests whenever any file changes
autoWatch = true;

// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['Chrome'];

// If browser does not capture in given timeout [ms], kill it
captureTimeout = 5000;

// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;
<commit_msg>test: Set log level to LOG_DEBUG<commit_after>// Karma configuration

// base path, that will be used to resolve files and exclude
basePath = '';

// list of files / patterns to load in the browser
files = [
  JASMINE,
  JASMINE_ADAPTER,
  'test/components/angular/angular.js',
  'test/components/angular-mocks/angular-mocks.js',

  'src/scripts/*.js',
  'src/scripts/**/*.js',

  'test/spec/**/*.js'
];

// list of files to exclude
exclude = [];

// test results reporter to use
// possible values: dots || progress || growl
reporters = ['progress'];

// web server port
port = 8080;

// cli runner port
runnerPort = 9100;

// enable / disable colors in the output (reporters and logs)
colors = true;

// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_DEBUG;

// enable / disable watching file and executing tests whenever any file changes
autoWatch = true;

// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['Chrome'];

// If browser does not capture in given timeout [ms], kill it
captureTimeout = 5000;

// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;
<|endoftext|>


<commit_before>var moment = require('moment');

var SimpleDateFormat = function(pattern) {
  this.pattern = pattern;
  this.regex = /('[^']*')|(G+|y+|Y+|M+|L+|w+|W+|D+|d+|F+|E+|u+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

  this.TYPES = {
    TEXT: "TEXT",
    NUMBER: "NUMBER",
    YEAR: "YEAR",
    MONTH: "MONTH"
  };
};

SimpleDateFormat.prototype.format = function(date) {
  var d = moment(date);
  var p = this.pattern;
  var matches;
  while((matches = this.regex.exec(p))) {
    var subPattern = matches[2];

    if (subPattern) {
      return this._formatField(this._fieldWithType(d, subPattern[0], subPattern.length));
    }

    p = p.substr(matches.index + matches[0].length);
  }
  return "";
}

moment.prototype.weekInMonth = function() {
  var first = moment(this).startOf("month").week();
  var current = this.week();
  if (first > current) first = first - moment(this).startOf("month").weeksInYear();
  return current - first + 1;
}

moment.prototype.dayOfWeekInMonth = function() {
  var c = 1;
  var m = moment(this);
  while ((m = moment(m).date(m.date() - 7)).month() === this.month()) c++;
  return c;
}

moment.prototype.dayNameInWeek = function() {
  return moment.weekdays()[this.weekday()];
}

moment.prototype.shortDayNameInWeek = function() {
  return moment.weekdaysShort()[this.weekday()];
}

SimpleDateFormat.prototype._fieldWithType = function(d, letter, length) {
  switch (letter) {
    case "G":
      return this._asText("AD");
    case "y":
      return this._asYear(d.year(), length);
    case "Y":
      return this._asYear(d.weekYear(), length);
    case "M":
      return this._asMonth(d.month(), length);
    case "L":
      return this._asMonth(d.month(), length);
    case "w":
      return this._asNumber(d.week(), length);
    case "W":
      return this._asNumber(d.weekInMonth(), length);
    case "D":
      return this._asNumber(d.dayOfYear(), length);
    case "d":
      return this._asNumber(d.date(), length);
    case "F":
      return this._asNumber(d.dayOfWeekInMonth(), length);
    case "E":
      if (length <= 3) return this._asText(d.shortDayNameInWeek());
      else return this._asText(d.dayNameInWeek());
    case "u":
      return this._asNumber(d.isoWeekday(), length);
  }
  throw "Unexpected pattern letter: " + letter;
}

SimpleDateFormat.prototype._asText = function(v) {
  return { value: v, type: this.TYPES.TEXT };
}

SimpleDateFormat.prototype._asNumber = function(v, l) {
  return { value: v, length: l, type: this.TYPES.NUMBER };
}

SimpleDateFormat.prototype._asMonth = function(v, l) {
  return { value: v, length: l, type: this.TYPES.MONTH };
}

SimpleDateFormat.prototype._asYear = function(v, l) {
  return { value: v, length: l, type: this.TYPES.YEAR };
}

SimpleDateFormat.prototype._formatField = function(field) {
  switch (field.type) {
    case this.TYPES.YEAR:
      if (field.length === 2) return ("" + field.value).substr(2);
      else return this._padWithZeroes("" + field.value, field.length);
    case this.TYPES.MONTH:
      if (field.length <= 2) return this._padWithZeroes("" + (field.value + 1), field.length);
      else if (field.length === 3) return moment.monthsShort()[field.value];
      else return moment.months()[field.value];
    case this.TYPES.NUMBER:
      return this._padWithZeroes("" + field.value, field.length);
    case this.TYPES.TEXT:
      return field.value;
  }
  throw "Unexpected field type: " + field.type;
}

SimpleDateFormat.prototype._padWithZeroes = function(str, length) {
  var s = str;
  while(s.length < length) s = "0" + s;
  return s;
}

module.exports.SimpleDateFormat = SimpleDateFormat;
<commit_msg>Combines date patterns.<commit_after>var moment = require('moment');

var SimpleDateFormat = function(pattern) {
  this.pattern = pattern;
  this.regex = /('[^']*')|(G+|y+|Y+|M+|L+|w+|W+|D+|d+|F+|E+|u+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

  this.TYPES = {
    TEXT: "TEXT",
    NUMBER: "NUMBER",
    YEAR: "YEAR",
    MONTH: "MONTH"
  };
};

SimpleDateFormat.prototype.format = function(date) {
  var formattedString = "";
  var d = moment(date);
  var p = this.pattern;
  var matches;
  while((matches = this.regex.exec(p))) {
    var quotedString = matches[1];
    var subPattern = matches[2];
    var nonPatternLetters = matches[3];
    var otherCharacters = matches[4];

    if (quotedString) {
			if (quotedString == "''") {
			  formattedString += "'";
			} else {
			  formattedString += quotedString.substring(1, quotedString.length - 1);
			}
		} else if (nonPatternLetters) {
      // swallow non pattern letters
    } else if (otherCharacters) {
      formattedString += otherCharacters;
    } else if (subPattern) {
      formattedString += this._formatField(this._fieldWithType(d, subPattern[0], subPattern.length));
    }

    p = p.substr(matches.index + matches[0].length);
  }
  return formattedString;
}

moment.prototype.weekInMonth = function() {
  var first = moment(this).startOf("month").week();
  var current = this.week();
  if (first > current) first = first - moment(this).startOf("month").weeksInYear();
  return current - first + 1;
}

moment.prototype.dayOfWeekInMonth = function() {
  var c = 1;
  var m = moment(this);
  while ((m = moment(m).date(m.date() - 7)).month() === this.month()) c++;
  return c;
}

moment.prototype.dayNameInWeek = function() {
  return moment.weekdays()[this.weekday()];
}

moment.prototype.shortDayNameInWeek = function() {
  return moment.weekdaysShort()[this.weekday()];
}

SimpleDateFormat.prototype._fieldWithType = function(d, letter, length) {
  switch (letter) {
    case "G":
      return this._asText("AD");
    case "y":
      return this._asYear(d.year(), length);
    case "Y":
      return this._asYear(d.weekYear(), length);
    case "M":
      return this._asMonth(d.month(), length);
    case "L":
      return this._asMonth(d.month(), length);
    case "w":
      return this._asNumber(d.week(), length);
    case "W":
      return this._asNumber(d.weekInMonth(), length);
    case "D":
      return this._asNumber(d.dayOfYear(), length);
    case "d":
      return this._asNumber(d.date(), length);
    case "F":
      return this._asNumber(d.dayOfWeekInMonth(), length);
    case "E":
      if (length <= 3) return this._asText(d.shortDayNameInWeek());
      else return this._asText(d.dayNameInWeek());
    case "u":
      return this._asNumber(d.isoWeekday(), length);
  }
  throw "Unexpected pattern letter: " + letter;
}

SimpleDateFormat.prototype._asText = function(v) {
  return { value: v, type: this.TYPES.TEXT };
}

SimpleDateFormat.prototype._asNumber = function(v, l) {
  return { value: v, length: l, type: this.TYPES.NUMBER };
}

SimpleDateFormat.prototype._asMonth = function(v, l) {
  return { value: v, length: l, type: this.TYPES.MONTH };
}

SimpleDateFormat.prototype._asYear = function(v, l) {
  return { value: v, length: l, type: this.TYPES.YEAR };
}

SimpleDateFormat.prototype._formatField = function(field) {
  switch (field.type) {
    case this.TYPES.YEAR:
      if (field.length === 2) return ("" + field.value).substr(2);
      else return this._padWithZeroes("" + field.value, field.length);
    case this.TYPES.MONTH:
      if (field.length <= 2) return this._padWithZeroes("" + (field.value + 1), field.length);
      else if (field.length === 3) return moment.monthsShort()[field.value];
      else return moment.months()[field.value];
    case this.TYPES.NUMBER:
      return this._padWithZeroes("" + field.value, field.length);
    case this.TYPES.TEXT:
      return field.value;
  }
  throw "Unexpected field type: " + field.type;
}

SimpleDateFormat.prototype._padWithZeroes = function(str, length) {
  var s = str;
  while(s.length < length) s = "0" + s;
  return s;
}

module.exports.SimpleDateFormat = SimpleDateFormat;
<|endoftext|>


<commit_before>const sign = require('koa-jsonwebtoken').sign
const secret = require('../../middleware/authentication').secret
const User = require('./model')
const log = require('../../modules/logger')('arxivum:users:authenticate')

async function authenticate (ctx) {
  const {email, password} = ctx.request.body

  try {
    const user = await User.findOne({email})
      .select('email password admin')
    if (!user) {
      throw new Error('UserDoesNotExist')
    }
    if (await user.checkPassword(password)) {
      const token = {
        id: user._id,
        email: user.email,
        admin: user.admin
      }
      ctx.body = {
        token: sign(token, secret, { expiresIn: '7d' }),
        user_id: user._id
      }
    } else {
      throw new Error('IncorrectPassword')
    }
  } catch (e) {
    if (e.message === 'IncorrectPassword') {
      ctx.throw(401, 'Incorrect credentials')
    }
    if (e.message === 'UserDoesNotExist') {
      ctx.throw(401, 'Incorrect credentials')
    }
    log(e)
    throw new Error()
  }
}

module.exports = authenticate
<commit_msg>changed auth strategy<commit_after>const sign = require('koa-jsonwebtoken').sign
const secret = require('../../middleware/authentication').secret
const User = require('./model')
const log = require('../../modules/logger')('arxivum:users:authenticate')

async function authenticate (ctx) {
  const {email, password} = ctx.request.body

  try {
    const user = await User.findOne({email})
      .select('email password admin')
    if (!user) {
      throw new Error('UserDoesNotExist')
    }
    if (await user.checkPassword(password)) {
      delete user.password
      const token = {
        id: user._id,
        admin: user.admin
      }
      ctx.body = {
        token: sign(token, secret, { expiresIn: '7d' }),
        id: user._id,
        email: user.email,
        admin: user.admin
      }
    } else {
      throw new Error('IncorrectPassword')
    }
  } catch (e) {
    if (e.message === 'IncorrectPassword') {
      ctx.throw(401, 'Incorrect credentials')
    }
    if (e.message === 'UserDoesNotExist') {
      ctx.throw(401, 'Incorrect credentials')
    }
    log(e)
    throw new Error()
  }
}

module.exports = authenticate
<|endoftext|>


<commit_before>module.exports = config => {
    config.set({
        autoWatch: true,
        singleRun: true,
        browsers: ["Chrome"],
        files: [
            "dist/karma/index.js",
        ],
        frameworks: [
            "mocha",
        ],
        plugins: [
            "karma-chrome-launcher",
            "karma-firefox-launcher",
            "karma-spec-reporter",
            "karma-mocha",
        ],
        reporters: ["spec"],
        client: {
            mocha: {
                timeout: 10000
            }
        }
    });
};
<commit_msg>add Firefox in karma's target browsers<commit_after>module.exports = config => {
    config.set({
        autoWatch: true,
        singleRun: true,
        browsers: ["Chrome", "Firefox"],
        files: [
            "dist/karma/index.js",
        ],
        frameworks: [
            "mocha",
        ],
        plugins: [
            "karma-chrome-launcher",
            "karma-firefox-launcher",
            "karma-spec-reporter",
            "karma-mocha",
        ],
        reporters: ["spec"],
        client: {
            mocha: {
                timeout: 10000
            }
        }
    });
};
<|endoftext|>


<commit_before>'use strict';

var User = require('../models/users');
var Poll = require('../models/polls');
var Choice = require('../models/choices');

//var path = __dirname;
var path = process.cwd();
//var ClickHandler = require(path + '/app/controllers/clickHandler.server.js');
var PollHandler = require(path + '/app/controllers/pollHandler.server.js');

module.exports = function (app, passport) {

	function isLoggedIn (req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		} else {
			res.redirect('/login');
		}
	}

	//var clickHandler = new ClickHandler();
	var pollHandler = new PollHandler();

	app.route('/')
		.get(function (req, res) {
			console.log(req.params);
			Poll.find({}, {}, { sort: { 'created_at' : -1 } }, function(err, poll) {
				console.log(poll);
				res.render('index',{poll:poll});
			})
		});

	app.route('/login')
		.get(function (req, res) {
			console.log(req.params);
			Poll.find({}, {}, { sort: { 'created_at' : -1 } }, function(err, poll) {
				console.log(poll);
			res.render('login',{poll:poll, layout:'loggedout'});
			})
		});

	/*app.route('/poll')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				res.render('poll');
			})
		});*/

	app.route('/logout')
		.get(function (req, res) {
			req.logout();
			res.redirect('/login');
		});

	app.route('/profile/:id')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				console.log(user);
				res.render('profile',{user:user, time:Date.now()});
			})
		});

	app.route('/createpoll')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				res.render('createpoll');
			})
		});

	app.route('/poll')
		.post(isLoggedIn, function (req, res) {
			console.log(req.body);
			var newpoll = {question : req.body.question};
			newpoll.choices = {};
			var choices = req.body.choices.split(',');
			choices.forEach(function(item) {
				newpoll.choices[item]=0;
			})
			newpoll.creator = req.user._id;
			console.log(newpoll);
			Poll.create(newpoll, function(err, poll) {
				if (err) {
					console.log(err)
				}
			User.findById(req.user._id, function(err, user){
				console.log(user);
				user.polls.push(poll._id);
    			user.save();
				res.redirect('/poll/' + poll._id)
			});
		});

	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.render("profile",{user:req.user});
		});

	app.route('/poll/:id')
		.get(function (req, res) {
			Poll.findById(req.params.id, function(err, poll){
				console.log(poll.choices);
				//poll.poll.choices.count++;
				res.render("poll",{poll:poll});
			})
		})
		.delete(function (req, res) {
			console.log(req.params);
			Poll.findOne({"_id":req.params.id}, function(err, poll){
				console.log(poll);
				if (poll) {
					poll.remove();
				};
			User.findById(req.user._id, function(err, user){
				console.log(user);
				var index = user.polls.indexOf(req.params.id);
				console.log(index);
				if (index > -1) {
    				user.polls.splice(index, 1);
    				user.save();
				}
				res.redirect('/profile');
			})
			})
		})
		.post(function (req, res) {
			console.log(req.body);
			if (req.body.choice) {
				Poll.findOne({"_id": req.params.id}, function(err, poll) {
					poll.choices[req.body.choice]++;
					console.log(poll);
					poll.markModified('choices');
					poll.save();
					res.redirect('/poll/' + poll._id);
				})
			}
		});

	/*app.route('/poll/:id/:choice')
		.post(function (req, res) {
			Poll.findOne({"_id":req.params.id}, function(err, poll){
				Choice.findOneAndUpdate({"_id": req.params.choice}, {$inc : {'count' : 1}});
				res.redirect('/poll');
				})
				//console.log(poll.poll.choices);
			});*/

	app.route('/auth/github')
		.get(passport.authenticate('github'));

	app.route('/auth/github/callback')
		.get(passport.authenticate('github', {
			successRedirect: '/',
			failureRedirect: '/login'
		}));

	app.route('/auth/twitter')
		.get(passport.authenticate('twitter'));

	app.route('/auth/twitter/callback')
		.get(passport.authenticate('twitter', {
			successRedirect: '/',
			failureRedirect: '/login'
		}));

	/*app.route('/api/:id/clicks')
		.get(isLoggedIn, clickHandler.getClicks)
		.post(isLoggedIn, clickHandler.addClick)
		.delete(isLoggedIn, clickHandler.resetClicks);*/

//	app.route('/createpoll')
	//	.post(pollHandler.addPoll);

	app.route('/success')
		.get(function (req, res) {
		//console.dir(req.body);
		res.render('success');
		});
//agasg

};
<commit_msg>displaying polls<commit_after>'use strict';

var User = require('../models/users');
var Poll = require('../models/polls');
var Choice = require('../models/choices');

//var path = __dirname;
var path = process.cwd();
//var ClickHandler = require(path + '/app/controllers/clickHandler.server.js');
var PollHandler = require(path + '/app/controllers/pollHandler.server.js');

module.exports = function (app, passport) {

	function isLoggedIn (req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		} else {
			res.redirect('/login');
		}
	}

	//var clickHandler = new ClickHandler();
	var pollHandler = new PollHandler();

	app.route('/')
		.get(function (req, res) {
			console.log(req.params);
			Poll.find({}, {}, { sort: { 'created_at' : -1 } }, function(err, poll) {
				console.log(poll);
				res.render('index',{poll:poll});
			})
		});

	app.route('/login')
		.get(function (req, res) {
			console.log(req.params);
			Poll.find({}, {}, { sort: { 'created_at' : -1 } }, function(err, poll) {
				console.log(poll);
			res.render('login',{poll:poll, layout:'loggedout'});
			})
		});

	/*app.route('/poll')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				res.render('poll');
			})
		});*/

	app.route('/logout')
		.get(function (req, res) {
			req.logout();
			res.redirect('/login');
		});

	app.route('/profile/:id')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				console.log(user);
				res.render('profile',{user:user, time:Date.now()});
			})
		});

	app.route('/createpoll')
		.get(isLoggedIn, function (req, res) {
			console.log(req.params);
			User.findOne({"twitter.username":req.params.id}, function(err, user) {
				res.render('createpoll');
			})
		});

	app.route('/poll')
		.post(isLoggedIn, function (req, res) {
			console.log(req.body);
			var newpoll = {question : req.body.question};
			newpoll.choices = {};
			var choices = req.body.choices.split(',');
			choices.forEach(function(item) {
				newpoll.choices[item]=0;
			})
			newpoll.creator = req.user._id;
			console.log(newpoll);
			Poll.create(newpoll, function(err, poll) {
				if (err) {
					console.log(err)
				}
			User.findById(req.user._id, function(err, user){
				console.log(user);
				user.polls.push(poll._id);
    			user.save();
				res.redirect('/poll/' + poll._id)
			});
			});
		});

	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.render("profile",{user:req.user});
		});

	app.route('/poll/:id')
		.get(function (req, res) {
			Poll.findById(req.params.id, function(err, poll){
				console.log(poll.choices);
				//poll.poll.choices.count++;
				res.render("poll",{poll:poll});
			})
		})
		.delete(function (req, res) {
			console.log(req.params);
			Poll.findOne({"_id":req.params.id}, function(err, poll){
				console.log(poll);
				if (poll) {
					poll.remove();
				};
			User.findById(req.user._id, function(err, user){
				console.log(user);
				var index = user.polls.indexOf(req.params.id);
				console.log(index);
				if (index > -1) {
    				user.polls.splice(index, 1);
    				user.save();
				}
				res.redirect('/profile');
			})
			})
		})
		.post(function (req, res) {
			console.log(req.body);
			if (req.body.choice) {
				Poll.findOne({"_id": req.params.id}, function(err, poll) {
					poll.choices[req.body.choice]++;
					console.log(poll);
					poll.markModified('choices');
					poll.save();
					res.redirect('/poll/' + poll._id);
				})
			}
		});

	/*app.route('/poll/:id/:choice')
		.post(function (req, res) {
			Poll.findOne({"_id":req.params.id}, function(err, poll){
				Choice.findOneAndUpdate({"_id": req.params.choice}, {$inc : {'count' : 1}});
				res.redirect('/poll');
				})
				//console.log(poll.poll.choices);
			});*/

	app.route('/auth/github')
		.get(passport.authenticate('github'));

	app.route('/auth/github/callback')
		.get(passport.authenticate('github', {
			successRedirect: '/',
			failureRedirect: '/login'
		}));

	app.route('/auth/twitter')
		.get(passport.authenticate('twitter'));

	app.route('/auth/twitter/callback')
		.get(passport.authenticate('twitter', {
			successRedirect: '/',
			failureRedirect: '/login'
		}));

	/*app.route('/api/:id/clicks')
		.get(isLoggedIn, clickHandler.getClicks)
		.post(isLoggedIn, clickHandler.addClick)
		.delete(isLoggedIn, clickHandler.resetClicks);*/

//	app.route('/createpoll')
	//	.post(pollHandler.addPoll);

	app.route('/success')
		.get(function (req, res) {
		//console.dir(req.body);
		res.render('success');
		});
//agasg

};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var jformatter = require('jformatter');

function showUsage() {
    console.log('Usage:');
    console.log('   jformatter file.js');
    console.log();
    process.exit(1);
}

if (process.argv.length < 2) {
    showUsage();
}

var targetFile = null;
process.argv.forEach(function(arg, index) {
    if (index === 2) {
        targetFile = arg;
    }
});

if (typeof targetFile !== 'string') {
    showUsage();
    process.exit(1);
}

var getConfig = function (targetFile) {
    var config = {};
    var path = require('path');
    var fs = require('fs');
    var absolutePath = path.resolve(targetFile);
    var currentDir = path.dirname(absolutePath);
    var configPath = null;

    while (currentDir !== '/') {
        if (fs.existsSync(currentDir + '/.jformatterrc')) {
            configPath = currentDir + '/.jformatterrc';
            break;
        }
        currentDir = path.dirname(currentDir);
    }

    if (configPath) {
        config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
    }
    return config ? config : {};
};

console.log(jformatter.formatFile(targetFile, getConfig(targetFile)));
<commit_msg>update comment<commit_after>#!/usr/bin/env node

var jformatter = require('jformatter');

function showUsage() {
    console.log('Usage:');
    console.log('   jformatter file.js');
    console.log();
    process.exit(1);
}

if (process.argv.length < 2) {
    showUsage();
}

var targetFile = null;
process.argv.forEach(function(arg, index) {
    if (index === 2) {
        targetFile = arg;
    }
});

if (typeof targetFile !== 'string') {
    showUsage();
    process.exit(1);
}

/**
 * 递归寻找配置文件
 * @param {string} targetFile
 * @returns {Object}
 */
var getConfig = function (targetFile) {
    var config = {};
    var path = require('path');
    var fs = require('fs');
    var absolutePath = path.resolve(targetFile);
    var currentDir = path.dirname(absolutePath);
    var configPath = null;

    while (currentDir !== '/') {
        if (fs.existsSync(currentDir + '/.jformatterrc')) {
            configPath = currentDir + '/.jformatterrc';
            break;
        }
        currentDir = path.dirname(currentDir);
    }

    if (configPath) {
        config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
    }
    return config ? config : {};
};

console.log(jformatter.formatFile(targetFile, getConfig(targetFile)));
<|endoftext|>