<commit_before>define(["pat-registry", "pat-clone"], function(registry) {

    describe("pat-clone", function() {
        beforeEach(function() {
            $("div#lab").remove();
            $("
", {id: "lab"}).appendTo(document.body);
        });
        afterEach(function() {
            $("#lab").remove();
        });

        it("clones the node's first child when .add-clone is clicked and places the clone after the cloned element", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Clone Me
' +
                '    <button class="add-clone">Clone!</button>' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            // Try now a different variation with the trigger inside the cloned
            // element.
            $lab.empty().html(
                '
' +
                '
' +
                '       <button class="add-clone">Clone!</button>' +
                '
' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);
            $lab.find('.add-clone:last').click();
            expect($('div.item').length).toBe(3);
            $lab.find('.add-clone:first').click();
            expect($('div.item').length).toBe(4);
        });

        it("allows the trigger element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Clone Me
' +
                '    <button class="add-clone">Will not Clone!</button>' +
                '    <button class="real-add-clone">Clone!</button>' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(1);
            $lab.find('.real-add-clone').click();
            expect($('div.item').length).toBe(2);
        });

        it("allows the cloned element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Original item
' +
                '
Clone template
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(2);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(3);
            expect($('div.item:last').text()).toBe('Clone template');
            expect($("div.item:contains('Clone template')").length).toBe(2);
        });

        it("will automatically increment any number in name and value attributes.", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Family member #{1}
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('p.legend').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('p.legend').length).toBe(2);
            expect($('p.legend:last').attr('name')).toBe('item-2');

            $lab.find('.add-clone').click();
            expect($('p.legend').length).toBe(3);
            expect($('p.legend:last').attr('name')).toBe('item-3');
        });

        it("will remove a clone when .remove-clone inside the clone is clicked.", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
<button type="button" class="remove-clone">Remove</button>
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            $lab.find('.remove-clone:last').click();
            expect($('div.item').length).toBe(1);

            $lab.find('.remove-clone').click();
            expect($('div.item').length).toBe(0);
        });

        it("allows the remove element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
<button type="button" class="custom-remove-class">Remove</button>
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            $lab.find('.custom-remove-class:last').click();
            expect($('div.item').length).toBe(1);

            $lab.find('.custom-remove-class').click();
            expect($('div.item').length).toBe(0);
        });
    });
});
<commit_msg>Fix failing test for pat-clone.<commit_after>define(["pat-registry", "pat-clone"], function(registry) {

    describe("pat-clone", function() {
        beforeEach(function() {
            $("div#lab").remove();
            $("
", {id: "lab"}).appendTo(document.body);
        });
        afterEach(function() {
            $("#lab").remove();
        });

        it("clones the node's first child when .add-clone is clicked and places the clone after the cloned element", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Clone Me
' +
                '    <button class="add-clone">Clone!</button>' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            // Try now a different variation with the trigger inside the cloned
            // element.
            $lab.empty().html(
                '
' +
                '
' +
                '       <button class="add-clone">Clone!</button>' +
                '
' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);
            $lab.find('.add-clone:last').click();
            expect($('div.item').length).toBe(3);
            $lab.find('.add-clone:first').click();
            expect($('div.item').length).toBe(4);
        });

        it("allows the trigger element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Clone Me
' +
                '    <button class="add-clone">Will not Clone!</button>' +
                '    <button class="real-add-clone">Clone!</button>' +
                '
');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(1);
            $lab.find('.real-add-clone').click();
            expect($('div.item').length).toBe(2);
        });

        it("allows the cloned element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Original item
' +
                '
Clone template
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(2);
            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(3);
            expect($('div.item:last').text()).toBe('Clone template');
            expect($("div.item:contains('Clone template')").length).toBe(2);
        });

        it("will automatically increment any number in name and value attributes.", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
Family member #{1}
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('p.legend').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('p.legend').length).toBe(2);
            expect($('p.legend:last').attr('name')).toBe('item-2');

            $lab.find('.add-clone').click();
            expect($('p.legend').length).toBe(3);
            expect($('p.legend:last').attr('name')).toBe('item-3');
        });

        it("will remove a clone when .remove-clone inside the clone is clicked.", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
<button type="button" class="remove-clone">Remove</button>
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            $lab.find('.remove-clone:last').click();
            expect($('div.item').length).toBe(1);

            $lab.find('.remove-clone').click();
            expect($('div.item').length).toBe(0);
        });

        it("allows the remove element to be configured", function() {
            var $lab = $('#lab');
            $lab.html(
                '
' +
                '
<button type="button" class="custom-remove-class">Remove</button>
' +
                '
' +
                '<button class="add-clone">Clone!</button>');
            registry.scan($lab);
            expect($('div.item').length).toBe(1);

            $lab.find('.add-clone').click();
            expect($('div.item').length).toBe(2);

            $lab.find('.custom-remove-class:last').click();
            expect($('div.item').length).toBe(1);

            $lab.find('.custom-remove-class').click();
            expect($('div.item').length).toBe(0);
        });
    });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
/* jshint node: true */

/*
 * 46elks samples: Wall of text messages
 * ===
 *
 * This example introduces you with how to receive text messages to a phone number allocated
 * to you and store them. The scenario is that a web portal can be displayed on a wall to show
 * the most recent text messages which can be great for announcements and notices or various
 * kinds. The same idea can be expanded further to provide all kinds of logging, highlighted
 * notices, etc.
 *
 * Setup
 * ---
 *
 * Give this example's process write access to its working directory for simple data storage.
 * Get a new random secret key and set it as the `key` variable.
 * Set the `sms_url` value for the allocated numbers you are going to use to match the endpoint
 *   provided by this example along with the key (http://example.com/callback/newsms?key=abc123).
 */

var core = require(__dirname + '/_core.js');
var fs = require('fs');

var key = 'abc123'; // This is the key that should be unique.

var knownPeople = { // This object is used for nicer output formatting.
  '+46704508449': 'Johannes L', // Each pair consists of a phone number and a name.
  '+46701234124': 'Mike Douglas'
};

function getStamp() {
  // You might want to use a seperate timestamp for each day or hour or whatever else.
  // One is added to the month as January is the 0th month in JavaScript.
  var d = new Date();
  return d.getUTCFullYear() + '.' + (d.getUTCMonth() + 1);
}

core.listen('/callback/newsms?key=' + key, function listener(page) {

  // Make sure the POST data looks sane before doing anything.
  var fields = [ 'from', 'to', 'message' ];
  for (var i = 0; i < fields.length; i++) {
    var field = fields[i];
    if (typeof page.post[field] === 'undefined') {
      console.error('No "' + field + '" key in the POST data.');
      return;
    }
  }

  // Get the file to store the message in.
  var file = __dirname + '/textwall.' + getStamp() + '.txt';
  // Process the data to be stored.
  var line = page.post.from + ' ' +
    new Buffer(page.post.message, 'utf8').toString('base64') + '\n';
  // Do the actual storing. This should be done async and cached, but this will do for the example.
  fs.appendFileSync(file, line, { encoding: 'utf8', mode: 0664 });

});

core.listen('/wall', function listener(page) {

  // Load the history. This should already be cached, but this will do for the example.
  var file = __dirname + '/textwall.' + getStamp() + '.txt';
  var lines = [];
  try {
    lines = fs.readFileSync(file, { encoding: 'utf8' }).split('\n');
  } catch (err) {
    if (err.code === 'ENOENT') {
      // File not found. Carry on.
    } else {
      throw err;
    }
  }

  // Throw the beginning of the HTML at the requesting client.
  page.write('<!DOCTYPE html>\n<title>Text wall example for 46elks</title><meta http-equiv="refresh" content="5">
SMS text wall
');

  // Output each line to the client.
  for (var i = lines.length - 1; i >= 0; i--) {
    var line = lines[i].trim();

    // Skip empty lines.
    if (line === '') continue;

    // Parse the original sender.
    var from = line.split(' ')[0];
    // Check if we know that person. If we do, grab his/her name.
    if (typeof knownPeople[from] !== 'undefined') from = knownPeople[from];
    // Parse the original message.
    var message = new Buffer(line.split(' ')[1], 'base64').toString('utf8');

    page.write('
' + message + ' ' + from + '
');
  }

  // Wrap up.
  page.write('\n');

});
<commit_msg>Rename the heading on example four<commit_after>#!/usr/bin/env node
/* jshint node: true */

/*
 * 46elks samples: Wall of text messages
 * ===
 *
 * This example introduces you with how to receive text messages to a phone number allocated
 * to you and store them. The scenario is that a web portal can be displayed on a wall to show
 * the most recent text messages which can be great for announcements and notices or various
 * kinds. The same idea can be expanded further to provide all kinds of logging, highlighted
 * notices, etc.
 *
 * Setup
 * ---
 *
 * Give this example's process write access to its working directory for simple data storage.
 * Get a new random secret key and set it as the `key` variable.
 * Set the `sms_url` value for the allocated numbers you are going to use to match the endpoint
 *   provided by this example along with the key (http://example.com/callback/newsms?key=abc123).
 */

var core = require(__dirname + '/_core.js');
var fs = require('fs');

var key = 'abc123'; // This is the key that should be unique.

var knownPeople = { // This object is used for nicer output formatting.
  '+46704508449': 'Johannes L', // Each pair consists of a phone number and a name.
  '+46701234124': 'Mike Douglas'
};

function getStamp() {
  // You might want to use a seperate timestamp for each day or hour or whatever else.
  // One is added to the month as January is the 0th month in JavaScript.
  var d = new Date();
  return d.getUTCFullYear() + '.' + (d.getUTCMonth() + 1);
}

core.listen('/callback/newsms?key=' + key, function listener(page) {

  // Make sure the POST data looks sane before doing anything.
  var fields = [ 'from', 'to', 'message' ];
  for (var i = 0; i < fields.length; i++) {
    var field = fields[i];
    if (typeof page.post[field] === 'undefined') {
      console.error('No "' + field + '" key in the POST data.');
      return;
    }
  }

  // Get the file to store the message in.
  var file = __dirname + '/textwall.' + getStamp() + '.txt';
  // Process the data to be stored.
  var line = page.post.from + ' ' +
    new Buffer(page.post.message, 'utf8').toString('base64') + '\n';
  // Do the actual storing. This should be done async and cached, but this will do for the example.
  fs.appendFileSync(file, line, { encoding: 'utf8', mode: 0664 });

});

core.listen('/wall', function listener(page) {

  // Load the history. This should already be cached, but this will do for the example.
  var file = __dirname + '/textwall.' + getStamp() + '.txt';
  var lines = [];
  try {
    lines = fs.readFileSync(file, { encoding: 'utf8' }).split('\n');
  } catch (err) {
    if (err.code === 'ENOENT') {
      // File not found. Carry on.
    } else {
      throw err;
    }
  }

  // Throw the beginning of the HTML at the requesting client.
  page.write('<!DOCTYPE html>\n<title>Text wall example for 46elks</title><meta http-equiv="refresh" content="5">
Text wall example
');

  // Output each line to the client.
  for (var i = lines.length - 1; i >= 0; i--) {
    var line = lines[i].trim();

    // Skip empty lines.
    if (line === '') continue;

    // Parse the original sender.
    var from = line.split(' ')[0];
    // Check if we know that person. If we do, grab his/her name.
    if (typeof knownPeople[from] !== 'undefined') from = knownPeople[from];
    // Parse the original message.
    var message = new Buffer(line.split(' ')[1], 'base64').toString('utf8');

    page.write('
' + message + ' ' + from + '
');
  }

  // Wrap up.
  page.write('\n');

});
<|endoftext|>


<commit_before>'use strict';

var util = require('../../common');

/**
 * Monitors the references attached to a RecordSet and maintains a cache of
 * current snapshots (inside RecordList below). Any time there is an update, this calls
 * RecordSet.handler() to invoke the correct event types (child_added, child_removed, value, et al)
 * on the RecordSet object.
 *
 * @param parentRec
 * @constructor
 */
function RecordSetEventManager(parentRec) {
  var pm = parentRec.getPathManager();
  this.masterRef = pm.first().ref();
  this.url = this.masterRef.toString();
  this.recList = new RecordList(parentRec, this.url);
  this.running = false;
}

RecordSetEventManager.prototype = {
  start: function() {
    if( !this.running ) {
      util.log('RecordSetEventManager: Loading normalized records from master list %s', this.url);
      this.running = true;
      this.masterRef.on('child_added',   this._add,    this);
      this.masterRef.on('child_removed', this._remove, this);
      this.masterRef.on('child_moved',   this._move,   this);
      /**
       * This depends on the fact that all child_added events on a given path will be triggered
       * before
       */
      this.masterRef.once('value', this.recList.masterPathLoaded, this.recList);
    }
    return this;
  },

  stop: function() {
    if( this.running ) {
      util.log('RecordSetEventManager: Stopped monitoring master list %s', this.url);
      this.running = false;
      this.masterRef.off('child_added',   this._add,    this);
      this.masterRef.off('child_removed', this._remove, this);
      this.masterRef.off('child_moved',   this._move,   this);
      this.recList.unloaded();
    }
    return this;
  },

  _add: function(snap, prevChild) {
    this.recList.add(snap.key(), prevChild);
  },

  _remove: function(snap) {
    this.recList.remove(snap.key());
  },

  _move: function(snap, prevChild) {
    this.recList.move(snap.key(), prevChild);
  }
};

function RecordList(observable, url) {
  this.obs = observable;
  this.url = url;
  this._reset();
}

RecordList.prototype = {
  add: function(key, prevChild) {
    util.log.debug('RecordList.add: key=%s, prevChild=%s', key, prevChild);
    var rec = this.obs.child(key);
    var fn = util.bind(this._valueUpdated, this, key);
    this.loading[key] = {rec: rec, prev: prevChild, fn: fn};
    if( !this.loadComplete ) {
      this.initialKeysLeft.push(key);
    }
    rec.watch('value', fn);
  },

  remove: function(key) {
    util.log.debug('RecordList.remove: key=%s', key);
    var oldSnap = this._dropRecord(key);
    if( oldSnap !== null ) {
      this._notify('child_removed', key, oldSnap);
    }
  },

  move: function(key, prevChild) {
    if(util.has(this.recs, key)) {
      var currPos = util.indexOf(this.recIds, key);
      this.recIds.splice(currPos, 1);
      this._putAfter(key, prevChild);
      this._notify('child_moved', key);
    }
  },

  masterPathLoaded: function() {
    util.log.debug('RecordList: Initial data has been loaded from master list at %s', this.url);
    this.masterLoaded = true;
    this._checkLoadState();
  },

  unloaded: function() {
    this._reset();
  },

  findKey: function(key) {
    //todo cache these lookups in a weak map?
    return util.indexOf(this.recIds, key);
  },

  _reset: function() {
    util.each(this.recs, function(rec, key) {
      this.remove(key);
    }, this);
    this.recs = {};
    this.recIds = [];
    this.snaps = {};
    this.loading = {};
    this.loadComplete = false;
    this.initialKeysLeft = [];
    this.masterLoaded = false;
  },

  _valueUpdated: function(key, snap) {
    this.snaps[key] = snap;
    if(util.has(this.loading, key)) {
      // newly added record
      var r = this.loading[key];
      delete this.loading[key];
      if( this.obs.filters.test(snap.val(), key, snap.getPriority()) ) {
        this.recs[key] = r.rec;
        this._putAfter(key, r.prev);
        this._checkLoadState(key);
        this._notify('child_added', key);
      }
      else {
        util.log('RecordList: Filtered key %s', key);
        r.rec.unwatch('value', r.fn);
      }
    }
    else if(util.has(this.recs, key)) {
      // a changed record
      this._notify('child_changed', key);
    }
    else {
      util.log('RecordList: Orphan key %s ignored. Probably a concurrent edit.', key);
    }
  },

  _notify: function(event, key, oldSnap) {
    var args = [key];
    // do not fetch prev child for other events as it costs an indexOf
    switch(event) {
      case 'child_added':
      case 'child_moved':
        var prev = this._getPrevChild(key);
        args.push(this.snaps[key], prev);
        break;
      case 'child_changed':
        args.push(this.snaps[key]);
        break;
      case 'child_removed':
        args.push(oldSnap);
        break;
      default:
        throw new Error('Invalid event type ' + event + ' for key ' + key);
    }
    util.log('RecordList._notify: event=%s, key=%s, prev=%s', event, key, prev);
    this.obs.handler(event).apply(this.obs, args);
    this._notifyValue();
  },

  _notifyValue: function() {
    util.log.debug('RecordList._notifyValue: snap_keys=%s, loadComplete=%s', util.keys(this.snaps), this.loadComplete);
    if( this.loadComplete ) {
      this.obs.handler('value')(util.toArray(this.snaps));
    }
  },

  _getPrevChild: function(key) {
    if( !this.recIds.length ) { return null; }
    var pos = this.findKey(key);
    if( pos === -1 ) {
      return this.recIds[this.recIds.length-1];
    }
    else if( pos === 0 ) {
      return null;
    }
    else {
      return this.recIds[pos-1];
    }
  },

  _posFor: function(prevKey) {
    var pos, x;
    if( prevKey === null ) {
      pos = 0;
    }
    else {
      x = this.findKey(prevKey);
      pos = x === -1? this.recIds.length : x+1;
    }
    return pos;
  },

  _putAfter: function(key, prevChild) {
    var newPos = this._posFor(prevChild);
    this.recIds.splice(newPos, 0, key);
  },

  _dropRecord: function(key) {
    if(util.has(this.recs, key)) {
      var snap = this.snaps[key];
      this.recs[key].unwatch('value', this._valueUpdated, this);
      delete this.recs[key];
      delete this.snaps[key];
      delete this.loading[key];
      util.remove(this.recIds, key);
      return snap;
    }
    return null;
  },

  /**
   * Because the initial once('value') will probably trigger before all the child paths
   * are retrieved (remember that we are monitoring multiple paths per child), we need
   * to wait for them to load in before triggering our first value event.
   * @private
   */
  _checkLoadState: function(key) {
    if( this.loadComplete ) { return; }
    if( key ) {
      util.remove(this.initialKeysLeft, key);
    }
    if( !this.initialKeysLeft.length && this.masterLoaded ) {
      this.loadComplete = true;
      if( !key ) {
        this._notifyValue();
      }
    }
  }
};

module.exports = RecordSetEventManager;<commit_msg>Fixes #35 - on('value') not working properly with filter()<commit_after>'use strict';

var util = require('../../common');

/**
 * Monitors the references attached to a RecordSet and maintains a cache of
 * current snapshots (inside RecordList below). Any time there is an update, this calls
 * RecordSet.handler() to invoke the correct event types (child_added, child_removed, value, et al)
 * on the RecordSet object.
 *
 * @param parentRec
 * @constructor
 */
function RecordSetEventManager(parentRec) {
  var pm = parentRec.getPathManager();
  this.masterRef = pm.first().ref();
  this.url = this.masterRef.toString();
  this.recList = new RecordList(parentRec, this.url);
  this.running = false;
}

RecordSetEventManager.prototype = {
  start: function() {
    if( !this.running ) {
      util.log('RecordSetEventManager: Loading normalized records from master list %s', this.url);
      this.running = true;
      this.masterRef.on('child_added',   this._add,    this);
      this.masterRef.on('child_removed', this._remove, this);
      this.masterRef.on('child_moved',   this._move,   this);
      /**
       * This depends on the fact that all child_added events on a given path will be triggered
       * before
       */
      this.masterRef.once('value', this.recList.masterPathLoaded, this.recList);
    }
    return this;
  },

  stop: function() {
    if( this.running ) {
      util.log('RecordSetEventManager: Stopped monitoring master list %s', this.url);
      this.running = false;
      this.masterRef.off('child_added',   this._add,    this);
      this.masterRef.off('child_removed', this._remove, this);
      this.masterRef.off('child_moved',   this._move,   this);
      this.recList.unloaded();
    }
    return this;
  },

  _add: function(snap, prevChild) {
    this.recList.add(snap.key(), prevChild);
  },

  _remove: function(snap) {
    this.recList.remove(snap.key());
  },

  _move: function(snap, prevChild) {
    this.recList.move(snap.key(), prevChild);
  }
};

function RecordList(observable, url) {
  this.obs = observable;
  this.url = url;
  this._reset();
}

RecordList.prototype = {
  add: function(key, prevChild) {
    util.log.debug('RecordList.add: key=%s, prevChild=%s', key, prevChild);
    var rec = this.obs.child(key);
    var fn = util.bind(this._valueUpdated, this, key);
    this.loading[key] = {rec: rec, prev: prevChild, fn: fn};
    if( !this.loadComplete ) {
      this.initialKeysLeft.push(key);
    }
    rec.watch('value', fn);
  },

  remove: function(key) {
    util.log.debug('RecordList.remove: key=%s', key);
    var oldSnap = this._dropRecord(key);
    if( oldSnap !== null ) {
      this._notify('child_removed', key, oldSnap);
    }
  },

  move: function(key, prevChild) {
    if(util.has(this.recs, key)) {
      var currPos = util.indexOf(this.recIds, key);
      this.recIds.splice(currPos, 1);
      this._putAfter(key, prevChild);
      this._notify('child_moved', key);
    }
  },

  masterPathLoaded: function() {
    util.log.debug('RecordList: Initial data has been loaded from master list at %s', this.url);
    this.masterLoaded = true;
    if( this._checkLoadState() ) {
      this._notifyValue();
    }
  },

  unloaded: function() {
    this._reset();
  },

  findKey: function(key) {
    return util.indexOf(this.recIds, key);
  },

  _reset: function() {
    util.each(this.recs, function(rec, key) {
      this.remove(key);
    }, this);
    this.recs = {};
    this.recIds = [];
    this.snaps = {};
    this.loading = {};
    this.loadComplete = false;
    this.initialKeysLeft = [];
    this.masterLoaded = false;
  },

  _valueUpdated: function(key, snap) {
    this.snaps[key] = snap;
    if(util.has(this.loading, key)) {
      // newly added record
      var r = this.loading[key];
      delete this.loading[key];
      if( this.obs.filters.test(snap.val(), key, snap.getPriority()) ) {
        this.recs[key] = r.rec;
        this._putAfter(key, r.prev);
        this._notify('child_added', key);
      }
      else {
        util.log('RecordList: Filtered key %s', key);
        r.rec.unwatch('value', r.fn);
      }
      if( this._checkLoadState(key) ) {
        this._notifyValue();
      }
    }
    else if(util.has(this.recs, key)) {
      // a changed record
      this._notify('child_changed', key);
    }
    else {
      util.log('RecordList: Orphan key %s ignored. Probably a concurrent edit.', key);
    }
  },

  _notify: function(event, key, oldSnap) {
    var args = [key];
    // do not fetch prev child for other events as it costs an indexOf
    switch(event) {
      case 'child_added':
      case 'child_moved':
        var prev = this._getPrevChild(key);
        args.push(this.snaps[key], prev);
        break;
      case 'child_changed':
        args.push(this.snaps[key]);
        break;
      case 'child_removed':
        args.push(oldSnap);
        break;
      default:
        throw new Error('Invalid event type ' + event + ' for key ' + key);
    }
    util.log('RecordList._notify: event=%s, key=%s, prev=%s', event, key, prev);
    this.obs.handler(event).apply(this.obs, args);
    this._notifyValue();
  },

  _notifyValue: function() {
    if( this.loadComplete ) {
      util.log.debug('RecordList._notifyValue: snap_keys=%s', util.keys(this.snaps));
      this.obs.handler('value')(util.toArray(this.snaps));
    }
  },

  _getPrevChild: function(key) {
    if( !this.recIds.length ) { return null; }
    var pos = this.findKey(key);
    if( pos === -1 ) {
      return this.recIds[this.recIds.length-1];
    }
    else if( pos === 0 ) {
      return null;
    }
    else {
      return this.recIds[pos-1];
    }
  },

  _posFor: function(prevKey) {
    var pos, x;
    if( prevKey === null ) {
      pos = 0;
    }
    else {
      x = this.findKey(prevKey);
      pos = x === -1? this.recIds.length : x+1;
    }
    return pos;
  },

  _putAfter: function(key, prevChild) {
    var newPos = this._posFor(prevChild);
    this.recIds.splice(newPos, 0, key);
  },

  _dropRecord: function(key) {
    if(util.has(this.recs, key)) {
      var snap = this.snaps[key];
      this.recs[key].unwatch('value', this._valueUpdated, this);
      delete this.recs[key];
      delete this.snaps[key];
      delete this.loading[key];
      util.remove(this.recIds, key);
      return snap;
    }
    return null;
  },

  /**
   * Because the initial once('value') will probably trigger before all the child paths
   * are retrieved (remember that we are monitoring multiple paths per child), we need
   * to wait for them to load in before triggering our first value event.
   * @private
   */
  _checkLoadState: function(key) {
    if( !this.loadComplete ) {
      if( key ) {
        util.remove(this.initialKeysLeft, key);
      }
      if( !this.initialKeysLeft.length && this.masterLoaded ) {
        this.loadComplete = true;
        return true;
      }
    }
    return false;
  }
};

module.exports = RecordSetEventManager;<|endoftext|>


<commit_before>/*
 * Admin.js
 * Fabien Sa 2013
 */

// Load editor (CodeMirror)
var editor = CodeMirror.fromTextArea(document.getElementById("editor"), {
	lineWrapping: true,
	mode: "markdown",
	viewportMargin: Infinity
});

var getPage = function(pagePath, callback) {
	if(pagePath === '') {
		return;
	}
	$.getJSON('../_api/pages/' + pagePath, function(data) {
		callback(data);
	})
}

var deletePage = function(pagePath, callback) {
	$.ajax({
		type: "DELETE",
		url: '../_api/pages/' + pagePath
	})
	.done(function( msg ) {
		callback(msg, false);
	})
	.fail(function( msg ) {
		callback(msg, true);
	});
}

var onHashChange = function() {
	var url = window.location.hash.substr(1);

	if(url !== '') {
		pageTitleEl.val(url).removeClass('notice');
		getPage(url, function(page) {
			editor.setValue(page.content || '');
			setPageInfo(page);
			refreshPreview();
		});
	} else {
		// New page
		editor.setValue('');
		refreshPreview();
		setPageInfo({});
		pageTitleEl.val('').focus();
	}
}

var setPageInfo = function(page) {
	var ulEl = pageInfoEl.find("ul");

	ulEl.html(''); // Clean previous fields

	for(field in page) {
		if(page.hasOwnProperty(field) && field !== "content" && field !== "url") {
			if(page[field] !== null) {

				if(field === "title") {
					pageTitleEl.val(page.title);
				} else {
					ulEl.append(
						'
' + field + ': <input class="title" value="' + page[field] + '" /> <button class="admin-btn-s delete">x</button>
');
				}

			}
		}
	}
}

var refreshPreview = function() {
	var content = editor.getValue();
	previewEl.html(marked(content));
}

var savePage = function(page, pagePath, callback) {
	$.ajax({
		type: "PUT",
		url: '../_api/pages/' + pagePath,
		data: page
	})
	.done(function( msg ) {
		window.location.hash = '#' + pagePath;
		callback(msg, false);
	})
	.fail(function( msg ) {
		callback(msg, true);
	});
}

var toggleClassEffect = function(el, className, time) {
	el.addClass(className).delay(time).queue(function(next) {
		$(this).removeClass(className);
		next();
	});
}

function stripHtml(html) {
   var tmp = document.createElement("DIV");
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}

$(function() {

	// Main elements
	previewEl = $('#preview .inner');
	listPagesEl = $('#pages-list');
	pageInfoEl = $('#page-info');
	headbarEl = $('#headbar');
	pageTitleEl = headbarEl.find('.title');

	$(window).on('hashchange', onHashChange);
	onHashChange();

	editor.on('keyup', function() {
		refreshPreview();
	});

	// Hide pages list on focus
	editor.on('focus', function() {
		$(".toggleList").removeClass("active").find(".anim").removeClass("rotate");
			listPagesEl.animate({ left: -300 });
	});

	// Pages list panel
	$(".toggleList").on('click', function() {
		if($(this).hasClass("active")) {
			$(this).removeClass("active").find(".anim").removeClass("rotate");
			listPagesEl.animate({ left: -300 });
		} else {
			$(this).addClass("active").find(".anim").addClass("rotate");
			listPagesEl.animate({ left: 0 });
		}
	});
	listPagesEl.css({ left: -300 });

	// Pages list panel
	$(".toggleInfo").on('click', function() {
		if($(this).hasClass("active")) {
			$(this).removeClass("active").find(".anim").removeClass("rotate");
			pageInfoEl.animate({ top: -320 });
		} else {
			$(this).addClass("active").find(".anim").addClass("rotate");
			pageInfoEl.animate({ top: 0 });
		}
	});
	pageInfoEl.css({ 'top': -320 });

	// Save page
	$(".save").on('click', function() {
		var page = {};
		page.content = editor.getValue();
		page.title = pageTitleEl.val();

		pageInfoEl.find("ul li").each(function(a, li) {
			var curr = $(this);
			var key = curr.find(".field").html();
			var val = curr.find("input").val();

			page[key] = val;
		});

		var url = window.location.hash.substr(1);

		var isNewPage = false;
		if(url === '') {
			// Sanitize filename
			url = page.title.replace(/[^a-z0-9_\-\[\]\(\)!\'~\|\+=&,]/gi, '_').toLowerCase();
			isNewPage = true;
		}

		savePage(page, url, function(msg, err) {
			if(err || msg === "false" || msg === '') {
				toggleClassEffect(headbarEl, 'error', 1000);
				console.log("Error: " + msg);
			} else {
				toggleClassEffect(headbarEl, 'ok', 1000);
				console.log(msg);

				if(isNewPage) {
					// pages-list
					listPagesEl.find("ul.list").append(
						'
'+url+' <button class="admin-btn-s delete">x</button>
');
				}
			}
		});
	});

	// Logout
	$(".logout").on('click', function() {
		$.get('../_api/logout', function() {
			location.reload();
		})
	});

	// Delete field
	$("#page-info").on('click', ".delete", function() {
		console.log($(this).parent().html());
		if (confirm('Delete this field ?')) {
			$(this).parent().remove();
		}
	});

	// Delete pages
	listPagesEl.on('click', ".delete", function() {
		var li = $(this).parent();
		var pageName = $(this).parent().find('a').html();

		if (confirm('Delete page "' + pageName + '" ?')) {
			deletePage(pageName, function(msg, err) {
				if(err || msg === "false" || msg === '') {
					toggleClassEffect(headbarEl, 'error', 1000);
					console.log("Error: " + msg);
				} else {
					toggleClassEffect(headbarEl, 'ok', 1000);
					li.remove(); // Remove element from list
				}
			});
		}
	});

	pageTitleEl.on('keyup | blur', function(e) {
		var title = stripHtml(pageTitleEl.val());
		if(title === '') {
			pageTitleEl.addClass('notice');
		} else {
			pageTitleEl.removeClass('notice');
		}
	});

});

marked.InlineLexer.prototype.outputLink = function(cap, link) {
	var patt = /^(https?|ftp):\/\//;
	if(!patt.test(link.href)) {
		link.href = baseUrl + '/data/images/' + link.href;
	}

	if (cap[0].charAt(0) !== '!') {
		return ''
			+ this.output(cap[1])
			+ '';
	} else {
		return '';
	}
};
<commit_msg>clearQueue() when toggle panels<commit_after>/*
 * Admin.js
 * Fabien Sa 2013
 */

// Load editor (CodeMirror)
var editor = CodeMirror.fromTextArea(document.getElementById("editor"), {
	lineWrapping: true,
	mode: "markdown",
	viewportMargin: Infinity
});

var getPage = function(pagePath, callback) {
	if(pagePath === '') {
		return;
	}
	$.getJSON('../_api/pages/' + pagePath, function(data) {
		callback(data);
	})
}

var deletePage = function(pagePath, callback) {
	$.ajax({
		type: "DELETE",
		url: '../_api/pages/' + pagePath
	})
	.done(function( msg ) {
		callback(msg, false);
	})
	.fail(function( msg ) {
		callback(msg, true);
	});
}

var onHashChange = function() {
	var url = window.location.hash.substr(1);

	if(url !== '') {
		pageTitleEl.val(url).removeClass('notice');
		getPage(url, function(page) {
			editor.setValue(page.content || '');
			setPageInfo(page);
			refreshPreview();
		});
	} else {
		// New page
		editor.setValue('');
		refreshPreview();
		setPageInfo({});
		pageTitleEl.val('').focus();
	}
}

var setPageInfo = function(page) {
	var ulEl = pageInfoEl.find("ul");

	ulEl.html(''); // Clean previous fields

	for(field in page) {
		if(page.hasOwnProperty(field) && field !== "content" && field !== "url") {
			if(page[field] !== null) {

				if(field === "title") {
					pageTitleEl.val(page.title);
				} else {
					ulEl.append(
						'
' + field + ': <input class="title" value="' + page[field] + '" /> <button class="admin-btn-s delete">x</button>
');
				}

			}
		}
	}
}

var refreshPreview = function() {
	var content = editor.getValue();
	previewEl.html(marked(content));
}

var savePage = function(page, pagePath, callback) {
	$.ajax({
		type: "PUT",
		url: '../_api/pages/' + pagePath,
		data: page
	})
	.done(function( msg ) {
		window.location.hash = '#' + pagePath;
		callback(msg, false);
	})
	.fail(function( msg ) {
		callback(msg, true);
	});
}

var toggleClassEffect = function(el, className, time) {
	el.addClass(className).delay(time).queue(function(next) {
		$(this).removeClass(className);
		next();
	});
}

function stripHtml(html) {
   var tmp = document.createElement("DIV");
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}

$(function() {

	// Main elements
	previewEl = $('#preview .inner');
	listPagesEl = $('#pages-list');
	pageInfoEl = $('#page-info');
	headbarEl = $('#headbar');
	pageTitleEl = headbarEl.find('.title');

	$(window).on('hashchange', onHashChange);
	onHashChange();

	editor.on('keyup', function() {
		refreshPreview();
	});

	// Hide pages list on focus
	editor.on('focus', function() {
		$(".toggleList").removeClass("active").find(".anim").removeClass("rotate");
		listPagesEl.animate({ left: -300 });
	});

	// Pages list panel
	$(".toggleList").on('click', function(e) {
		listPagesEl.clearQueue().stop();
		if($(this).hasClass("active")) {
			$(this).removeClass("active").find(".anim").removeClass("rotate");
			listPagesEl.animate({ left: -300 });
		} else {
			$(this).addClass("active").find(".anim").addClass("rotate");
			listPagesEl.animate({ left: 0 });
		}
	});
	listPagesEl.css({ left: -300 });

	// Pages list panel
	$(".toggleInfo").on('click', function(e) {
		pageInfoEl.clearQueue().stop();
		if($(this).hasClass("active")) {
			$(this).removeClass("active").find(".anim").removeClass("rotate");
			pageInfoEl.animate({ top: -320 });
		} else {
			$(this).addClass("active").find(".anim").addClass("rotate");
			pageInfoEl.animate({ top: 0 });
		}
	});
	pageInfoEl.css({ 'top': -320 });

	// Save page
	$(".save").on('click', function() {
		var page = {};
		page.content = editor.getValue();
		page.title = pageTitleEl.val();

		pageInfoEl.find("ul li").each(function(a, li) {
			var curr = $(this);
			var key = curr.find(".field").html();
			var val = curr.find("input").val();

			page[key] = val;
		});

		var url = window.location.hash.substr(1);

		var isNewPage = false;
		if(url === '') {
			// Sanitize filename
			url = page.title.replace(/[^a-z0-9_\-\[\]\(\)!\'~\|\+=&,]/gi, '_').toLowerCase();
			isNewPage = true;
		}

		savePage(page, url, function(msg, err) {
			if(err || msg === "false" || msg === '') {
				toggleClassEffect(headbarEl, 'error', 1000);
				console.log("Error: " + msg);
			} else {
				toggleClassEffect(headbarEl, 'ok', 1000);
				console.log(msg);

				if(isNewPage) {
					// pages-list
					listPagesEl.find("ul.list").append(
						'
'+url+' <button class="admin-btn-s delete">x</button>
');
				}
			}
		});
	});

	// Logout
	$(".logout").on('click', function() {
		$.get('../_api/logout', function() {
			location.reload();
		})
	});

	// Delete field
	$("#page-info").on('click', ".delete", function() {
		console.log($(this).parent().html());
		if (confirm('Delete this field ?')) {
			$(this).parent().remove();
		}
	});

	// Delete pages
	listPagesEl.on('click', ".delete", function() {
		var li = $(this).parent();
		var pageName = $(this).parent().find('a').html();

		if (confirm('Delete page "' + pageName + '" ?')) {
			deletePage(pageName, function(msg, err) {
				if(err || msg === "false" || msg === '') {
					toggleClassEffect(headbarEl, 'error', 1000);
					console.log("Error: " + msg);
				} else {
					toggleClassEffect(headbarEl, 'ok', 1000);
					li.remove(); // Remove element from list
				}
			});
		}
	});

	pageTitleEl.on('keyup | blur', function(e) {
		var title = stripHtml(pageTitleEl.val());
		if(title === '') {
			pageTitleEl.addClass('notice');
		} else {
			pageTitleEl.removeClass('notice');
		}
	});

});

marked.InlineLexer.prototype.outputLink = function(cap, link) {
	var patt = /^(https?|ftp):\/\//;
	if(!patt.test(link.href)) {
		link.href = baseUrl + '/data/images/' + link.href;
	}

	if (cap[0].charAt(0) !== '!') {
		return ''
			+ this.output(cap[1])
			+ '';
	} else {
		return '';
	}
};
<|endoftext|>


<commit_before>var es = require("event-stream");
var filesize = require("filesize");
var prettyHrtime = require("pretty-hrtime");
var ora = require("ora");
var chalk = require('chalk');
var warnings = require("./warnings");

var FAILED = 0;
var SUCCESS = 1;
var NOMSG = null;

function buildstatsStreamFactory(options) {
  options = options || {};
  var startTime, spinner;
  var animation = options.animation !== false;

  return es.map(function(chunk, callback) {
    if (isBuildStart(chunk)) {
      if (animation) {
        spinner = nextSpinner("build in progress").start();
      }

      startTime = process.hrtime();
    }
    else if (isBuildSuccess(chunk)) {
      var msg = "build success";

      if (spinner) {
        finishSpinner(nextSpinner(msg, spinner, startTime, SUCCESS), startTime, SUCCESS);
      }
    }
    else if (isBuildFailure(chunk)) {
      var msg = chalk.red("build error");

      if (spinner) {
        finishSpinner(nextSpinner(msg, spinner, startTime, SUCCESS), startTime, FAILED);
      }
    }
    else if (isBuildBundling(chunk)) {
      if (spinner) {
        spinner = nextSpinner("creating bundles", spinner, startTime, SUCCESS).start();
      }
    }
    else if (isBuildWriting(chunk)) {
      if (spinner) {
        spinner = nextSpinner("writing bundles", spinner, startTime, SUCCESS).start();
      }
    }
    else if (isBuildInfo(chunk)) {
      if (spinner) {
        infoSpinner(chalk.cyan(">> ") + chunk.data[1], startTime);
      }
    }
    else if (isBundleWriteSuccess(chunk)) {
      if (spinner) {
        spinner.clear();
      }

      var bundle = chunk.data[1];
      infoSpinner(chalk.cyan("|- ") + "bundle: [" + bundle.name + "] " + filesize(bundle.content.length));

      if (spinner) {
        spinner.render();
      }
    }

    if (warnings.hasWarningsOrErrors(chunk)) {
      if (spinner) {
        spinner.clear();
      }

      warnings.logWarningsAndErrors(chunk, { showName: false });

      if (spinner) {
        spinner.render();
      }
    }

    callback(null, chunk);
  });
}

function getData(chunk) {
  var data = chunk.data.slice(2).map(function(data) {
    return "  " + data;
  });

  return [chunk.data[0]].concat(data).join("");
}

function isBundleWriteSuccess(chunk) {
  return chunk.name === "bundler/writer" && chunk.data[0] === "write-success";
}

function isBuildStart(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-start";
}

function isBuildSuccess(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-success";
}

function isBuildBundling(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-bundling";
}

function isBuildWriting(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-writing";
}

function isBuildFailure(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-failed";
}

function isBuildInfo(chunk) {
  return chunk.data[0] === "build-info";
}

module.exports = buildstatsStreamFactory;

function nextSpinner(text, prevSpinner, htime, success) {
  finishSpinner(prevSpinner, htime, success);

  return text && ora({
    text: text,
    spinner: "dots"
  });
}

function infoSpinner(text, htime) {
  text = htime ? text + " " + prettyHrtime(process.hrtime(htime)) : text;

  ora({
    text: text,
    spinner: "dots"
  })
  .stopAndPersist();
}

function finishSpinner(spinner, htime, success) {
  if (spinner) {
    spinner.text = spinner.text + ": " + prettyHrtime(process.hrtime(htime));
    success = success === undefined ? SUCCESS : success;
    success === FAILED ? spinner.fail() : spinner.succeed();
  }
}
<commit_msg>adding logic to color code build-info messages based on info, warn, error status<commit_after>var es = require("event-stream");
var filesize = require("filesize");
var prettyHrtime = require("pretty-hrtime");
var ora = require("ora");
var chalk = require('chalk');
var warnings = require("./warnings");

var FAILED = 0;
var SUCCESS = 1;
var NOMSG = null;

function buildstatsStreamFactory(options) {
  options = options || {};
  var startTime, spinner;
  var animation = options.animation !== false;

  return es.map(function(chunk, callback) {
    if (isBuildStart(chunk)) {
      if (animation) {
        spinner = nextSpinner("build in progress").start();
      }

      startTime = process.hrtime();
    }
    else if (isBuildSuccess(chunk)) {
      var msg = "build success";

      if (spinner) {
        finishSpinner(nextSpinner(msg, spinner, startTime, SUCCESS), startTime, SUCCESS);
      }
    }
    else if (isBuildFailure(chunk)) {
      var msg = chalk.red("build error");

      if (spinner) {
        finishSpinner(nextSpinner(msg, spinner, startTime, SUCCESS), startTime, FAILED);
      }
    }
    else if (isBuildBundling(chunk)) {
      if (spinner) {
        spinner = nextSpinner("creating bundles", spinner, startTime, SUCCESS).start();
      }
    }
    else if (isBuildWriting(chunk)) {
      if (spinner) {
        spinner = nextSpinner("writing bundles", spinner, startTime, SUCCESS).start();
      }
    }
    else if (isBuildInfo(chunk)) {
      if (spinner) {
        var msg = (
          chunk.level === 1 ? chalk.cyan("ⓘ  " + chunk.data[1])  :
          chunk.level === 2 ? chalk.green("ⓦ  " + chunk.data[1]) :
          chunk.level === 3 ? chalk.red("ⓔ  " + chunk.data[1]) : chunk.data[1]
        );

        infoSpinner(msg, startTime);
      }
    }
    else if (isBundleWriteSuccess(chunk)) {
      if (spinner) {
        spinner.clear();
      }

      var bundle = chunk.data[1];
      infoSpinner(chalk.cyan("📦  ") + "[" + bundle.name + "] " + filesize(bundle.content.length));

      if (spinner) {
        spinner.render();
      }
    }

    if (warnings.hasWarningsOrErrors(chunk)) {
      if (spinner) {
        spinner.clear();
      }

      warnings.logWarningsAndErrors(chunk, { showName: false });

      if (spinner) {
        spinner.render();
      }
    }

    callback(null, chunk);
  });
}

function getData(chunk) {
  var data = chunk.data.slice(2).map(function(data) {
    return "  " + data;
  });

  return [chunk.data[0]].concat(data).join("");
}

function isBundleWriteSuccess(chunk) {
  return chunk.name === "bundler/writer" && chunk.data[0] === "write-success";
}

function isBuildStart(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-start";
}

function isBuildSuccess(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-success";
}

function isBuildBundling(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-bundling";
}

function isBuildWriting(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-writing";
}

function isBuildFailure(chunk) {
  return chunk.name === "bundler/context" && chunk.data[0] === "build-failed";
}

function isBuildInfo(chunk) {
  return chunk.data[0] === "build-info";
}

module.exports = buildstatsStreamFactory;

function nextSpinner(text, prevSpinner, htime, success) {
  finishSpinner(prevSpinner, htime, success);

  return text && ora({
    text: text,
    spinner: "dots"
  });
}

function infoSpinner(text, htime) {
  text = htime ? text + " " + prettyHrtime(process.hrtime(htime)) : text;

  ora({
    text: text,
    spinner: "dots"
  })
  .stopAndPersist();
}

function finishSpinner(spinner, htime, success) {
  if (spinner) {
    spinner.text = spinner.text + ": " + prettyHrtime(process.hrtime(htime));
    success = success === undefined ? SUCCESS : success;
    success === FAILED ? spinner.fail() : spinner.succeed();
  }
}
<|endoftext|>


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

"use strict";

var pjson = require("../../package.json");
var specs = require("../api-specs");
var config = require('../config').conf;

module.exports = function(app, conf) {
  // Videur integration.
  var roomTokenSize = Math.ceil(config.get('rooms').tokenSize / 3 * 4);
  var callTokenSize = Math.ceil(config.get('callUrls').tokenSize / 3 * 4);

  app.get("/api-specs", function(req, res) {
    specs.service.location = conf.get("protocol") + "://" + req.get("host");
    specs.service.version = pjson.version;

    var roomsKey = "regexp:/rooms/[a-zA-Z0-9_-]{" + roomTokenSize + "}";
    specs.service.resources[roomsKey] = specs.service.resources._ROOMS_;
    delete specs.service.resources._ROOMS_;

    var callsKey = "regexp:/calls/[a-zA-Z0-9_-]{" + callTokenSize + "}";
    specs.service.resources[callsKey] = specs.service.resources._CALLS_;
    delete specs.service.resources._CALLS_;

    res.json(200, specs);
  });
};
<commit_msg>use publicServerAddress<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

var pjson = require("../../package.json");
var specs = require("../api-specs");
var config = require('../config').conf;

module.exports = function(app, conf) {
  // Videur integration.
  var roomTokenSize = Math.ceil(config.get('rooms').tokenSize / 3 * 4);
  var callTokenSize = Math.ceil(config.get('callUrls').tokenSize / 3 * 4);

  app.get("/api-specs", function(req, res) {
    specs.service.location = conf.get("protocol") + "://" + req.get("publicServerAddress");
    specs.service.version = pjson.version;

    var roomsKey = "regexp:/rooms/[a-zA-Z0-9_-]{" + roomTokenSize + "}";
    specs.service.resources[roomsKey] = specs.service.resources._ROOMS_;
    delete specs.service.resources._ROOMS_;

    var callsKey = "regexp:/calls/[a-zA-Z0-9_-]{" + callTokenSize + "}";
    specs.service.resources[callsKey] = specs.service.resources._CALLS_;
    delete specs.service.resources._CALLS_;

    res.json(200, specs);
  });
};
<|endoftext|>


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

"use strict";
var redis = require("redis");

function RedisStorage(options, settings) {
  this._settings = settings;
  this._client = redis.createClient(
    options.host,
    options.port,
    options.options
  );
  if (options.db) {
    this._client.select(options.db);
  }
}

RedisStorage.prototype = {
  revokeURLToken: function(token, callback) {
    var ttl = (token.expires * 60 * 60 * 1000);
    this._client.psetex('urlRevoked.' + token.uuid, ttl, "ok", callback);
  },

  isURLRevoked: function(urlId, callback) {
    this._client.get('urlRevoked.' + urlId, function(err, result) {
      if(result === null) {
        callback(err, false);
      } else {
        callback(err, true);
      }
    });
  },

  addUserSimplePushURL: function(userMac, simplepushURL, callback) {
    this._client.set('spurl.' + userMac, simplepushURL, callback);
  },

  getUserSimplePushURLs: function(userMac, callback) {
    this._client.get('spurl.' + userMac, function(err, result) {
      var simplePushURL = [];
      if (result !== null) {
        simplePushURL.push(result);
      }
      callback(err, simplePushURL);
    });
  },

  addUserCall: function(userMac, call, callback) {
    var self = this;
    this._client.setex(
      'call.' + call.callId,
      this._settings.tokenDuration,
      JSON.stringify(call),
      function(err) {
        if (err) {
          callback(err);
          return;
        }
        self._client.sadd('userCalls.' + userMac,
                          'call.' + call.callId, callback);
      });
  },

  getUserCalls: function(userMac, callback) {
    var self = this;
    this._client.smembers('userCalls.' + userMac, function(err, members) {
      self._client.mget(members, function(err, calls) {
        if (err) {
          callback(err);
          return;
        }
        var expired = calls.map(function(val, index) {
          return (val === null) ? index : null;
        }).filter(function(val) {
          return val !== null;
        });

        var pendingCalls = calls.filter(function(val) {
          return val !== null;
        }).map(JSON.parse).sort(function(a, b) {
          return a.timestamp - b.timestamp;
        });

        if (expired.length > 0) {
          self._client.srem(expired, function(err, res) {
            callback(null, pendingCalls);
          });
          return;
        }
        callback(null, pendingCalls);
      });
    });
  },

  getCall: function(callId, callback) {
    this._client.get('call.' + callId, function(err, call) {
      callback(err, JSON.parse(call));
    });
  },

  deleteCall: function(callId, callback) {
    this._client.del('call.' + callId, function(err, result) {
      callback(err, result !== 0);
    });
  },

  drop: function(callback) {
    this._client.flushdb(callback);
  },

  ping: function(callback) {
    this._client.ping(function(err, value) {
      callback((err === null && value === "PONG"));
    });
  }
};

module.exports = RedisStorage;
<commit_msg>fix bug with redis.createClient<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";
var redis = require("redis");

function RedisStorage(options, settings) {
  this._settings = settings;
  this._client = redis.createClient(
    options.port,
    options.host,
    options.options
  );
  if (options.db) {
    this._client.select(options.db);
  }
}

RedisStorage.prototype = {
  revokeURLToken: function(token, callback) {
    var ttl = (token.expires * 60 * 60 * 1000);
    this._client.psetex('urlRevoked.' + token.uuid, ttl, "ok", callback);
  },

  isURLRevoked: function(urlId, callback) {
    this._client.get('urlRevoked.' + urlId, function(err, result) {
      if(result === null) {
        callback(err, false);
      } else {
        callback(err, true);
      }
    });
  },

  addUserSimplePushURL: function(userMac, simplepushURL, callback) {
    this._client.set('spurl.' + userMac, simplepushURL, callback);
  },

  getUserSimplePushURLs: function(userMac, callback) {
    this._client.get('spurl.' + userMac, function(err, result) {
      var simplePushURL = [];
      if (result !== null) {
        simplePushURL.push(result);
      }
      callback(err, simplePushURL);
    });
  },

  addUserCall: function(userMac, call, callback) {
    var self = this;
    this._client.setex(
      'call.' + call.callId,
      this._settings.tokenDuration,
      JSON.stringify(call),
      function(err) {
        if (err) {
          callback(err);
          return;
        }
        self._client.sadd('userCalls.' + userMac,
                          'call.' + call.callId, callback);
      });
  },

  getUserCalls: function(userMac, callback) {
    var self = this;
    this._client.smembers('userCalls.' + userMac, function(err, members) {
      self._client.mget(members, function(err, calls) {
        if (err) {
          callback(err);
          return;
        }
        var expired = calls.map(function(val, index) {
          return (val === null) ? index : null;
        }).filter(function(val) {
          return val !== null;
        });

        var pendingCalls = calls.filter(function(val) {
          return val !== null;
        }).map(JSON.parse).sort(function(a, b) {
          return a.timestamp - b.timestamp;
        });

        if (expired.length > 0) {
          self._client.srem(expired, function(err, res) {
            callback(null, pendingCalls);
          });
          return;
        }
        callback(null, pendingCalls);
      });
    });
  },

  getCall: function(callId, callback) {
    this._client.get('call.' + callId, function(err, call) {
      callback(err, JSON.parse(call));
    });
  },

  deleteCall: function(callId, callback) {
    this._client.del('call.' + callId, function(err, result) {
      callback(err, result !== 0);
    });
  },

  drop: function(callback) {
    this._client.flushdb(callback);
  },

  ping: function(callback) {
    this._client.ping(function(err, value) {
      callback((err === null && value === "PONG"));
    });
  }
};

module.exports = RedisStorage;
<|endoftext|>


<commit_before>/**
 * RcmHtmlEditor - Main adapter to an actual tinymce
 * @param id
 * @param rcmHtmlEditorService
 * @constructor
 */
var RcmHtmlEditor = function (id, rcmHtmlEditorService) {

    var self = this;
    self.id = id;
    self.scope;
    self.elm;
    self.attrs;
    self.ngModel;

    self.settings = {};

    self.tagName = "";
    self.initTimeout;

    self.init = function (scope, elm, attrs, ngModel, settings) {

        self.scope = scope;
        self.elm = elm;
        self.ngModel = ngModel;
        self.settings = settings;
        self.attrs = attrs;

        // is dom has changed, init may not complete
        self.initTimeout = setTimeout(
            function () {
                self.onInitTimout();
            },
            2000
        );

        self.buildEditor();
    };

    /**
     * onInit
     */
    self.onInit = function (editor) {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onInit',
            {
                rcmHtmlEditor: self,
                editorInstance: editor
            }
        );
        clearTimeout(self.initTimeout);
    };

    /**
     * onInitTimout
     */
    self.onInitTimout = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onInitTimeout',
            self
        );
        //console.warn('RcmHtmlEditor: ' + id + ' failed to init.');
        self.destroy('onInitTimout');
    };

    /**
     * onDestroy
     */
    self.onDestroy = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onDestroy',
            self
        );
        clearTimeout(self.initTimeout);
    };

    /**
     * onApply
     */
    self.onApply = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onApply',
            self
        );
    };

    /**
     * getTagName
     * @returns {string}
     */
    self.getTagName = function () {

        if ((self.elm && self.elm[0]) && !self.tagName) {
            self.tagName = self.elm[0].tagName;
        }

        return self.tagName;
    };

    /**
     * getElmValue
     * @returns {*}
     */
    self.getElmValue = function () {

        if (self.isFormControl()) {

            return self.elm.val();
        }

        return self.elm.html();
    };

    /**
     * getEditorInstance
     * @returns {*}
     */
    self.getEditorInstance = function(){

        return tinymce.get(self.id);
    };

    /**
     * isFormControl
     * @returns {boolean}
     */
    self.isFormControl = function () {

        return (self.getTagName() == "TEXTAREA");
    };

    /**
     * updateView
     */
    self.updateView = function () {

        if (self.ngModel) {
            var editorInstance = self.getEditorInstance();
            self.ngModel.$setViewValue(editorInstance.getContent());
        }

        self.apply();
    };

    /**
     * apply
     */
    self.apply = function () {

        if (!self.scope.$root.$$phase) {

            self.scope.$apply(
                function () {
                    self.onApply();
                }
            );
        } else {

            self.onApply();
        }
    };

    /**
     * buildEditor
     */
    self.buildEditor = function () {

        self.settings.setup = function (editor) {

            var args;
            // This did not work, might be a way to sync click events
            //editor.on('click', function (args) {
            //
            //    if (self.elm.click) {
            //        self.elm.click();
            //    }
            //});
            editor.on(
                'init',
                function (args) {

                    if (self.ngModel) {
                        self.ngModel.$render();
                        self.ngModel.$setPristine();
                    }

                    self.onInit(editor);
                    self.apply();
                }
            );
            //
            editor.on(
                'postrender',
                function (args) {
                }
            );
            // Update model on button click
            editor.on(
                'ExecCommand',
                function (e) {
                    editor.save();
                    self.updateView();
                }
            );
            // Update model on keypress
            editor.on(
                'KeyUp',
                function (e) {
                    editor.save();
                    self.updateView();
                }
            );
            //editor.on(
            //    'BeforeSetContent',
            //    function (e) {
            //    }
            //);
            // Update model on change, i.e. copy/pasted text, plugins altering content
            editor.on(
                'SetContent',
                function (e) {

                    /**
                     * IMPORTANT
                     * We do NOT sync content on initial and when it is selection
                     * Selection adds some special markup which causes issues when we sync it
                     */
                    if (!e.initial && !e.selection) {

                        if (self.ngModel) {

                            if (self.ngModel.$viewValue !== e.content) {
                                editor.save();
                                self.updateView();
                            }
                        } else {

                            editor.save();
                            self.updateView();
                        }
                    }
                }
            );
            // blur
            editor.on(
                'blur',
                function (e) {

                    rcmHtmlEditorService.isEditing = false;

                    self.updateView();
                }
            );
            // focus
            editor.on(
                'focus',
                function (e) {

                    rcmHtmlEditorService.isEditing = true;

                    self.updateView();
                }
            );
            // Update model when an object has been resized (table, image)
            editor.on(
                'ObjectResized',
                function (e) {

                    editor.save();
                    self.updateView();
                }
            );
            // change
            editor.on(
                'change',
                function (e) {

                    self.updateView();
                }
            );

            // change selection
            //editor.on(
            //    'SelectionChange',
            //    function () {
            //
            //        self.updateView();
            //    }
            //);
            // This might be needed if setup can be passed in
            //if (settings) {
            //    settings(editor);
            //}
        };

        setTimeout(
            function () {

                tinymce.init(self.settings);
            }
        );

        if (self.ngModel) {

            self.ngModel.$render = function () {

                var editorInstance = self.getEditorInstance();

                if (editorInstance) {
                    editorInstance.setContent(self.ngModel.$viewValue || self.getElmValue());
                } else {
                    // Should not be required, was extra garbage cleanup
                    // self.destroy('editorInstance not found')
                }
            };
        }

        self.elm.on(
            '$destroy', function () {

                self.destroy('self.elm.on $destroy');
            }
        );

        self.scope.$on(
            '$destroy', function () {

                // this can cause issues with editors that are on the page dynamically
                // might be caused by element being destroyed and scope is part on elm.
                // self.destroy();
            }
        );
    };

    /**
     * destroy
     * @param msg For tracking only - not required
     */
    self.destroy = function (msg) {

        var editorInstance = self.getEditorInstance();

        if (editorInstance) {

            editorInstance.remove();
        }

        self.onDestroy();

        self.apply();
    };

    /**
     * hasEditorInstance
     * @returns {boolean}
     */
    self.hasEditorInstance = function () {

        var tinyInstance = tinymce.get(self.id);

        return (tinyInstance);
    };
};<commit_msg>Fix for event error<commit_after>/**
 * RcmHtmlEditor - Main adapter to an actual tinymce
 * @param id
 * @param rcmHtmlEditorService
 * @constructor
 */
var RcmHtmlEditor = function (id, rcmHtmlEditorService) {

    var self = this;
    self.id = id;
    self.scope;
    self.elm;
    self.attrs;
    self.ngModel;

    self.settings = {};

    self.tagName = "";
    self.initTimeout;

    self.init = function (scope, elm, attrs, ngModel, settings) {

        self.scope = scope;
        self.elm = elm;
        self.ngModel = ngModel;
        self.settings = settings;
        self.attrs = attrs;

        // is dom has changed, init may not complete
        self.initTimeout = setTimeout(
            function () {
                self.onInitTimout();
            },
            2000
        );

        self.buildEditor();
    };

    /**
     * onInit
     */
    self.onInit = function (editor) {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onInit',
            {
                rcmHtmlEditor: self,
                editorInstance: editor
            }
        );
        clearTimeout(self.initTimeout);
    };

    /**
     * onInitTimout
     */
    self.onInitTimout = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onInitTimeout',
            self
        );
        //console.warn('RcmHtmlEditor: ' + id + ' failed to init.');
        self.destroy('onInitTimout');
    };

    /**
     * onDestroy
     */
    self.onDestroy = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onDestroy',
            self
        );
        clearTimeout(self.initTimeout);
    };

    /**
     * onApply
     */
    self.onApply = function () {

        rcmHtmlEditorService.eventManager.trigger(
            'RcmHtmlEditor.onApply',
            self
        );
    };

    /**
     * getTagName
     * @returns {string}
     */
    self.getTagName = function () {

        if ((self.elm && self.elm[0]) && !self.tagName) {
            self.tagName = self.elm[0].tagName;
        }

        return self.tagName;
    };

    /**
     * getElmValue
     * @returns {*}
     */
    self.getElmValue = function () {

        if (self.isFormControl()) {

            return self.elm.val();
        }

        return self.elm.html();
    };

    /**
     * getEditorInstance
     * @returns {*}
     */
    self.getEditorInstance = function(){

        return tinymce.get(self.id);
    };

    /**
     * isFormControl
     * @returns {boolean}
     */
    self.isFormControl = function () {

        return (self.getTagName() == "TEXTAREA");
    };

    /**
     * updateView
     */
    self.updateView = function () {

        if (self.ngModel) {
            var editorInstance = self.getEditorInstance();
            self.ngModel.$setViewValue(editorInstance.getContent());
        }

        self.apply();
    };

    /**
     * apply
     */
    self.apply = function () {

        if (!self.scope.$root.$$phase) {

            self.scope.$apply(
                function () {
                    self.onApply();
                }
            );
        } else {

            self.onApply();
        }
    };

    /**
     * buildEditor
     */
    self.buildEditor = function () {

        self.settings.setup = function (editor) {

            var args;
            // This did not work, might be a way to sync click events
            //editor.on('click', function (args) {
            //
            //    if (self.elm.click) {
            //        self.elm.click();
            //    }
            //});
            editor.on(
                'init',
                function (args) {

                    if (self.ngModel) {
                        self.ngModel.$render();
                        self.ngModel.$setPristine();
                    }

                    self.onInit(editor);
                    self.apply();
                }
            );
            //
            editor.on(
                'postrender',
                function (args) {
                }
            );
            // Update model on button click
            editor.on(
                'ExecCommand',
                function (e) {
                    editor.save();
                    self.updateView();
                }
            );
            // Update model on keypress
            editor.on(
                'KeyUp',
                function (e) {
                    editor.save();
                    self.updateView();
                }
            );
            //editor.on(
            //    'BeforeSetContent',
            //    function (e) {
            //    }
            //);
            // Update model on change, i.e. copy/pasted text, plugins altering content
            editor.on(
                'SetContent',
                function (e) {

                    /**
                     * IMPORTANT
                     * We do NOT sync content on initial and when it is selection
                     * Selection adds some special markup which causes issues when we sync it
                     */
                    if (!e.initial && !e.selection) {

                        if (self.ngModel) {

                            if (self.ngModel.$viewValue !== e.content) {
                                editor.save();
                                self.updateView();
                            }
                        } else {

                            editor.save();
                            self.updateView();
                        }
                    }
                }
            );
            // blur
            editor.on(
                'blur',
                function (e) {

                    rcmHtmlEditorService.isEditing = false;

                    self.updateView();
                }
            );
            // focus
            editor.on(
                'focus',
                function (e) {

                    rcmHtmlEditorService.isEditing = true;

                    self.updateView();
                }
            );
            // Update model when an object has been resized (table, image)
            editor.on(
                'ObjectResized',
                function (e) {

                    editor.save();
                    self.updateView();
                }
            );
            // change
            editor.on(
                'change',
                function (e) {

                    self.updateView();
                }
            );

            // change selection
            //editor.on(
            //    'SelectionChange',
            //    function () {
            //
            //        self.updateView();
            //    }
            //);
            // This might be needed if setup can be passed in
            //if (settings) {
            //    settings(editor);
            //}
        };

        setTimeout(
            function () {

                tinymce.init(self.settings);
            }
        );

        if (self.ngModel) {

            self.ngModel.$render = function () {

                var editorInstance = self.getEditorInstance();

                if (editorInstance) {
                    editorInstance.setContent(self.ngModel.$viewValue || self.getElmValue(), {format : 'raw'});
                } else {
                    // Should not be required, was extra garbage cleanup
                    // self.destroy('editorInstance not found')
                }
            };
        }

        self.elm.on(
            '$destroy', function () {

                self.destroy('self.elm.on $destroy');
            }
        );

        self.scope.$on(
            '$destroy', function () {

                // this can cause issues with editors that are on the page dynamically
                // might be caused by element being destroyed and scope is part on elm.
                // self.destroy();
            }
        );
    };

    /**
     * destroy
     * @param msg For tracking only - not required
     */
    self.destroy = function (msg) {

        var editorInstance = self.getEditorInstance();

        if (editorInstance) {

            editorInstance.remove();
        }

        self.onDestroy();

        self.apply();
    };

    /**
     * hasEditorInstance
     * @returns {boolean}
     */
    self.hasEditorInstance = function () {

        var tinyInstance = tinymce.get(self.id);

        return (tinyInstance);
    };
};<|endoftext|>


<commit_before>const execa = require('execa')
const {writeFileSync} = require('fs')
const {join, resolve} = require('path')

const root = resolve(__dirname, '../../..')
const version = require('../package.json').version

const path = join(root, 'primer-version.txt')
writeFileSync(path, version, 'utf8')

const cwd = process.cwd()
execa.sync(join(root, 'script/notify'), ['success'], {cwd, stdio: 'inherit'})
<commit_msg>nix duplicate commit status<commit_after>const execa = require('execa')
const {writeFileSync} = require('fs')
const {join, resolve} = require('path')

const root = resolve(__dirname, '../../..')
const version = require('../package.json').version

const path = join(root, 'primer-version.txt')
writeFileSync(path, version, 'utf8')
<|endoftext|>


<commit_before>/*
 * @package jsDAV
 * @subpackage DAV
 * @copyright Copyright(c) 2011 Ajax.org B.V. <info AT ajax DOT org>
 * @author Mike de Boer <info AT mikedeboer DOT nl>
 * @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
 */

var jsDAV           = require("./../../jsdav"),
    jsDAV_Ftp_Node = require("./node").jsDAV_Ftp_Node,
    jsDAV_Directory = require("./../directory").jsDAV_Directory,
    jsDAV_iFile     = require("./../iFile").jsDAV_iFile,

    Fs              = require("fs"),
    Exc             = require("./../exceptions"),
    Util            = require("./../util");

var Path = require("path");

function jsDAV_Ftp_File(path, ftp) {
    this.path = path || "";
    this.ftp = ftp;
}

exports.jsDAV_Ftp_File = jsDAV_Ftp_File;

(function() {
    this.implement(jsDAV_iFile);

    /**
     * Creates or updates the data of this node
     *
     * @param {mixed} data
     * @return void
     */
    this.put = function(data, type, cbftpput) {
        var path = this.path;
        var ftp  = this.ftp;
        var cached = ftp.$cache[path];

        if (cached && cached.$stat && cached.$stat.target)
            path = Path.resolve(Path.dirname(path), cached.$stat.target);

        if (!Buffer.isBuffer(data))
            data = new Buffer(data, type || "binary");

        ftp.put(path, data, function(err) {
            if (err)
                return cbftpput(err);
            // @todo what about parent node's cache??
            delete ftp.$cache[path];
            cbftpput();
        });
    };

    /**
     * Returns the data
     *
     * @return Buffer
     */
    this.get = function(cbftpfileget) {
        var path = this.path;
        var cached = this.ftp.$cache[path];

        if (cached && cached.$stat && cached.$stat.target)
            path = Path.resolve(Path.dirname(path), cached.$stat.target);

        this.ftp.get(path, function(err, data) {
            cbftpfileget(err, data && data.toString("utf8"));
        });
    };

    /**
     * Delete the current file
     *
     * @return void
     */
    this["delete"] = function(cbftpfiledel) {
        var path = this.path
        this.ftp.raw.dele(path, function(err){
            if (err)
                return cbftpfiledel(new Exc.jsDAV_Exception_FileNotFound(
                        "File " + path + " not found"));

            delete self.ftp.$cache[path];
            cbftpfiledel();
        });
    };

    /**
     * Returns the size of the node, in bytes
     *
     * @return int
     */
    this.getSize = function(cbftpgetsize) {
        var path = this.path;
        var cached = this.ftp.$cache[path];

        if (cached && cached.$stat) {
            if (cached.$stat.target)
                path = Path.resolve(Path.dirname(path), cached.$stat.target);

            cbftpgetsize(null, cached.$stat.size);
        }
        else {
            cbftpgetsize("The file '"+ path + "' was not cached and its information couldn't be determined");
        }
    };

    /**
     * Returns the ETag for a file
     * An ETag is a unique identifier representing the current version of the file.
     * If the file changes, the ETag MUST change.
     * Return null if the ETag can not effectively be determined
     *
     * @return mixed
     */
    this.getETag = function(cbftpgetetag) {
        cbftpgetetag(null, null);
    };

    /**
     * Returns the mime-type for a file
     * If null is returned, we'll assume application/octet-stream
     *
     * @return mixed
     */
    this.getContentType = function(cbftpmime) {
        return cbftpmime(null, Util.mime.type(this.path));
    };
}).call(jsDAV_Ftp_File.prototype = new jsDAV_Ftp_Node());
<commit_msg>Fixed missing variable.<commit_after>/*
 * @package jsDAV
 * @subpackage DAV
 * @copyright Copyright(c) 2011 Ajax.org B.V. <info AT ajax DOT org>
 * @author Mike de Boer <info AT mikedeboer DOT nl>
 * @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
 */

var jsDAV           = require("./../../jsdav"),
    jsDAV_Ftp_Node = require("./node").jsDAV_Ftp_Node,
    jsDAV_Directory = require("./../directory").jsDAV_Directory,
    jsDAV_iFile     = require("./../iFile").jsDAV_iFile,

    Fs              = require("fs"),
    Exc             = require("./../exceptions"),
    Util            = require("./../util");

var Path = require("path");

function jsDAV_Ftp_File(path, ftp) {
    this.path = path || "";
    this.ftp = ftp;
}

exports.jsDAV_Ftp_File = jsDAV_Ftp_File;

(function() {
    this.implement(jsDAV_iFile);

    /**
     * Creates or updates the data of this node
     *
     * @param {mixed} data
     * @return void
     */
    this.put = function(data, type, cbftpput) {
        var path = this.path;
        var ftp  = this.ftp;
        var cached = ftp.$cache[path];

        if (cached && cached.$stat && cached.$stat.target)
            path = Path.resolve(Path.dirname(path), cached.$stat.target);

        if (!Buffer.isBuffer(data))
            data = new Buffer(data, type || "binary");

        ftp.put(path, data, function(err) {
            if (err)
                return cbftpput(err);
            // @todo what about parent node's cache??
            delete ftp.$cache[path];
            cbftpput();
        });
    };

    /**
     * Returns the data
     *
     * @return Buffer
     */
    this.get = function(cbftpfileget) {
        var path = this.path;
        var cached = this.ftp.$cache[path];

        if (cached && cached.$stat && cached.$stat.target)
            path = Path.resolve(Path.dirname(path), cached.$stat.target);

        this.ftp.get(path, function(err, data) {
            cbftpfileget(err, data && data.toString("utf8"));
        });
    };

    /**
     * Delete the current file
     *
     * @return void
     */
    this["delete"] = function(cbftpfiledel) {
        var self = this;
        var path = this.path
        this.ftp.raw.dele(path, function(err){
            if (err)
                return cbftpfiledel(new Exc.jsDAV_Exception_FileNotFound(
                        "File " + path + " not found"));

            delete self.ftp.$cache[path];
            cbftpfiledel();
        });
    };

    /**
     * Returns the size of the node, in bytes
     *
     * @return int
     */
    this.getSize = function(cbftpgetsize) {
        var path = this.path;
        var cached = this.ftp.$cache[path];

        if (cached && cached.$stat) {
            if (cached.$stat.target)
                path = Path.resolve(Path.dirname(path), cached.$stat.target);

            cbftpgetsize(null, cached.$stat.size);
        }
        else {
            cbftpgetsize("The file '"+ path + "' was not cached and its information couldn't be determined");
        }
    };

    /**
     * Returns the ETag for a file
     * An ETag is a unique identifier representing the current version of the file.
     * If the file changes, the ETag MUST change.
     * Return null if the ETag can not effectively be determined
     *
     * @return mixed
     */
    this.getETag = function(cbftpgetetag) {
        cbftpgetetag(null, null);
    };

    /**
     * Returns the mime-type for a file
     * If null is returned, we'll assume application/octet-stream
     *
     * @return mixed
     */
    this.getContentType = function(cbftpmime) {
        return cbftpmime(null, Util.mime.type(this.path));
    };
}).call(jsDAV_Ftp_File.prototype = new jsDAV_Ftp_Node());
<|endoftext|>


<commit_before>import fullSchema10203 from 'vets-json-schema/dist/22-10203-schema.json';
import createContactInformationPage from '../../pages/contactInformation';
import createDirectDepositChangePage from '../../pages/directDepositChange';
import createApplicantInformationPage from 'platform/forms/pages/applicantInformation';

import { display10203StemFlow, displayStemEligibility } from '../helpers';

import { activeDuty, benefitSelection, stem, stemEligibility } from '../pages';

export const chapters = {
  applicantInformation: {
    title: 'Applicant Information',
    pages: {
      applicantInformation: createApplicantInformationPage(fullSchema10203, {
        isVeteran: true,
        fields: [
          'veteranFullName',
          'veteranSocialSecurityNumber',
          'view:noSSN',
          'vaFileNumber',
        ],
        required: ['veteranFullName'],
      }),
    },
  },
  benefitSelection: {
    title: 'Education Benefit',
    pages: {
      benefitSelection: {
        title: 'Education benefit selection',
        path: 'benefits/eligibility',
        uiSchema: benefitSelection.uiSchema,
        schema: benefitSelection.schema,
      },
      stem: {
        title: 'Rogers STEM Scholarship',
        path: 'benefits/stem',
        uiSchema: stem.uiSchema,
        schema: stem.schema,
      },
      stemEligibility: {
        title: 'Rogers STEM Scholarship eligibility',
        path: 'benefits/stem-eligibility',
        pageClass: 'vads-u-max-width--100 vads-u-vads-u-width--full',
        depends: form => displayStemEligibility(form),
        uiSchema: stemEligibility.uiSchema,
        schema: stemEligibility.schema,
      },
    },
  },
  militaryService: {
    title: 'Military History',
    pages: {
      activeDuty: {
        title: 'Active Duty',
        path: 'active-duty',
        depends: display10203StemFlow,
        uiSchema: activeDuty.uiSchema,
        schema: activeDuty.schema,
      },
    },
  },
  personalInformation: {
    title: 'Personal Information',
    pages: {
      contactInformation: createContactInformationPage(fullSchema10203),
      directDeposit: createDirectDepositChangePage(fullSchema10203),
    },
  },
};
<commit_msg>Update Chapter 1 of 10203 Form Workflow to match the prototype (#13223)<commit_after>import fullSchema10203 from 'vets-json-schema/dist/22-10203-schema.json';
import createContactInformationPage from '../../pages/contactInformation';
import createDirectDepositChangePage from '../../pages/directDepositChange';
import createApplicantInformationPage from 'platform/forms/pages/applicantInformation';

import { display10203StemFlow, displayStemEligibility } from '../helpers';

import { activeDuty, benefitSelection, stem, stemEligibility } from '../pages';

export const chapters = {
  applicantInformation: {
    title: 'Applicant Information',
    pages: {
      applicantInformation: createApplicantInformationPage(fullSchema10203, {
        isVeteran: true,
        fields: ['veteranFullName', 'veteranSocialSecurityNumber'],
        required: ['veteranFullName'],
      }),
    },
  },
  benefitSelection: {
    title: 'Education Benefit',
    pages: {
      benefitSelection: {
        title: 'Education benefit selection',
        path: 'benefits/eligibility',
        uiSchema: benefitSelection.uiSchema,
        schema: benefitSelection.schema,
      },
      stem: {
        title: 'Rogers STEM Scholarship',
        path: 'benefits/stem',
        uiSchema: stem.uiSchema,
        schema: stem.schema,
      },
      stemEligibility: {
        title: 'Rogers STEM Scholarship eligibility',
        path: 'benefits/stem-eligibility',
        pageClass: 'vads-u-max-width--100 vads-u-vads-u-width--full',
        depends: form => displayStemEligibility(form),
        uiSchema: stemEligibility.uiSchema,
        schema: stemEligibility.schema,
      },
    },
  },
  militaryService: {
    title: 'Military History',
    pages: {
      activeDuty: {
        title: 'Active Duty',
        path: 'active-duty',
        depends: display10203StemFlow,
        uiSchema: activeDuty.uiSchema,
        schema: activeDuty.schema,
      },
    },
  },
  personalInformation: {
    title: 'Personal Information',
    pages: {
      contactInformation: createContactInformationPage(fullSchema10203),
      directDeposit: createDirectDepositChangePage(fullSchema10203),
    },
  },
};
<|endoftext|>


<commit_before>var request   = require('request-promise');
var Sequelize = require('sequelize');
var db        = require('./lib/models/db')(Sequelize);

var promiseToGetAuthorizationToken = function(code, options={}){
  console.log("Starting Request...");
  return request({
    url: 'https://slack.com/api/oauth.access',
    method: 'POST',
    form: {
      client_id: (options.client_id || process.env.CLIENT_ID),
      client_secret: (options.client_secret || process.env.CLIENT_SECRET),
      code: code
    }
  });
};

var promiseToSaveAuthorization = function(responseString){
  console.log("Received Request...");
  var response = JSON.parse(responseString);
  console.log(JSON.stringify(response));

  console.log("Looking up Team by slack_id: " + response.team_id);
  return db.team.findOrCreate({ where: { slack_id: response.team_id } }).spread(
    (team, created) => { return db.authorization.create({ details: response }); }
  );
};

exports.handler = (event, context, callback) => {
  //console.log("\nENV: \n" + JSON.stringify(process.env) + "\n\n");
  console.log("\nEvent: \n" + JSON.stringify(event) + "\n\n");
  //console.log("\nContext: \n" + JSON.stringify(context) + "\n\n");

  var success = function(){
    console.log("Declaring Success");
    callback(null, {
      statusCode: 200,
      body: "Hi! From the API.",
      isBase64Encoded: false
    });
  };

  var handleError = (failure) => {
    console.log("Encountered an Error");
    console.log(failure);
    callback(new Error('internal server error'));
  };

  var code = event.queryStringParameters.code;
  //promiseToGetAuthorizationToken(code).then(
  //  promiseToSaveAuthorization).then(
  //    function(){ console.log(arguments); }
  //).then(success);
  success();
};
<commit_msg>Connection closing code.<commit_after>var request   = require('request-promise');
var Sequelize = require('sequelize');
var db        = require('./lib/models/db')(Sequelize);

// Ask Slack to provide tokens for us to store and use later.
var promiseToGetAuthorizationToken = function(code, options={}){
  console.log("Starting Request...");
  return request({
    url: 'https://slack.com/api/oauth.access',
    method: 'POST',
    form: {
      client_id: (options.client_id || process.env.CLIENT_ID),
      client_secret: (options.client_secret || process.env.CLIENT_SECRET),
      code: code
    }
  });
};

var promiseToSaveAuthorization = function(responseString){
  console.log("Received Request...");
  var response = JSON.parse(responseString);
  console.log(JSON.stringify(response));

  console.log("Looking up Team by slack_id: " + response.team_id);
  return db.team.findOrCreate({ where: { slack_id: response.team_id } }).spread(
    (team, created) => { return db.authorization.create({ details: response }); }
  );
};

// Sequelize needs to be instructed to close db connections
// so that Lambda can exit gracefully
var promiseToCloseConnections = function(){
  db.sequelize.sync().then(function() {
    console.log("handles before:", process._getActiveHandles().length);
    return db.sequelize.close().then(function() {
      console.log("handles after:", process._getActiveHandles().length);
    });
  });
};

exports.handler = (event, context, callback) => {
  //console.log("\nENV: \n" + JSON.stringify(process.env) + "\n\n");
  console.log("\nEvent: \n" + JSON.stringify(event) + "\n\n");
  //console.log("\nContext: \n" + JSON.stringify(context) + "\n\n");

  var success = function(){
    console.log("Declaring Success");
    callback(null, {
      statusCode: 200,
      body: "Hi! You've added Quackbot to your team!",
      isBase64Encoded: false
    });
  };

  var handleError = (failure) => {
    console.log("Encountered an Error");
    console.log(failure);
    callback(new Error('internal server error'));
  };

  var code = event.queryStringParameters.code;
  Promise.all([
    promiseToGetAuthorizationToken(code),
    promiseToSaveAuthorization,
    promiseToCloseConnections
  ]).then(success, handleError);
};
<|endoftext|>