<commit_before>
module.exports = appinit;

appinit.usage = "\nfhc appinit <app-id> <app-key> [<params>]";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common.js");
var util = require('util');
var ini = require('./utils/ini');
var request = require('request');
var read = require('./read.js').read;

// main appinit entry point
function appinit (args, cb) {
  if (args.length < 2) return cb(appinit.usage);

  var appId = fhc.appId(args[0]);
  var appKey = args[1];
  var data = args[2] ? JSON.parse(args[2]): {};
  log.silly(data, "act params");

  doMillicoreInit(appId, appKey, data, cb);
}

function doMillicoreInit(appId, appKey, data, cb) {
  log.silly(appKey, "appKey");
  var dataToSend = JSON.parse(JSON.stringify(data));
  dataToSend.appid = appId;
  dataToSend.appkey = appKey;
  dataToSend.destination = 'fhc';
  dataToSend.cuid = '12345678790123456787901234567879012';
  fhreq.POST(fhreq.getFeedHenryUrl(), "box/srv/1.1/app/init", dataToSend, function (err, remoteData, raw, response) {
    if (err) {
      log.verbose("Error in init: " + err);
      log.verbose(remoteData, "list");
      return cb(err);
    }
    return cb(err, remoteData);
  });
}

// bash completion
appinit.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;

  // only complete for 3'rd param, i.e. 'fhc appinit <tab>'
  if (argv.length === 2) {
    common.getAppIds(cb);
  }
};
<commit_msg>Setting the sdk_version in appinit.js<commit_after>
module.exports = appinit;

appinit.usage = "\nfhc appinit <app-id> <app-key> [<params>]";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common.js");
var util = require('util');
var ini = require('./utils/ini');
var request = require('request');
var read = require('./read.js').read;

// main appinit entry point
function appinit (args, cb) {
  if (args.length < 2) return cb(appinit.usage);

  var appId = fhc.appId(args[0]);
  var appKey = args[1];
  var data = args[2] ? JSON.parse(args[2]): {};
  log.silly(data, "act params");

  doMillicoreInit(appId, appKey, data, cb);
}

function doMillicoreInit(appId, appKey, data, cb) {
  log.silly(appKey, "appKey");
  var dataToSend = JSON.parse(JSON.stringify(data));
  dataToSend.appid = appId;
  dataToSend.appkey = appKey;
  dataToSend.destination = 'fhc';
  dataToSend.cuid = '12345678790123456787901234567879012';
  dataToSend.sdk_version = 'FHC_SDK';
  fhreq.POST(fhreq.getFeedHenryUrl(), "box/srv/1.1/app/init", dataToSend, function (err, remoteData, raw, response) {
    if (err) {
      log.verbose("Error in init: " + err);
      log.verbose(remoteData, "list");
      return cb(err);
    }
    return cb(err, remoteData);
  });
}

// bash completion
appinit.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;

  // only complete for 3'rd param, i.e. 'fhc appinit <tab>'
  if (argv.length === 2) {
    common.getAppIds(cb);
  }
};
<|endoftext|>


<commit_before>module.exports = Archiver;

var http = require('http');
var os = require('os');
var xtend = require('xtend');

var util = require('./util');
var version = require("../package.json").version;

var HOSTNAME = os.hostname();
var DEFAULTS = {
  skipArchive: false,
  archiveInterval: 60000,
  proxyHost: "localhost",
  proxyPort: "9090",
  proxyPath: "/results",
}

function Archiver(aggregator, options) {
  if (!(this instanceof Archiver)) return new Archiver(aggregator, options);

  this.aggregator = aggregator;
  this.options = xtend(DEFAULTS, options);
}

Archiver.prototype.start = function start() {
  this.aggregator.reset();
  if (this.interval || this.options.skipArchive) {
    return;
  }
  this.interval = setInterval(this.send.bind(this), this.options.archiveInterval);
}

Archiver.prototype.unref = function unref() {
  if (this.interval) {
    this.interval.unref();
  }
}

// This is a stop-gap solution to sending out finalized data.
// At most we will miss the last CLEANUP_INTERVAL millis of data.
Archiver.prototype._checkFinished = function _checkFinished() {
  if (!this.interval) {
    return;
  }
  // If there is more data, don't quit until it is sent.
  if (this.aggregator.windowStart != null) {
    this.interval.ref();
  }
}

Archiver.prototype.finish = function finish() {
  this.send();
  this.stop();
}

Archiver.prototype.stop = function stop() {
  clearInterval(this.interval);
  this.aggregator.stop();
}

Archiver.prototype.send = function send() {
  if (this.aggregator.windowStart == null) {
    //console.log("Skipping because tracer has nothing to send.")
    this.unref();
    return;
  }

  if (this.options.skipArchive) {
    //console.log("Skipping due to skipArchive setting")
    return;
  }

  this.aggregator.stopTracing();
  var body = Buffer(JSON.stringify(this.computePackage()));
  this.aggregator.resetTimes();

  //console.log("Sending packet that is %s bytes.", body.length);
  var options = {
    agent: false,
    host: this.options.proxyHost,
    port: this.options.proxyPort,
    path: this.options.proxyPath,
    method: "POST",
    headers: {
      "Concurix-API-Key": this.options.accountKey,
      "content-type": "application/json",
      "content-length": body.length
    }
  };

  var self = this
  var request = http.request(options, function (res) {
    self.aggregator.stopTracing();
    if (res.statusCode != 202) {
      console.log("Failed to send archive to Concurix: %s", res.statusCode);
    }
    res.socket.unref();
    self.aggregator.startTracing();
  });
  request.end(body);
  request.on("error", function (err) {
    console.log("Error attempting to send trace file: %s", err);
  })
  this.unref();
  this.aggregator.startTracing();
}

Archiver.prototype.computePackage = function computePackage() {
  //quick validation
  var links = this.aggregator.linkCache;
  var nodes = this.aggregator.nodeCache;
  var linkKeys = Object.keys(links);
  for (var i = 0; i < linkKeys.length; i++) {
    var key = linkKeys[i];
    if( !nodes[links[key].source] || !nodes[links[key].target]){
      console.log('yikes, missing node for link ', links[key]);
    } else {
      //console.log('got it');
    }
  }

  var msg = {
    type: "nodejs",
    version: version,
    tracing_interval: this.options.archiveInterval,
    hostname: HOSTNAME,
    pid: process.pid,
    // run_id: 'to be set',
    // TODO move these two into system_info -- will require aggregation server change.
    load_avg: os.loadavg(), //array of 1, 5, and 15 minute load averages
    cpus: os.cpus(),
    process_info: {
      memory: process.memoryUsage(),
      uptime: process.uptime(),
      active_requests: process._getActiveRequests().length,
      active_handles: process._getActiveHandles().length,
      versions: process.versions,
      environment: this.options.environment,
    },
    system_info: {
      freemem: os.freemem(),
      totalmem: os.totalmem(),
      arch: process.arch,
      platform: process.platform,
      uptime: os.uptime(),
    },
    timestamp: util.unixTimeSec(),
    data: {
      nodes:   util.values(nodes),
      links:   util.values(links)
    }
  };
  // console.log(msg)
  return msg;
}
<commit_msg>Update with production proxyHost<commit_after>module.exports = Archiver;

var http = require('http');
var os = require('os');
var xtend = require('xtend');

var util = require('./util');
var version = require("../package.json").version;

var HOSTNAME = os.hostname();
var DEFAULTS = {
  skipArchive: false,
  archiveInterval: 60000,
  proxyHost: "results.concurix.com",
  proxyPort: "9090",
  proxyPath: "/results",
}

function Archiver(aggregator, options) {
  if (!(this instanceof Archiver)) return new Archiver(aggregator, options);

  this.aggregator = aggregator;
  this.options = xtend(DEFAULTS, options);
}

Archiver.prototype.start = function start() {
  this.aggregator.reset();
  if (this.interval || this.options.skipArchive) {
    return;
  }
  this.interval = setInterval(this.send.bind(this), this.options.archiveInterval);
}

Archiver.prototype.unref = function unref() {
  if (this.interval) {
    this.interval.unref();
  }
}

// This is a stop-gap solution to sending out finalized data.
// At most we will miss the last CLEANUP_INTERVAL millis of data.
Archiver.prototype._checkFinished = function _checkFinished() {
  if (!this.interval) {
    return;
  }
  // If there is more data, don't quit until it is sent.
  if (this.aggregator.windowStart != null) {
    this.interval.ref();
  }
}

Archiver.prototype.finish = function finish() {
  this.send();
  this.stop();
}

Archiver.prototype.stop = function stop() {
  clearInterval(this.interval);
  this.aggregator.stop();
}

Archiver.prototype.send = function send() {
  if (this.aggregator.windowStart == null) {
    //console.log("Skipping because tracer has nothing to send.")
    this.unref();
    return;
  }

  if (this.options.skipArchive) {
    //console.log("Skipping due to skipArchive setting")
    return;
  }

  this.aggregator.stopTracing();
  var body = Buffer(JSON.stringify(this.computePackage()));
  this.aggregator.resetTimes();

  //console.log("Sending packet that is %s bytes.", body.length);
  var options = {
    agent: false,
    host: this.options.proxyHost,
    port: this.options.proxyPort,
    path: this.options.proxyPath,
    method: "POST",
    headers: {
      "Concurix-API-Key": this.options.accountKey,
      "content-type": "application/json",
      "content-length": body.length
    }
  };

  var self = this
  var request = http.request(options, function (res) {
    self.aggregator.stopTracing();
    if (res.statusCode != 202) {
      console.log("Failed to send archive to Concurix: %s", res.statusCode);
    }
    res.socket.unref();
    self.aggregator.startTracing();
  });
  request.end(body);
  request.on("error", function (err) {
    console.log("Error attempting to send trace file: %s", err);
  })
  this.unref();
  this.aggregator.startTracing();
}

Archiver.prototype.computePackage = function computePackage() {
  //quick validation
  var links = this.aggregator.linkCache;
  var nodes = this.aggregator.nodeCache;
  var linkKeys = Object.keys(links);
  for (var i = 0; i < linkKeys.length; i++) {
    var key = linkKeys[i];
    if( !nodes[links[key].source] || !nodes[links[key].target]){
      console.log('yikes, missing node for link ', links[key]);
    } else {
      //console.log('got it');
    }
  }

  var msg = {
    type: "nodejs",
    version: version,
    tracing_interval: this.options.archiveInterval,
    hostname: HOSTNAME,
    pid: process.pid,
    // run_id: 'to be set',
    // TODO move these two into system_info -- will require aggregation server change.
    load_avg: os.loadavg(), //array of 1, 5, and 15 minute load averages
    cpus: os.cpus(),
    process_info: {
      memory: process.memoryUsage(),
      uptime: process.uptime(),
      active_requests: process._getActiveRequests().length,
      active_handles: process._getActiveHandles().length,
      versions: process.versions,
      environment: this.options.environment,
    },
    system_info: {
      freemem: os.freemem(),
      totalmem: os.totalmem(),
      arch: process.arch,
      platform: process.platform,
      uptime: os.uptime(),
    },
    timestamp: util.unixTimeSec(),
    data: {
      nodes:   util.values(nodes),
      links:   util.values(links)
    }
  };
  // console.log(msg)
  return msg;
}
<|endoftext|>


<commit_before>var Pagelet = require('./pagelet.js');
var status = Pagelet.status;
var mode = Pagelet.mode;
var _ = require('./util.js');
var Readable = require('stream').Readable;
var util = require('util');

var BigPipe = module.exports = function BigPipe(options) {
    this.options = _.mixin(_.mixin({}, BigPipe.options), options);
    this.map = {};
    this.pagelets = [];
    this.pipelines = [];
    this.rendered = [];
    this.sources = {};
    this.state = status.pending;
    this.quicklings = [];
    this.parentQuicklings = [];

    this.on('pagelet:after', this._onPageletDone);
    Readable.call(this, null);
};

// default options
BigPipe.options = {
    skipAnalysis: true,
    // configure output template.
    // you can use the following varible.
    //
    // - this.id            pagelet id
    // - this.js            pagelet js
    // - this.css           pagelet css
    // - this.scripts       pagelet inline scripts
    // - this.styles        pagelet inline css
    // - this.html          pagelet html content
    // - this.container     pagelet container if specified
    // - this.json          stringfied json data.
    tpl: {
        _default: '<script type="text/javascript">' +
            'BigPipe.onPageletArrive(<%= this.json %>);' +
            '</script>',

        quickling: 'BigPipe.onPageletArrive(<%= this.json %>);'
    }
};

util.inherits(BigPipe, Readable);

// don't call this directly.
BigPipe.prototype._read = function (n) {
    if (this.state === status.pending) {
        this.render();
    }
};

// bind pagelet data source.
// accept fucntion and model name.
BigPipe.prototype.bind = function (id, fn) {
    this.sources[id] = fn;
    return this;
};

// 当为 quickling 模式的时候调用。
// 设置后，只有在此列表中的 pagelet 才会渲染。
BigPipe.prototype.addQuicklingPagelets = function (pagelets) {
    var me = this;
    pagelets.forEach(function (id) {
        var pageletIDSplit = id.split('@');
        var pageletID = pageletIDSplit.shift();
        me.quicklings.push(pageletID);
        me.parentQuicklings.push.apply(me.parentQuicklings, pageletIDSplit);
    });
};

// 判断是否是 quickling 模式。
BigPipe.prototype.isQuicklingMode = function () {
    return !!(this.quicklings && this.quicklings.length);
};

// 拼写兼容
BigPipe.prototype.isQuickingMode = BigPipe.prototype.isQuicklingMode;

// 添加 pagelet.
BigPipe.prototype.addPagelet = function (obj) {
    // 已经晚了了，不处理。
    if (this.state === status.fulfilled) {
        return false;
    }
    else if (!obj.id) {
        this.emit('error', new Error('Id is required when add pagelet'));
        return;
    }

    if (!this.isQuicklingMode() && obj.mode !== mode.pipeline && obj.mode !== mode.async) {
        // 非 quickling 请求，只接收 pipeline 和 async 模式的 pagelet.
        return false;
    }
    else if (this.isQuicklingMode() && !~this.quicklings.indexOf(obj.id)) {
        // 以下几种情况均需要继续执行
        // 1. 被声明为父Pagelet
        // 2. 先祖Pagelet被请求了

        if (!~this.parentQuicklings.indexOf(obj.id)) {
            var parent, founded;
            // 如果没有被声明为父Pagelet，则检查是否属于先祖Pagelet被请求了的情况

            // 如果是lazy模式，则不寻找先祖Pagelet
            if (obj.lazy) {
                return false;
            }
            // 支持嵌套pagelet时，一次性返回所有pagelet
            parent = obj;
            founded = false;
            // 如果指定的pagelet不在quicklings列表中，检查先祖节点，查看先祖节点是否在列表中，如果在则加载
            // 以此实现Pagelet A contain Pagelet B时，会用一个请求同时返回A与B
            while (parent && parent.parentId) {
                parent = this.map[parent.parentId];
                if (parent.mode === mode.quickling && !!~this.quicklings.indexOf(parent.id)) {
                    founded = true;
                    // 插入为需要输出的Pagelet
                    this.quicklings.push(obj.id);
                    break;
                }
            }
            if (!founded) {
                return false;
            }
        }
    }

    obj.reqID = this.reqID;
    obj.skipAnalysis = this.options.skipAnalysis;

    var pagelet = new Pagelet(obj);
    var self = this;

    this.pagelets.push(pagelet);
    this.map[pagelet.id] = pagelet;
    pagelet.mode === mode.pipeline && this.pipelines.push(pagelet);

    // 转发事件。
    pagelet.on('error', this.emit.bind(this, 'error'));
    [
        'before', 'after',
        'render:before', 'render:after',
        'analyse:before', 'analyse:after'
    ].forEach(function (name) {
        pagelet.on(name, self.emit.bind(self, 'pagelet:' + name, pagelet));
    });

    if (this.state === status.rendering) {
        this.renderPagelet(pagelet);
    }
};

BigPipe.prototype.render = function () {
    var pagelets = this.pagelets.concat();

    this.state = status.rendering;

    pagelets.forEach(this.renderPagelet.bind(this));
    this._checkFinish();
};

BigPipe.prototype.renderPagelet = function (pagelet) {
    var sources = this.sources;
    var source = sources[pagelet.id];

    if (!source && typeof sources.all === 'function') {
        source = sources.all.bind(null, pagelet.id);
    }

    // hook
    this.emit('pagelet:source', pagelet.id, function (_source) {
        source = _source;
    });

    pagelet.start(source);
};

BigPipe.prototype.destroy = function () {
    this.sources = null;

    this.removeAllListeners();

    this.rendered.concat(this.pagelets).forEach(function (pagelet) {
        pagelet.destroy();
    });

    this.rendered = this.pipelines = this.pagelets = this.map = this.quicklings = null;
};

BigPipe.prototype._onPageletDone = function (pagelet) {
    var cb, idx, item;

    if (pagelet.mode === mode.pipeline) {
        // 必须按顺序
        // idx = this.pipelines.indexOf(pagelet);

        // // if this is not the first pipline pagelet.
        // if (idx !== 0) {
        //     return;
        // }

        // 必须是第一个才开始吐数据。否则等待。
        while ((item = this.pipelines[0]) &&
            item.state === status.fulfilled) {

            this.outputPagelet(item);
        }
    }
    else {
        this.outputPagelet(pagelet);
    }

    process.nextTick(this._checkFinish.bind(this));
};

BigPipe.prototype._checkFinish = function () {
    if (!this.pagelets.length && this.state === status.rendering) {
        // 标记已经完成。
        this.state = status.fulfilled;
        this.push(null);
    }
};

BigPipe.prototype.outputPagelet = function (pagelet) {
    var content = this.format(pagelet);
    if (!this.isQuicklingMode() || !!~this.quicklings.indexOf(pagelet.id)) {
        content && this.push(content);
    }
    this._markPageletRendered(pagelet);
};

BigPipe.prototype.format = function (pagelet) {
    var tpl = this.options.tpl;
    var type = this.isQuicklingMode() ? 'quickling' : '_default';
    var json = pagelet.toJson();
    var obj = {};

    tpl = tpl[type] || tpl['_default'];

    _.mixin(obj, json);
    obj.json = JSON.stringify(json);

    return _.tpl(tpl, obj);
};

BigPipe.prototype._markPageletRendered = function (pagelet) {
    var idx = this.pagelets.indexOf(pagelet);
    var removed = this.pagelets.splice(idx, 1)[0];

    idx = this.pipelines.indexOf(pagelet);
    ~idx && this.pipelines.splice(idx, 1);

    // should I save this?
    this.rendered.push(removed);
};
<commit_msg>fix: should load a child if parent is async<commit_after>var Pagelet = require('./pagelet.js');
var status = Pagelet.status;
var mode = Pagelet.mode;
var _ = require('./util.js');
var Readable = require('stream').Readable;
var util = require('util');

var BigPipe = module.exports = function BigPipe(options) {
    this.options = _.mixin(_.mixin({}, BigPipe.options), options);
    this.map = {};
    this.pagelets = [];
    this.pipelines = [];
    this.rendered = [];
    this.sources = {};
    this.state = status.pending;
    this.quicklings = [];
    this.parentQuicklings = [];

    this.on('pagelet:after', this._onPageletDone);
    Readable.call(this, null);
};

// default options
BigPipe.options = {
    skipAnalysis: true,
    // configure output template.
    // you can use the following varible.
    //
    // - this.id            pagelet id
    // - this.js            pagelet js
    // - this.css           pagelet css
    // - this.scripts       pagelet inline scripts
    // - this.styles        pagelet inline css
    // - this.html          pagelet html content
    // - this.container     pagelet container if specified
    // - this.json          stringfied json data.
    tpl: {
        _default: '<script type="text/javascript">' +
            'BigPipe.onPageletArrive(<%= this.json %>);' +
            '</script>',

        quickling: 'BigPipe.onPageletArrive(<%= this.json %>);'
    }
};

util.inherits(BigPipe, Readable);

// don't call this directly.
BigPipe.prototype._read = function (n) {
    if (this.state === status.pending) {
        this.render();
    }
};

// bind pagelet data source.
// accept fucntion and model name.
BigPipe.prototype.bind = function (id, fn) {
    this.sources[id] = fn;
    return this;
};

// 当为 quickling 模式的时候调用。
// 设置后，只有在此列表中的 pagelet 才会渲染。
BigPipe.prototype.addQuicklingPagelets = function (pagelets) {
    var me = this;
    pagelets.forEach(function (id) {
        var pageletIDSplit = id.split('@');
        var pageletID = pageletIDSplit.shift();
        me.quicklings.push(pageletID);
        me.parentQuicklings.push.apply(me.parentQuicklings, pageletIDSplit);
    });
};

// 判断是否是 quickling 模式。
BigPipe.prototype.isQuicklingMode = function () {
    return !!(this.quicklings && this.quicklings.length);
};

// 拼写兼容
BigPipe.prototype.isQuickingMode = BigPipe.prototype.isQuicklingMode;

// 添加 pagelet.
BigPipe.prototype.addPagelet = function (obj) {
    // 已经晚了了，不处理。
    if (this.state === status.fulfilled) {
        return false;
    }
    else if (!obj.id) {
        this.emit('error', new Error('Id is required when add pagelet'));
        return;
    }

    if (!this.isQuicklingMode() && obj.mode !== mode.pipeline && obj.mode !== mode.async) {
        // 非 quickling 请求，只接收 pipeline 和 async 模式的 pagelet.
        return false;
    }
    else if (this.isQuicklingMode() && !~this.quicklings.indexOf(obj.id)) {
        // 以下几种情况均需要继续执行
        // 1. 被声明为父Pagelet
        // 2. 先祖Pagelet被请求了

        if (!~this.parentQuicklings.indexOf(obj.id)) {
            var parent, founded;
            // 如果没有被声明为父Pagelet，则检查是否属于先祖Pagelet被请求了的情况

            // 如果是lazy模式，则不寻找先祖Pagelet
            if (obj.lazy) {
                return false;
            }
            // 支持嵌套pagelet时，一次性返回所有pagelet
            parent = obj;
            founded = false;
            // 如果指定的pagelet不在quicklings列表中，检查先祖节点，查看先祖节点是否在列表中，如果在则加载
            // 以此实现Pagelet A contain Pagelet B时，会用一个请求同时返回A与B
            while (parent && parent.parentId) {
                parent = this.map[parent.parentId];
                if (this.isQuicklingWidget(parent) && !!~this.quicklings.indexOf(parent.id)) {
                    founded = true;
                    // 插入为需要输出的Pagelet
                    this.quicklings.push(obj.id);
                    break;
                }
            }
            if (!founded) {
                return false;
            }
        }
    }

    obj.reqID = this.reqID;
    obj.skipAnalysis = this.options.skipAnalysis;

    var pagelet = new Pagelet(obj);
    var self = this;

    this.pagelets.push(pagelet);
    this.map[pagelet.id] = pagelet;
    pagelet.mode === mode.pipeline && this.pipelines.push(pagelet);

    // 转发事件。
    pagelet.on('error', this.emit.bind(this, 'error'));
    [
        'before', 'after',
        'render:before', 'render:after',
        'analyse:before', 'analyse:after'
    ].forEach(function (name) {
        pagelet.on(name, self.emit.bind(self, 'pagelet:' + name, pagelet));
    });

    if (this.state === status.rendering) {
        this.renderPagelet(pagelet);
    }
};

BigPipe.prototype.isQuicklingWidget = function (item) {
    return (item.mode === mode.quickling || item.mode === mode.async || item.mode === mode.pipeline);
}

BigPipe.prototype.render = function () {
    var pagelets = this.pagelets.concat();

    this.state = status.rendering;

    pagelets.forEach(this.renderPagelet.bind(this));
    this._checkFinish();
};

BigPipe.prototype.renderPagelet = function (pagelet) {
    var sources = this.sources;
    var source = sources[pagelet.id];

    if (!source && typeof sources.all === 'function') {
        source = sources.all.bind(null, pagelet.id);
    }

    // hook
    this.emit('pagelet:source', pagelet.id, function (_source) {
        source = _source;
    });

    pagelet.start(source);
};

BigPipe.prototype.destroy = function () {
    this.sources = null;

    this.removeAllListeners();

    this.rendered.concat(this.pagelets).forEach(function (pagelet) {
        pagelet.destroy();
    });

    this.rendered = this.pipelines = this.pagelets = this.map = this.quicklings = null;
};

BigPipe.prototype._onPageletDone = function (pagelet) {
    var cb, idx, item;

    if (pagelet.mode === mode.pipeline) {
        // 必须按顺序
        // idx = this.pipelines.indexOf(pagelet);

        // // if this is not the first pipline pagelet.
        // if (idx !== 0) {
        //     return;
        // }

        // 必须是第一个才开始吐数据。否则等待。
        while ((item = this.pipelines[0]) &&
            item.state === status.fulfilled) {

            this.outputPagelet(item);
        }
    }
    else {
        this.outputPagelet(pagelet);
    }

    process.nextTick(this._checkFinish.bind(this));
};

BigPipe.prototype._checkFinish = function () {
    if (!this.pagelets.length && this.state === status.rendering) {
        // 标记已经完成。
        this.state = status.fulfilled;
        this.push(null);
    }
};

BigPipe.prototype.outputPagelet = function (pagelet) {
    var content = this.format(pagelet);
    if (!this.isQuicklingMode() || !!~this.quicklings.indexOf(pagelet.id)) {
        content && this.push(content);
    }
    this._markPageletRendered(pagelet);
};

BigPipe.prototype.format = function (pagelet) {
    var tpl = this.options.tpl;
    var type = this.isQuicklingMode() ? 'quickling' : '_default';
    var json = pagelet.toJson();
    var obj = {};

    tpl = tpl[type] || tpl['_default'];

    _.mixin(obj, json);
    obj.json = JSON.stringify(json);

    return _.tpl(tpl, obj);
};

BigPipe.prototype._markPageletRendered = function (pagelet) {
    var idx = this.pagelets.indexOf(pagelet);
    var removed = this.pagelets.splice(idx, 1)[0];

    idx = this.pipelines.indexOf(pagelet);
    ~idx && this.pipelines.splice(idx, 1);

    // should I save this?
    this.rendered.push(removed);
};
<|endoftext|>


<commit_before>//require the c++ bindings & export to javascript
var binding = require(__dirname + '/../build/default/binding');
var Connection = binding.Connection;
var p = Connection.prototype;

var add = function(params, config, paramName) {
  var value = config[paramName];
  if(value) {
    params.push(paramName+"='"+value+"'");
  }
}

var getLibpgConString = function(config, callback) {
  var params = []
  if(typeof config == 'object') {
    add(params, config, 'user');
    add(params, config, 'password');
    add(params, config, 'port');
    if(config.database) {
      params.push("dbname='" + config.database + "'");
    }
    if(config.host) {
      if(config.host != 'localhost') {
        throw new Exception("Need to use node to do async DNS on host");
      }
      params.push("hostaddr=127.0.0.1 ");
    }
  }
  callback(params.join(" "));
}

var nativeConnect = p.connect;

p.connect = function() {
  var self = this;
  getLibpgConString(this._config, function(conString) {
    console.log("connecting with connection string '%s'", conString);
    nativeConnect.call(self, conString);
  })
}

p.query = function(queryString) {
  console.log("pushing '%s' as query", queryString);
  this._queryQueue.push(queryString);
  this._pulseQueryQueue();
  return this;
}

p._pulseQueryQueue = function() {
  console.log('pulsing query queue');
  if(!this._connected) {
    console.log("not connected");
    return;
  }
  if(this._activeQuery) {
    console.log("already have active query");
    return;
  }
  var query = this._queryQueue.shift();
  if(!query) {
    this.emit('drain');
    return;
  }
  console.log("dispatching query: '%s'", query);
  this._sendQuery(query);
}

var ctor = function(config) {
  var connection = new Connection();
  connection._queryQueue = [];
  connection._activeQuery = null;
  connection._config = config;
  connection.on('connect', function() {
    connection._connected = true;
    connection._pulseQueryQueue();
  });
  connection.on('readyForQuery', function() {
    this.emit('end');
    this._activeQuery = null;
    connection._pulseQueryQueue();
  })
  return connection;
}

module.exports = {
  Client:ctor
};
<commit_msg>remove debug logging<commit_after>//require the c++ bindings & export to javascript
var binding = require(__dirname + '/../build/default/binding');
var Connection = binding.Connection;
var p = Connection.prototype;

var add = function(params, config, paramName) {
  var value = config[paramName];
  if(value) {
    params.push(paramName+"='"+value+"'");
  }
}

var getLibpgConString = function(config, callback) {
  var params = []
  if(typeof config == 'object') {
    add(params, config, 'user');
    add(params, config, 'password');
    add(params, config, 'port');
    if(config.database) {
      params.push("dbname='" + config.database + "'");
    }
    if(config.host) {
      if(config.host != 'localhost') {
        throw new Exception("Need to use node to do async DNS on host");
      }
      params.push("hostaddr=127.0.0.1 ");
    }
  }
  callback(params.join(" "));
}

var nativeConnect = p.connect;

p.connect = function() {
  var self = this;
  getLibpgConString(this._config, function(conString) {
    nativeConnect.call(self, conString);
  })
}

p.query = function(queryString) {
  this._queryQueue.push(queryString);
  this._pulseQueryQueue();
  return this;
}

p._pulseQueryQueue = function() {
  if(!this._connected) {
    return;
  }
  if(this._activeQuery) {
    return;
  }
  var query = this._queryQueue.shift();
  if(!query) {
    this.emit('drain');
    return;
  }
  this._sendQuery(query);
}

var ctor = function(config) {
  var connection = new Connection();
  connection._queryQueue = [];
  connection._activeQuery = null;
  connection._config = config;
  connection.on('connect', function() {
    connection._connected = true;
    connection._pulseQueryQueue();
  });
  connection.on('readyForQuery', function() {
    this.emit('end');
    this._activeQuery = null;
    connection._pulseQueryQueue();
  })
  return connection;
}

module.exports = {
  Client:ctor
};
<|endoftext|>


<commit_before>import number from "./number.js";
import identity from "./identity.js";

export default function quantile(values, p, valueof = number) {
  values = Array.from(values)
    .map((d, i) => valueof(d, i, values))
    .filter(v => !isNaN(v))
    .sort((a, b) => a - b);
  var n = values.length;
  if (!n) return;
  if ((p = +p) <= 0 || n < 2) return +values[0];
  if (p >= 1) return +values.pop();
  return quantileSorted(values, p, identity);
}

export function quantileSorted(values, p, valueof = number) {
  if (!(n = values.length)) return;
  if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
  if (p >= 1) return +valueof(values[n - 1], n - 1, values);
  var n,
      i = (n - 1) * p,
      i0 = Math.floor(i),
      value0 = +valueof(values[i0], i0, values),
      value1 = +valueof(values[i0 + 1], i0 + 1, values);
  return value0 + (value1 - value0) * (i - i0);
}
<commit_msg>use numbers* and remove cruft<commit_after>import {default as number, numbers} from "./number.js";

export default function quantile(values, p, valueof = number) {
  values = Float64Array.from(numbers(values, valueof))
    .filter(v => !isNaN(v))
    .sort((a, b) => a - b);
  return quantileSorted(values, p);
}

export function quantileSorted(values, p, valueof = number) {
  if (!(n = values.length)) return;
  if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
  if (p >= 1) return +valueof(values[n - 1], n - 1, values);
  var n,
      i = (n - 1) * p,
      i0 = Math.floor(i),
      value0 = +valueof(values[i0], i0, values),
      value1 = +valueof(values[i0 + 1], i0 + 1, values);
  return value0 + (value1 - value0) * (i - i0);
}
<|endoftext|>


<commit_before>var helper = require('./helper')
var events = require('./events')
var logger = require('./logger')

var Result = require('./browser_result')

// The browser is ready to execute tests.
var READY = 1

// The browser is executing the tests.
var EXECUTING = 2

// The browser is not executing, but temporarily disconnected (waiting for reconnecting).
var READY_DISCONNECTED = 3

// The browser is executing the tests, but temporarily disconnect (waiting for reconnecting).
var EXECUTING_DISCONNECTED = 4

// The browser got permanently disconnected (being removed from the collection and destroyed).
var DISCONNECTED = 5

var Browser = function (id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
  /* config.browserDisconnectTimeout */ disconnectDelay,
  /* config.browserNoActivityTimeout */ noActivityTimeout) {
  var name = helper.browserFullNameToShort(fullName)
  var log = logger.create(name)
  var activeSockets = [socket]
  var activeSocketsIds = function () {
    return activeSockets.map(function (s) {
      return s.id
    }).join(', ')
  }

  var self = this
  var pendingDisconnect
  var disconnect = function (reason) {
    self.state = DISCONNECTED
    self.disconnectsCount++
    log.warn('Disconnected (%d times)' + (reason || ''), self.disconnectsCount)
    emitter.emit('browser_error', self, 'Disconnected' + reason)
    collection.remove(self)
  }

  var noActivityTimeoutId
  var refreshNoActivityTimeout = noActivityTimeout ? function () {
    clearNoActivityTimeout()
    noActivityTimeoutId = timer.setTimeout(function () {
      self.lastResult.totalTimeEnd()
      self.lastResult.disconnected = true
      disconnect(', because no message in ' + noActivityTimeout + ' ms.')
      emitter.emit('browser_complete', self)
    }, noActivityTimeout)
  } : function () {}

  var clearNoActivityTimeout = noActivityTimeout ? function () {
    if (noActivityTimeoutId) {
      timer.clearTimeout(noActivityTimeoutId)
      noActivityTimeoutId = null
    }
  } : function () {}

  this.id = id
  this.fullName = fullName
  this.name = name
  this.state = READY
  this.lastResult = new Result()
  this.disconnectsCount = 0

  this.init = function () {
    collection.add(this)

    events.bindAll(this, socket)

    log.info('Connected on socket %s with id %s', socket.id, id)

    // TODO(vojta): move to collection
    emitter.emit('browsers_change', collection)

    emitter.emit('browser_register', this)
  }

  this.isReady = function () {
    return this.state === READY
  }

  this.toString = function () {
    return this.name
  }

  this.onKarmaError = function (error) {
    if (this.isReady()) {
      return
    }

    this.lastResult.error = true
    emitter.emit('browser_error', this, error)

    refreshNoActivityTimeout()
  }

  this.onInfo = function (info) {
    if (this.isReady()) {
      return
    }

    // TODO(vojta): remove
    if (helper.isDefined(info.dump)) {
      emitter.emit('browser_log', this, info.dump, 'dump')
    }

    if (helper.isDefined(info.log)) {
      emitter.emit('browser_log', this, info.log, info.type)
    }

    if (
      !helper.isDefined(info.log) &&
      !helper.isDefined(info.dump)
    ) {
      emitter.emit('browser_info', this, info)
    }

    refreshNoActivityTimeout()
  }

  this.onStart = function (info) {
    this.lastResult = new Result()
    this.lastResult.total = info.total

    if (info.total === null) {
      log.warn('Adapter did not report total number of specs.')
    }

    emitter.emit('browser_start', this, info)
    refreshNoActivityTimeout()
  }

  this.onComplete = function (result) {
    if (this.isReady()) {
      return
    }

    this.state = READY
    this.lastResult.totalTimeEnd()

    if (!this.lastResult.success) {
      this.lastResult.error = true
    }

    emitter.emit('browsers_change', collection)
    emitter.emit('browser_complete', this, result)

    clearNoActivityTimeout()
  }

  this.onDisconnect = function (_, disconnectedSocket) {
    activeSockets.splice(activeSockets.indexOf(disconnectedSocket), 1)

    if (activeSockets.length) {
      log.debug('Disconnected %s, still have %s', disconnectedSocket.id, activeSocketsIds())
      return
    }

    if (this.state === READY) {
      disconnect()
    } else if (this.state === EXECUTING) {
      log.debug('Disconnected during run, waiting %sms for reconnecting.', disconnectDelay)
      this.state = EXECUTING_DISCONNECTED

      pendingDisconnect = timer.setTimeout(function () {
        self.lastResult.totalTimeEnd()
        self.lastResult.disconnected = true
        disconnect()
        emitter.emit('browser_complete', self)
      }, disconnectDelay)

      clearNoActivityTimeout()
    }
  }

  this.reconnect = function (newSocket) {
    if (this.state === EXECUTING_DISCONNECTED) {
      this.state = EXECUTING
      log.debug('Reconnected on %s.', newSocket.id)
    } else if (this.state === EXECUTING || this.state === READY) {
      log.debug('New connection %s (already have %s)', newSocket.id, activeSocketsIds())
    } else if (this.state === DISCONNECTED) {
      this.state = READY
      log.info('Connected on socket %s with id %s', newSocket.id, this.id)
      collection.add(this)

      // TODO(vojta): move to collection
      emitter.emit('browsers_change', collection)

      emitter.emit('browser_register', this)
    }

    var exists = activeSockets.some(function (s) {
      return s.id === newSocket.id
    })
    if (!exists) {
      activeSockets.push(newSocket)
      events.bindAll(this, newSocket)
    }

    if (pendingDisconnect) {
      timer.clearTimeout(pendingDisconnect)
    }

    refreshNoActivityTimeout()
  }

  this.onResult = function (result) {
    if (result.length) {
      return result.forEach(this.onResult, this)
    }

    // ignore - probably results from last run (after server disconnecting)
    if (this.isReady()) {
      return
    }

    this.lastResult.add(result)

    emitter.emit('spec_complete', this, result)
    refreshNoActivityTimeout()
  }

  this.serialize = function () {
    return {
      id: this.id,
      name: this.name,
      isReady: this.state === READY
    }
  }

  this.execute = function (config) {
    activeSockets.forEach(function (socket) {
      socket.emit('execute', config)
    })

    this.state = EXECUTING
    refreshNoActivityTimeout()
  }
}

Browser.STATE_READY = READY
Browser.STATE_EXECUTING = EXECUTING
Browser.STATE_READY_DISCONNECTED = READY_DISCONNECTED
Browser.STATE_EXECUTING_DISCONNECTED = EXECUTING_DISCONNECTED
Browser.STATE_DISCONNECTED = DISCONNECTED

module.exports = Browser
<commit_msg>fix(browser): nicer "disconnect" - no more "Disconnectedundefined"<commit_after>var helper = require('./helper')
var events = require('./events')
var logger = require('./logger')

var Result = require('./browser_result')

// The browser is ready to execute tests.
var READY = 1

// The browser is executing the tests.
var EXECUTING = 2

// The browser is not executing, but temporarily disconnected (waiting for reconnecting).
var READY_DISCONNECTED = 3

// The browser is executing the tests, but temporarily disconnect (waiting for reconnecting).
var EXECUTING_DISCONNECTED = 4

// The browser got permanently disconnected (being removed from the collection and destroyed).
var DISCONNECTED = 5

var Browser = function (id, fullName, /* capturedBrowsers */ collection, emitter, socket, timer,
  /* config.browserDisconnectTimeout */ disconnectDelay,
  /* config.browserNoActivityTimeout */ noActivityTimeout) {
  var name = helper.browserFullNameToShort(fullName)
  var log = logger.create(name)
  var activeSockets = [socket]
  var activeSocketsIds = function () {
    return activeSockets.map(function (s) {
      return s.id
    }).join(', ')
  }

  var self = this
  var pendingDisconnect
  var disconnect = function (reason) {
    self.state = DISCONNECTED
    self.disconnectsCount++
    log.warn('Disconnected (%d times)' + (reason || ''), self.disconnectsCount)
    emitter.emit('browser_error', self, 'Disconnected' + (reason || ''))
    collection.remove(self)
  }

  var noActivityTimeoutId
  var refreshNoActivityTimeout = noActivityTimeout ? function () {
    clearNoActivityTimeout()
    noActivityTimeoutId = timer.setTimeout(function () {
      self.lastResult.totalTimeEnd()
      self.lastResult.disconnected = true
      disconnect(', because no message in ' + noActivityTimeout + ' ms.')
      emitter.emit('browser_complete', self)
    }, noActivityTimeout)
  } : function () {}

  var clearNoActivityTimeout = noActivityTimeout ? function () {
    if (noActivityTimeoutId) {
      timer.clearTimeout(noActivityTimeoutId)
      noActivityTimeoutId = null
    }
  } : function () {}

  this.id = id
  this.fullName = fullName
  this.name = name
  this.state = READY
  this.lastResult = new Result()
  this.disconnectsCount = 0

  this.init = function () {
    collection.add(this)

    events.bindAll(this, socket)

    log.info('Connected on socket %s with id %s', socket.id, id)

    // TODO(vojta): move to collection
    emitter.emit('browsers_change', collection)

    emitter.emit('browser_register', this)
  }

  this.isReady = function () {
    return this.state === READY
  }

  this.toString = function () {
    return this.name
  }

  this.onKarmaError = function (error) {
    if (this.isReady()) {
      return
    }

    this.lastResult.error = true
    emitter.emit('browser_error', this, error)

    refreshNoActivityTimeout()
  }

  this.onInfo = function (info) {
    if (this.isReady()) {
      return
    }

    // TODO(vojta): remove
    if (helper.isDefined(info.dump)) {
      emitter.emit('browser_log', this, info.dump, 'dump')
    }

    if (helper.isDefined(info.log)) {
      emitter.emit('browser_log', this, info.log, info.type)
    }

    if (
      !helper.isDefined(info.log) &&
      !helper.isDefined(info.dump)
    ) {
      emitter.emit('browser_info', this, info)
    }

    refreshNoActivityTimeout()
  }

  this.onStart = function (info) {
    this.lastResult = new Result()
    this.lastResult.total = info.total

    if (info.total === null) {
      log.warn('Adapter did not report total number of specs.')
    }

    emitter.emit('browser_start', this, info)
    refreshNoActivityTimeout()
  }

  this.onComplete = function (result) {
    if (this.isReady()) {
      return
    }

    this.state = READY
    this.lastResult.totalTimeEnd()

    if (!this.lastResult.success) {
      this.lastResult.error = true
    }

    emitter.emit('browsers_change', collection)
    emitter.emit('browser_complete', this, result)

    clearNoActivityTimeout()
  }

  this.onDisconnect = function (_, disconnectedSocket) {
    activeSockets.splice(activeSockets.indexOf(disconnectedSocket), 1)

    if (activeSockets.length) {
      log.debug('Disconnected %s, still have %s', disconnectedSocket.id, activeSocketsIds())
      return
    }

    if (this.state === READY) {
      disconnect()
    } else if (this.state === EXECUTING) {
      log.debug('Disconnected during run, waiting %sms for reconnecting.', disconnectDelay)
      this.state = EXECUTING_DISCONNECTED

      pendingDisconnect = timer.setTimeout(function () {
        self.lastResult.totalTimeEnd()
        self.lastResult.disconnected = true
        disconnect()
        emitter.emit('browser_complete', self)
      }, disconnectDelay)

      clearNoActivityTimeout()
    }
  }

  this.reconnect = function (newSocket) {
    if (this.state === EXECUTING_DISCONNECTED) {
      this.state = EXECUTING
      log.debug('Reconnected on %s.', newSocket.id)
    } else if (this.state === EXECUTING || this.state === READY) {
      log.debug('New connection %s (already have %s)', newSocket.id, activeSocketsIds())
    } else if (this.state === DISCONNECTED) {
      this.state = READY
      log.info('Connected on socket %s with id %s', newSocket.id, this.id)
      collection.add(this)

      // TODO(vojta): move to collection
      emitter.emit('browsers_change', collection)

      emitter.emit('browser_register', this)
    }

    var exists = activeSockets.some(function (s) {
      return s.id === newSocket.id
    })
    if (!exists) {
      activeSockets.push(newSocket)
      events.bindAll(this, newSocket)
    }

    if (pendingDisconnect) {
      timer.clearTimeout(pendingDisconnect)
    }

    refreshNoActivityTimeout()
  }

  this.onResult = function (result) {
    if (result.length) {
      return result.forEach(this.onResult, this)
    }

    // ignore - probably results from last run (after server disconnecting)
    if (this.isReady()) {
      return
    }

    this.lastResult.add(result)

    emitter.emit('spec_complete', this, result)
    refreshNoActivityTimeout()
  }

  this.serialize = function () {
    return {
      id: this.id,
      name: this.name,
      isReady: this.state === READY
    }
  }

  this.execute = function (config) {
    activeSockets.forEach(function (socket) {
      socket.emit('execute', config)
    })

    this.state = EXECUTING
    refreshNoActivityTimeout()
  }
}

Browser.STATE_READY = READY
Browser.STATE_EXECUTING = EXECUTING
Browser.STATE_READY_DISCONNECTED = READY_DISCONNECTED
Browser.STATE_EXECUTING_DISCONNECTED = EXECUTING_DISCONNECTED
Browser.STATE_DISCONNECTED = DISCONNECTED

module.exports = Browser
<|endoftext|>


<commit_before>//= require ./core
//= require ./utils
//= require ./state

(function () {

"use strict";

/**
 * @memberof Marbles
 * @class
 * @param {*} id Anything serializable as JSON
 * @desc This class is meant to be sub-classed using Store.createClass
 */
var Store = Marbles.Store = function (id) {
	this.id = id;
	this.constructor.__trackInstance(this);

	this.__changeListeners = [];

	this.willInitialize.apply(this, Array.prototype.slice.call(arguments, 1));

	this.state = this.getInitialState();

	this.didInitialize.apply(this, Array.prototype.slice.call(arguments, 1));
};

Store.displayName = "Marbles.Store";

Marbles.Utils.extend(Store.prototype, Marbles.State, {
	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @returns {Object} Initial state object
	 */
	getInitialState: function () {
		return {};
	},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called before state is initialized
	 */
	willInitialize: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called after state is initialized
	 */
	didInitialize: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called when first change listener is added
	 */
	didBecomeActive: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called when last change listener is removed
	 */
	didBecomeInactive: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @param {Object} event
	 * @desc Called with Dispatcher events
	 */
	handleEvent: function () {}
});

// Call didBecomeActive when first change listener added
Store.prototype.addChangeListener = function () {
	Marbles.State.addChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 1) {
		this.didBecomeActive();
	}
};

// Call didBecomeInactive when last change listener removed
Store.prototype.removeChangeListener = function () {
	Marbles.State.removeChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 0) {
		this.didBecomeInactive();
	}
};

Store.__instances = {};

Store.__getInstance = function (id) {
	var key = JSON.stringify(id);
	return this.__instances[key] || new this(id);
};

Store.__trackInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	this.__instances[key] = instance;
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Marbles.Store} store
 * @desc Give Store instance up for garbage collection
 */
Store.discardInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	delete this.__instances[key];
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Store#id} id
 */
Store.addChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.addChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Store#id} id
 */
Store.removeChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.removeChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

/**
 * @memberof Marbles.Store
 * @prop {Number}
 */
Store.dispatcherIndex = null;

/**
 * @memberof Marbles.Store
 * @func
 * @param {Marbles.Dispatcher} dispatcher
 */
Store.registerWithDispatcher = function (dispatcher) {
	this.dispatcherIndex = dispatcher.register(function (event) {
		if (event.storeId && (!this.isValidId || this.isValidId(event.storeId))) {
			var instance = this.__getInstance(event.storeId);
			return instance.handleEvent(event);
		} else {
			return Promise.all(Object.keys(this.__instances).sort().map(function (key) {
				var instance = this.__instances[key];
				return new Promise(function (resolve) {
					resolve(instance.handleEvent(event));
				});
			}.bind(this)));
		}
	}.bind(this));
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Object} proto Prototype of new child class
 * @desc Creates a new class that inherits from Store
 * @example
 *	var MyStore = Marbles.Store.createClass({
 *		displayName: "MyStore",
 *
 *		getInitialState: function () {
 *			return { my: "state" };
 *		},
 *
 *		willInitialize: function () {
 *			// do something
 *		},
 *
 *		didInitialize: function () {
 *			// do something
 *		},
 *
 *		didBecomeActive: function () {
 *			// do something
 *		},
 *
 *		didBecomeInactive: function () {
 *			// do something
 *		},
 *
 *		handleEvent: function (event) {
 *			// do something
 *		}
 *	});
 *
 */
Store.createClass = function (proto) {
	var parent = this;
	var store = Marbles.Utils.inheritPrototype(function () {
		parent.apply(this, arguments);
	}, parent);

	store.__instances = {};

	if (proto.hasOwnProperty("displayName")) {
		store.displayName = proto.displayName;
		delete proto.displayName;
	}

	Marbles.Utils.extend(store.prototype, proto);

	function wrappedFn(name, id) {
		var instance = this.__getInstance(id);
		return instance[name].apply(instance, Array.prototype.slice.call(arguments, 2));
	}

	for (var k in proto) {
		if (proto.hasOwnProperty(k) && k.slice(0, 1) !== "_" && typeof proto[k] === "function") {
			store[k] = wrappedFn.bind(store, k);
		}
	}

	return store;
};

})();
<commit_msg>Fix Store: return value from dispatcher handler is always a Promise<commit_after>//= require ./core
//= require ./utils
//= require ./state

(function () {

"use strict";

/**
 * @memberof Marbles
 * @class
 * @param {*} id Anything serializable as JSON
 * @desc This class is meant to be sub-classed using Store.createClass
 */
var Store = Marbles.Store = function (id) {
	this.id = id;
	this.constructor.__trackInstance(this);

	this.__changeListeners = [];

	this.willInitialize.apply(this, Array.prototype.slice.call(arguments, 1));

	this.state = this.getInitialState();

	this.didInitialize.apply(this, Array.prototype.slice.call(arguments, 1));
};

Store.displayName = "Marbles.Store";

Marbles.Utils.extend(Store.prototype, Marbles.State, {
	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @returns {Object} Initial state object
	 */
	getInitialState: function () {
		return {};
	},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called before state is initialized
	 */
	willInitialize: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called after state is initialized
	 */
	didInitialize: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called when first change listener is added
	 */
	didBecomeActive: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @desc Called when last change listener is removed
	 */
	didBecomeInactive: function () {},

	/**
	 * @memberof Marbles.Store
	 * @instance
	 * @method
	 * @param {Object} event
	 * @desc Called with Dispatcher events
	 */
	handleEvent: function () {}
});

// Call didBecomeActive when first change listener added
Store.prototype.addChangeListener = function () {
	Marbles.State.addChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 1) {
		this.didBecomeActive();
	}
};

// Call didBecomeInactive when last change listener removed
Store.prototype.removeChangeListener = function () {
	Marbles.State.removeChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 0) {
		this.didBecomeInactive();
	}
};

Store.__instances = {};

Store.__getInstance = function (id) {
	var key = JSON.stringify(id);
	return this.__instances[key] || new this(id);
};

Store.__trackInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	this.__instances[key] = instance;
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Marbles.Store} store
 * @desc Give Store instance up for garbage collection
 */
Store.discardInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	delete this.__instances[key];
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Store#id} id
 */
Store.addChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.addChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Store#id} id
 */
Store.removeChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.removeChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

/**
 * @memberof Marbles.Store
 * @prop {Number}
 */
Store.dispatcherIndex = null;

/**
 * @memberof Marbles.Store
 * @func
 * @param {Marbles.Dispatcher} dispatcher
 */
Store.registerWithDispatcher = function (dispatcher) {
	this.dispatcherIndex = dispatcher.register(function (event) {
		if (event.storeId && (!this.isValidId || this.isValidId(event.storeId))) {
			var instance = this.__getInstance(event.storeId);
			return Promise.resolve(instance.handleEvent(event));
		} else {
			return Promise.all(Object.keys(this.__instances).sort().map(function (key) {
				var instance = this.__instances[key];
				return new Promise(function (resolve) {
					resolve(instance.handleEvent(event));
				});
			}.bind(this)));
		}
	}.bind(this));
};

/**
 * @memberof Marbles.Store
 * @func
 * @param {Object} proto Prototype of new child class
 * @desc Creates a new class that inherits from Store
 * @example
 *	var MyStore = Marbles.Store.createClass({
 *		displayName: "MyStore",
 *
 *		getInitialState: function () {
 *			return { my: "state" };
 *		},
 *
 *		willInitialize: function () {
 *			// do something
 *		},
 *
 *		didInitialize: function () {
 *			// do something
 *		},
 *
 *		didBecomeActive: function () {
 *			// do something
 *		},
 *
 *		didBecomeInactive: function () {
 *			// do something
 *		},
 *
 *		handleEvent: function (event) {
 *			// do something
 *		}
 *	});
 *
 */
Store.createClass = function (proto) {
	var parent = this;
	var store = Marbles.Utils.inheritPrototype(function () {
		parent.apply(this, arguments);
	}, parent);

	store.__instances = {};

	if (proto.hasOwnProperty("displayName")) {
		store.displayName = proto.displayName;
		delete proto.displayName;
	}

	Marbles.Utils.extend(store.prototype, proto);

	function wrappedFn(name, id) {
		var instance = this.__getInstance(id);
		return instance[name].apply(instance, Array.prototype.slice.call(arguments, 2));
	}

	for (var k in proto) {
		if (proto.hasOwnProperty(k) && k.slice(0, 1) !== "_" && typeof proto[k] === "function") {
			store[k] = wrappedFn.bind(store, k);
		}
	}

	return store;
};

})();
<|endoftext|>


<commit_before>//= require ./core
//= require ./utils
//= require ./state

(function () {

"use strict";

var Store = Marbles.Store = function (id) {
	this.id = id;
	this.constructor.__trackInstance(this);

	this.__changeListeners = [];

	this.willInitialize.apply(this, Array.prototype.slice.call(arguments, 1));

	this.state = this.getInitialState();

	this.didInitialize.apply(this, Array.prototype.slice.call(arguments, 1));
};

Store.displayName = "Marbles.Store";

Marbles.Utils.extend(Store.prototype, Marbles.State, {
	getInitialState: function () {
		return {};
	},

	willInitialize: function () {},

	didInitialize: function () {},

	didBecomeActive: function () {},

	didBecomeInactive: function () {}
});

// Call didBecomeActive when first change listener added
Store.prototype.addChangeListener = function () {
	Marbles.State.addChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 1) {
		this.didBecomeActive();
	}
};

// Call didBecomeInactive when last change listener removed
Store.prototype.removeChangeListener = function () {
	Marbles.State.removeChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 0) {
		this.didBecomeInactive();
	}
};

Store.__instances = {};

Store.__getInstance = function (id) {
	var key = JSON.stringify(id);
	return this.__instances[key] || new this(id);
};

Store.__trackInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	this.__instances[key] = instance;
};

Store.discardInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	delete this.__instances[key];
};

Store.addChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.addChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

Store.removeChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.removeChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

Store.dispatcherIndex = null;
Store.registerWithDispatcher = function (dispatcher) {
	this.dispatcherIndex = dispatcher.register(function (event) {
		var instance = this.__getInstance(event.storeId);
		return instance.handleEvent(event);
	}.bind(this));
};

Store.createClass = function (proto) {
	var parent = this;
	var store = Marbles.Utils.inheritPrototype(function () {
		parent.apply(this, arguments);
	}, parent);

	store.__instances = {};

	if (proto.hasOwnProperty("displayName")) {
		store.displayName = proto.displayName;
		delete proto.displayName;
	}

	Marbles.Utils.extend(store.prototype, proto);

	function wrappedFn(name, id) {
		var instance = this.__getInstance(id);
		return instance[name].apply(instance, Array.prototype.slice.call(arguments, 2));
	}

	for (var k in proto) {
		if (proto.hasOwnProperty(k) && k.slice(0, 1) !== "_" && typeof proto[k] === "function") {
			store[k] = wrappedFn.bind(store, k);
		}
	}

	return store;
};

})();
<commit_msg>Update Store: Add default handleEvent fn<commit_after>//= require ./core
//= require ./utils
//= require ./state

(function () {

"use strict";

var Store = Marbles.Store = function (id) {
	this.id = id;
	this.constructor.__trackInstance(this);

	this.__changeListeners = [];

	this.willInitialize.apply(this, Array.prototype.slice.call(arguments, 1));

	this.state = this.getInitialState();

	this.didInitialize.apply(this, Array.prototype.slice.call(arguments, 1));
};

Store.displayName = "Marbles.Store";

Marbles.Utils.extend(Store.prototype, Marbles.State, {
	getInitialState: function () {
		return {};
	},

	willInitialize: function () {},

	didInitialize: function () {},

	didBecomeActive: function () {},

	didBecomeInactive: function () {},

	handleEvent: function () {}
});

// Call didBecomeActive when first change listener added
Store.prototype.addChangeListener = function () {
	Marbles.State.addChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 1) {
		this.didBecomeActive();
	}
};

// Call didBecomeInactive when last change listener removed
Store.prototype.removeChangeListener = function () {
	Marbles.State.removeChangeListener.apply(this, arguments);
	if (this.__changeListeners.length === 0) {
		this.didBecomeInactive();
	}
};

Store.__instances = {};

Store.__getInstance = function (id) {
	var key = JSON.stringify(id);
	return this.__instances[key] || new this(id);
};

Store.__trackInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	this.__instances[key] = instance;
};

Store.discardInstance = function (instance) {
	var key = JSON.stringify(instance.id);
	delete this.__instances[key];
};

Store.addChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.addChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

Store.removeChangeListener = function (id) {
	var instance = this.__getInstance(id);
	return instance.removeChangeListener.apply(instance, Array.prototype.slice.call(arguments, 1));
};

Store.dispatcherIndex = null;
Store.registerWithDispatcher = function (dispatcher) {
	this.dispatcherIndex = dispatcher.register(function (event) {
		var instance = this.__getInstance(event.storeId);
		return instance.handleEvent(event);
	}.bind(this));
};

Store.createClass = function (proto) {
	var parent = this;
	var store = Marbles.Utils.inheritPrototype(function () {
		parent.apply(this, arguments);
	}, parent);

	store.__instances = {};

	if (proto.hasOwnProperty("displayName")) {
		store.displayName = proto.displayName;
		delete proto.displayName;
	}

	Marbles.Utils.extend(store.prototype, proto);

	function wrappedFn(name, id) {
		var instance = this.__getInstance(id);
		return instance[name].apply(instance, Array.prototype.slice.call(arguments, 2));
	}

	for (var k in proto) {
		if (proto.hasOwnProperty(k) && k.slice(0, 1) !== "_" && typeof proto[k] === "function") {
			store[k] = wrappedFn.bind(store, k);
		}
	}

	return store;
};

})();
<|endoftext|>


<commit_before>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var _ = require('lodash');
var uuid = require('uuid');

/**
 * container builder
 */
module.exports = function(config, _containers) {

  var logger = config.logger;

  var updateTopolgy = function(json, containerDef, container) {
    var prnt = json.topology.containers[container.containedBy];
    var newId = uuid.v4();
    var oldId = container.id;
    var idx;

    if (-1 !== (idx = prnt.contains.indexOf(oldId))) {
      prnt.contains[idx] = newId;
    }
    json.topology.containers[oldId].id = newId;

    json.topology.containers[newId] = json.topology.containers[oldId];
    delete json.topology.containers[oldId];
  };

  /**
   * Build the container and update all instantiations of the container
   * with the new speicific block and replace identifiers for new uuids
   */
  var build = function build(mode, system, cdef, out, cb) {
    var err = 'no matching container available for type: ' + cdef.type;
    var container = _containers[cdef.type];

    out.progress('executing container specific build');
    logger.info('executing container specific build');
    if (!container) { logger.error(err); return cb(err); }
    container.build(mode, system, cdef, out, function(err, specific) {
      if (err) { logger.error(err); out.stdout(err); return cb(err); }
      out.progress('updating topology');

      logger.info('updating topology');
      var matches = _.filter(system.topology.containers, function(c) {
        return c.containerDefinitionId === cdef.id;
      });
      _.each(matches, function(ctnr) {
        ctnr.specific = specific;
        updateTopolgy(system, cdef, ctnr);
      });

      if (cdef.specific.buildHead) {
        cdef.specific.buildHead = cdef.specific.buildHead + 1;
      }
      cb(err, specific);
    });
  };

  return {
    build: build,
  };
};

<commit_msg>Fix a typo in function name<commit_after>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var _ = require('lodash');
var uuid = require('uuid');

/**
 * container builder
 */
module.exports = function(config, _containers) {

  var logger = config.logger;

  var updateTopology = function(json, containerDef, container) {
    var prnt = json.topology.containers[container.containedBy];
    var newId = uuid.v4();
    var oldId = container.id;
    var idx;

    if (-1 !== (idx = prnt.contains.indexOf(oldId))) {
      prnt.contains[idx] = newId;
    }
    json.topology.containers[oldId].id = newId;

    json.topology.containers[newId] = json.topology.containers[oldId];
    delete json.topology.containers[oldId];
  };

  /**
   * Build the container and update all instantiations of the container
   * with the new speicific block and replace identifiers for new uuids
   */
  var build = function build(mode, system, cdef, out, cb) {
    var err = 'no matching container available for type: ' + cdef.type;
    var container = _containers[cdef.type];

    out.progress('executing container specific build');
    logger.info('executing container specific build');
    if (!container) { logger.error(err); return cb(err); }
    container.build(mode, system, cdef, out, function(err, specific) {
      if (err) { logger.error(err); out.stdout(err); return cb(err); }
      out.progress('updating topology');

      logger.info('updating topology');
      var matches = _.filter(system.topology.containers, function(c) {
        return c.containerDefinitionId === cdef.id;
      });
      _.each(matches, function(ctnr) {
        ctnr.specific = specific;
        updateTopology(system, cdef, ctnr);
      });

      if (cdef.specific.buildHead) {
        cdef.specific.buildHead = cdef.specific.buildHead + 1;
      }
      cb(err, specific);
    });
  };

  return {
    build: build,
  };
};

<|endoftext|>


<commit_before>
var spawn = require('child_process').spawn
  , path = require('path')
  , fs = require('fs')

  , mkdirp = require('mkdirp')

module.exports = cachier

function cachier(base) {
  function child(sub) {
    return cachier(path.join(base, sub))
  }
  child.get = function (key, dest, done) {
    if (arguments.length === 2) {
      done = dest
      dest = key
      key = ''
    }
    copy(path.join(base, key), dest, done)
  }
  child.update = function (key, dest, done) {
    if (arguments.length === 2) {
      done = dest
      dest = key
      key = ''
    }
    copy(dest, path.join(base, key), done)
  }
  child.base = base
  return child
}

function copy(from, to, done) {
  fs.exists(from, function (exists) {
    if (!exists) return done(new Error('Source does not exist: ' + from))
    spawn('rm', ['-rf', to]).on('close', function () {
      mkdirp(path.dirname(to), function () {
        var out = ''
          , child = spawn('cp', ['-R', from, to])
        child.stdout.on('data', function (data) {
          out += data.toString()
        })
        child.stderr.on('data', function (data) {
          out += data.toString()
        })
        child.on('close', function (exitCode) {
          return done(exitCode && new Error('Failed to retrieve cached code:' + out + ' ' + exitCode))
        })
      })
    })
  })
}

<commit_msg>safespawn with the cachier<commit_after>
var spawn = require('child_process').spawn
  , path = require('path')
  , fs = require('fs')

  , mkdirp = require('mkdirp')

module.exports = cachier

function safespawn() {
  var c = spawn.apply(null, arguments)
  c.on('error', function (err) {
    // suppress node errors
  })
  return c
}

function cachier(base) {
  function child(sub) {
    return cachier(path.join(base, sub))
  }
  child.get = function (key, dest, done) {
    if (arguments.length === 2) {
      done = dest
      dest = key
      key = ''
    }
    copy(path.join(base, key), dest, done)
  }
  child.update = function (key, dest, done) {
    if (arguments.length === 2) {
      done = dest
      dest = key
      key = ''
    }
    copy(dest, path.join(base, key), done)
  }
  child.base = base
  return child
}

function copy(from, to, done) {
  fs.exists(from, function (exists) {
    if (!exists) return done(new Error('Source does not exist: ' + from))
    safespawn('rm', ['-rf', to]).on('close', function () {
      mkdirp(path.dirname(to), function () {
        var out = ''
          , child = safespawn('cp', ['-R', from, to])
        child.stdout.on('data', function (data) {
          out += data.toString()
        })
        child.stderr.on('data', function (data) {
          out += data.toString()
        })
        child.on('close', function (exitCode) {
          return done(exitCode && new Error('Failed to retrieve cached code:' + out + ' ' + exitCode))
        })
      })
    })
  })
}

<|endoftext|>


<commit_before>/**
 * Push notification handler.
 *
 * Requires that the Cordova push plugin has been installed:
 *   cordova plugin add https://github.com/phonegap-build/PushPlugin.git
 */

var appSettings = require('../../build/app_settings');
var pushConstants = require('./push/constants');

var PushNotificationService = function (
  $rootScope, $state, $cordovaPush, acmGCMPushNotification, acmAPNSPushNotification) {

  var service = {

    getPlatformPushService_: function (devicePlatform) {
      if (devicePlatform === 'ANDROID') {
        return acmGCMPushNotification;
      } else if (devicePlatform === 'IOS') {
        return acmAPNSPushNotification;
      }
    },

    /**
     * Register the device with the notification backend.
     */
    register: function () {
      var platform = ionic.Platform.platform().toUpperCase();
      var devicePushHandler = this.getPlatformPushService_(platform);
      if (!angular.isUndefined(devicePushHandler)) {
        var pushConfig = {};

        if (platform === 'IOS') {
          angular.extend(pushConfig, {
            'badge': 'true',
            'sound': 'true',
            'alert': 'true'
          });
        } else if (platform === 'ANDROID') {
          // Android uses the local notification interface to pop up notifications, so register the click
          // handler here.
          window.plugin.notification.local.onclick = function (id, state, json) {
            if (id === pushConstants.PUSH_RECEIVED_FOREGROUND_NOTIFICATION_ID) {
              $state.go('acm.homeTabs.home', {}, {reload: true});
            }
          };
        }

        pushConfig.vibrate = true;
        pushConfig.forceShow = true;

        var pushObject = $cordovaPush.init({ android: pushConfig });
        pushObject.on('registration', function(registrationid, registrationType) {
          devicePushHandler.registrationSuccess(registrationid);
        });

        pushObject.on('error', function(error) {
          devicePushHandler.registrationError(error);
        });

        pushObject.on('notification', function(notification) {
          service.handlePushNotification(notification);
        });

        pushObject.subscribe(null, function() {});

        var ionicPush = new Push();
        ionicPush.createChannel({
          id: null,
          description: "EFF Alerts",
          importance: 3
        }).then(function() {
          console.log("Notification channel created.");
        }, function(e) {
          console.error("Error creating notification channel: " + JSON.stringify(e));
        });
      }
    },

    /**
     * Top level handler for push notifications on all platforms.
     *
     * @param {*} event The push notification event.
     */
    handlePushNotification: function (event) {
      var devicePlatform = ionic.Platform.platform().toUpperCase();
      this.getPlatformPushService_(devicePlatform).handleNotification(event);
    }

  };

  /**
   * Listen to push notification events from the event bus.
   */
  $rootScope.$on('pushNotificationReceived', function (event, pushEvent) {
    service.handlePushNotification(pushEvent);
  });

  return service;
};

module.exports = PushNotificationService;
<commit_msg>Fix push.js<commit_after>/**
 * Push notification handler.
 *
 * Requires that the Cordova push plugin has been installed:
 *   cordova plugin add https://github.com/phonegap-build/PushPlugin.git
 */

var appSettings = require('../../build/app_settings');
var pushConstants = require('./push/constants');

import { Push } from '@ionic-native/push';

var PushNotificationService = function (
  $rootScope, $state, $cordovaPush, acmGCMPushNotification, acmAPNSPushNotification) {

  var service = {

    getPlatformPushService_: function (devicePlatform) {
      if (devicePlatform === 'ANDROID') {
        return acmGCMPushNotification;
      } else if (devicePlatform === 'IOS') {
        return acmAPNSPushNotification;
      }
    },

    /**
     * Register the device with the notification backend.
     */
    register: function () {
      var platform = ionic.Platform.platform().toUpperCase();
      var devicePushHandler = this.getPlatformPushService_(platform);
      if (!angular.isUndefined(devicePushHandler)) {
        var pushConfig = {};

        if (platform === 'IOS') {
          angular.extend(pushConfig, {
            'badge': 'true',
            'sound': 'true',
            'alert': 'true'
          });
        } else if (platform === 'ANDROID') {
          // Android uses the local notification interface to pop up notifications, so register the click
          // handler here.
          window.plugin.notification.local.onclick = function (id, state, json) {
            if (id === pushConstants.PUSH_RECEIVED_FOREGROUND_NOTIFICATION_ID) {
              $state.go('acm.homeTabs.home', {}, {reload: true});
            }
          };
        }

        pushConfig.vibrate = true;
        pushConfig.forceShow = true;

        var pushObject = $cordovaPush.init({ android: pushConfig });
        pushObject.on('registration', function(registrationid, registrationType) {
          devicePushHandler.registrationSuccess(registrationid);
        });

        pushObject.on('error', function(error) {
          devicePushHandler.registrationError(error);
        });

        pushObject.on('notification', function(notification) {
          service.handlePushNotification(notification);
        });

        pushObject.subscribe(null, function() {});

        var ionicPush = new Push();
        ionicPush.createChannel({
          id: null,
          description: "EFF Alerts",
          importance: 3
        }).then(function() {
          console.log("Notification channel created.");
        }, function(e) {
          console.error("Error creating notification channel: " + JSON.stringify(e));
        });
      }
    },

    /**
     * Top level handler for push notifications on all platforms.
     *
     * @param {*} event The push notification event.
     */
    handlePushNotification: function (event) {
      var devicePlatform = ionic.Platform.platform().toUpperCase();
      this.getPlatformPushService_(devicePlatform).handleNotification(event);
    }

  };

  /**
   * Listen to push notification events from the event bus.
   */
  $rootScope.$on('pushNotificationReceived', function (event, pushEvent) {
    service.handlePushNotification(pushEvent);
  });

  return service;
};

module.exports = PushNotificationService;
<|endoftext|>


<commit_before>/*jslint indent:2, maxlen:80, node:true, nomen:true*/
'use strict';

// Node.JS standard modules

var events, path;
events = require('events');
path = require('path');

// 3rd-party modules

var Q, AWS, async;
Q = require('q');
AWS = require('aws-sdk');
async = require('async');

// custom modules

var File, FileList;
File = require(path.join(__dirname, '..', 'file'));
FileList = require(path.join(__dirname, '..', 'filelist'));

// promise-bound anti-callbacks

// this module

/**
 * @param {Object} options
 * @returns {CDN}
 * @constructor
 */
var CDN = function (options) {
  this.cfg = options || {};
  this.api = new AWS.S3(options);
  return this;
};

CDN.prototype = Object.create(events.EventEmitter.prototype);

CDN.prototype.executeBulkDelete = function (actions) {
  var self, dfrd, options, currentBatch, nextBatch, objects;
  self = this;
  dfrd = Q.defer();

  if (!Array.isArray(actions) || !actions.length) {
    dfrd.resolve();
    return dfrd.promise;
  }

  currentBatch = actions.slice(0, 1000);
  nextBatch = actions.slice(1000);

  objects = currentBatch.map(function (action) {
    return { Key: action.path };
  });

  options = {
    Bucket: this.cfg.Bucket,
    Delete: { Objects: objects }
  };

  this.api.deleteObjects(options, function (err, res) {
    // TODO: check response and errors and react intelligently
    if (err) {
      dfrd.reject(err);
    } else if (Array.isArray(res.Errors) && res.Errors.length) {
      dfrd.reject(new Error('DELETE: ' + res.Errors[0].Code));
    } else {
      currentBatch.forEach(function (action) {
        self.emit('progress', action);
      });
      self.executeBulkDelete(nextBatch).done(function () {
        dfrd.resolve();
      });
    }
  });

  return dfrd.promise;
};

CDN.prototype.executeUpload = function (action) {
  var dfrd, options, self;
  self = this;
  dfrd = Q.defer();
  options = {
    Bucket: this.cfg.Bucket,
    ContentType: action.file.headers['Content-Type'],
    Key: action.file.path
  };

  if (action.file.headers['Content-Encoding']) {
    options.ContentEncoding = action.file.headers['Content-Encoding'];
  }

  action.file.getBuffer().then(function (buffer) {
    options.Body = buffer;
    self.api.putObject(options, function (err) { // (err, res)
      if (err) {
        dfrd.reject(err);
      } else {
        self.emit('progress', action);
        dfrd.resolve();
      }
    });
  });

  return dfrd.promise;
};

CDN.prototype.executeAction = function (action) {
  var dfrd, self;
  self = this;
  dfrd = Q.defer();

  self.emit('progress', action);

  dfrd.resolve();

  return dfrd.promise;
};

CDN.prototype.executeActions = function (actions, options) {
  var self, dfrd, deleteActions, otherActions;
  self = this;
  dfrd = Q.defer();

  options = options || {};

  if (options['dry-run']) {
    actions.forEach(function (action) {
      self.emit('progress', action);
    });
    dfrd.resolve();
    return dfrd.promise;
  }

  this.totalActions = actions.length;
  if (!Array.isArray(actions) || !actions.length) {
    dfrd.resolve();
    return dfrd.promise;
  }

  deleteActions = actions.filter(function (action) {
    return action.doDelete && action.path;
  });

  otherActions = actions.filter(function (action) {
    return !action.doDelete && action.path;
  });

  if (deleteActions.length) {
    this.executeBulkDelete(deleteActions).then(function () {
      return self.executeActions(otherActions);
    }).done(function () {
      dfrd.resolve();
    });
    return dfrd.promise;
  }
  // only doHeader and doUpload actions left now

  async.eachLimit(actions, 10, function (action, done) { // perItem
    self.executeUpload(action).done(done, done);
  }, function (err) { // onComplete
    if (err) {
      dfrd.reject(err);
    } else {
      dfrd.resolve();
    }
  });

  return dfrd.promise;
};

/**
 * @param {File} file
 */
CDN.prototype.fixFile = function (file) {
  var self, dfrd, options;
  self = this;
  dfrd = Q.defer();

  if (file.mime && typeof file.mime === 'string') {
    self.emit('file:fixed');
    dfrd.resolve();
    return dfrd.promise;
  }

  options = {
    Bucket: this.cfg.Bucket,
    Key: file.path
  };
  this.api.headObject(options, function (err, res) {
    if (err) {
      console.error(err);
      dfrd.reject(err);
      return;
    }
    file.setMIME(res.ContentType);
    if (res.ContentEncoding) {
      file.headers['Content-Encoding'] = res.ContentEncoding;
    }
    self.emit('file:fixed');
    dfrd.resolve();
  });

  // TODO: check cache headers and permissions
  return dfrd.promise;
};

CDN.prototype.fixFiles = function (files) {
  var self, dfrd;
  self = this;
  dfrd = Q.defer();

  async.eachLimit(files, 15, function (file, done) { // perItem
    self.fixFile(file).done(done, done);
  }, function (err) { // onComplete
    if (err) {
      console.error('fixFiles', err);
      dfrd.reject(err);
    } else {
      dfrd.resolve(files);
    }
  });

  return dfrd.promise;
};

/**
 * grabs the initial list of Files, but they will be missing metadata
 * @param {Object} [options]
 * @returns {Promise}
 */
CDN.prototype.listAllFiles = function (files, options) {
  var self, dfrd;
  self = this;
  dfrd = Q.defer();
  options = options || {
    Bucket: this.cfg.Bucket
  };

  this.api.listObjects(options, function (err, res) {
    if (err) {
      dfrd.reject(err);
      return;
    }
    if (!Array.isArray(res.Contents)) {
      dfrd.resolve(files);
      return;
    }
    res.Contents.forEach(function (obj) {
      var file;
      if (obj.Key[obj.Key.length - 1] !== '/') {
        file = new File({
          path: obj.Key,
          md5: obj.ETag.replace(/"/g, ''), // AWS wraps in quotes, urgh
          size: obj.Size
        });
        files.push(file);
      }
    });
    if (res.IsTruncated) {
      options.Marker = files[files.length - 1].path;
      self.listAllFiles(files, options).done(function () {
        dfrd.resolve(files);
      });
    } else {
      dfrd.resolve(files);
    }
  });
  return dfrd.promise;
};

CDN.prototype.listFiles = function () {
  var self, dfrd, files;
  self = this;
  dfrd = Q.defer();

  files = new FileList();

  this.listAllFiles(files)
    .then(function (files) {
      self.emit('files.length', files.length);
      return self.fixFiles(files);
    })
    .then(function (files) {
      files.sort(function (a, b) {
        if (a.path < b.path) {
          return -1;
        }
        if (a.path > b.path) {
          return 1;
        }
        return 0;
      });
      dfrd.resolve(files);
    })
    .done();

  return dfrd.promise;
};

// exports

CDN.prototype.test = function () {
  var bucket, dfrd;
  dfrd = Q.defer();
  bucket = this.cfg.Bucket;
  this.api.headBucket({ Bucket: bucket }, function (err) { // (err, res)
    if (err) {
      dfrd.reject(new Error('access denied or missing AWS bucket: ' + bucket));
      return;
    }
    dfrd.resolve();
  });
  return dfrd.promise;
};

module.exports = CDN;
<commit_msg>add a try/catch to try to diagnose weird terminations<commit_after>/*jslint indent:2, maxlen:80, node:true, nomen:true*/
'use strict';

// Node.JS standard modules

var events, path;
events = require('events');
path = require('path');

// 3rd-party modules

var Q, AWS, async;
Q = require('q');
AWS = require('aws-sdk');
async = require('async');

// custom modules

var File, FileList;
File = require(path.join(__dirname, '..', 'file'));
FileList = require(path.join(__dirname, '..', 'filelist'));

// promise-bound anti-callbacks

// this module

/**
 * @param {Object} options
 * @returns {CDN}
 * @constructor
 */
var CDN = function (options) {
  this.cfg = options || {};
  this.api = new AWS.S3(options);
  return this;
};

CDN.prototype = Object.create(events.EventEmitter.prototype);

CDN.prototype.executeBulkDelete = function (actions) {
  var self, dfrd, options, currentBatch, nextBatch, objects;
  self = this;
  dfrd = Q.defer();

  if (!Array.isArray(actions) || !actions.length) {
    dfrd.resolve();
    return dfrd.promise;
  }

  currentBatch = actions.slice(0, 1000);
  nextBatch = actions.slice(1000);

  objects = currentBatch.map(function (action) {
    return { Key: action.path };
  });

  options = {
    Bucket: this.cfg.Bucket,
    Delete: { Objects: objects }
  };

  this.api.deleteObjects(options, function (err, res) {
    // TODO: check response and errors and react intelligently
    if (err) {
      dfrd.reject(err);
    } else if (Array.isArray(res.Errors) && res.Errors.length) {
      dfrd.reject(new Error('DELETE: ' + res.Errors[0].Code));
    } else {
      currentBatch.forEach(function (action) {
        self.emit('progress', action);
      });
      self.executeBulkDelete(nextBatch).done(function () {
        dfrd.resolve();
      });
    }
  });

  return dfrd.promise;
};

CDN.prototype.executeUpload = function (action) {
  var dfrd, options, self;
  self = this;
  dfrd = Q.defer();
  options = {
    Bucket: this.cfg.Bucket,
    ContentType: action.file.headers['Content-Type'],
    Key: action.file.path
  };

  if (action.file.headers['Content-Encoding']) {
    options.ContentEncoding = action.file.headers['Content-Encoding'];
  }

  action.file.getBuffer().then(function (buffer) {
    options.Body = buffer;
    self.api.putObject(options, function (err) { // (err, res)
      if (err) {
        dfrd.reject(err);
      } else {
        self.emit('progress', action);
        dfrd.resolve();
      }
    });
  });

  return dfrd.promise;
};

CDN.prototype.executeAction = function (action) {
  var dfrd, self;
  self = this;
  dfrd = Q.defer();

  self.emit('progress', action);

  dfrd.resolve();

  return dfrd.promise;
};

CDN.prototype.executeActions = function (actions, options) {
  var self, dfrd, deleteActions, otherActions;
  self = this;
  dfrd = Q.defer();

  options = options || {};

  if (options['dry-run']) {
    actions.forEach(function (action) {
      self.emit('progress', action);
    });
    dfrd.resolve();
    return dfrd.promise;
  }

  this.totalActions = actions.length;
  if (!Array.isArray(actions) || !actions.length) {
    dfrd.resolve();
    return dfrd.promise;
  }

  deleteActions = actions.filter(function (action) {
    return action.doDelete && action.path;
  });

  otherActions = actions.filter(function (action) {
    return !action.doDelete && action.path;
  });

  if (deleteActions.length) {
    this.executeBulkDelete(deleteActions).then(function () {
      return self.executeActions(otherActions);
    }).done(function () {
      dfrd.resolve();
    });
    return dfrd.promise;
  }
  // only doHeader and doUpload actions left now

  async.eachLimit(actions, 10, function (action, done) { // perItem
    self.executeUpload(action).done(done, done);
  }, function (err) { // onComplete
    if (err) {
      dfrd.reject(err);
    } else {
      dfrd.resolve();
    }
  });

  return dfrd.promise;
};

/**
 * @param {File} file
 */
CDN.prototype.fixFile = function (file) {
  var self, dfrd, options;
  self = this;
  dfrd = Q.defer();

  if (file.mime && typeof file.mime === 'string') {
    self.emit('file:fixed');
    dfrd.resolve();
    return dfrd.promise;
  }

  options = {
    Bucket: this.cfg.Bucket,
    Key: file.path
  };
  this.api.headObject(options, function (err, res) {
    try {
      if (err) {
        console.error(err);
        dfrd.reject(err);
        return;
      }
      file.setMIME(res.ContentType);
      if (res.ContentEncoding) {
        file.headers['Content-Encoding'] = res.ContentEncoding;
      }
      self.emit('file:fixed');
      dfrd.resolve();
    } catch (err) {
      console.error(err);
      dfrd.reject(err);
    }
  });

  // TODO: check cache headers and permissions
  return dfrd.promise;
};

CDN.prototype.fixFiles = function (files) {
  var self, dfrd;
  self = this;
  dfrd = Q.defer();

  async.eachLimit(files, 15, function (file, done) { // perItem
    self.fixFile(file).done(done, done);
  }, function (err) { // onComplete
    if (err) {
      console.error('fixFiles', err);
      dfrd.reject(err);
    } else {
      dfrd.resolve(files);
    }
  });

  return dfrd.promise;
};

/**
 * grabs the initial list of Files, but they will be missing metadata
 * @param {Object} [options]
 * @returns {Promise}
 */
CDN.prototype.listAllFiles = function (files, options) {
  var self, dfrd;
  self = this;
  dfrd = Q.defer();
  options = options || {
    Bucket: this.cfg.Bucket
  };

  this.api.listObjects(options, function (err, res) {
    if (err) {
      dfrd.reject(err);
      return;
    }
    if (!Array.isArray(res.Contents)) {
      dfrd.resolve(files);
      return;
    }
    res.Contents.forEach(function (obj) {
      var file;
      if (obj.Key[obj.Key.length - 1] !== '/') {
        file = new File({
          path: obj.Key,
          md5: obj.ETag.replace(/"/g, ''), // AWS wraps in quotes, urgh
          size: obj.Size
        });
        files.push(file);
      }
    });
    if (res.IsTruncated) {
      options.Marker = files[files.length - 1].path;
      self.listAllFiles(files, options).done(function () {
        dfrd.resolve(files);
      });
    } else {
      dfrd.resolve(files);
    }
  });
  return dfrd.promise;
};

CDN.prototype.listFiles = function () {
  var self, dfrd, files;
  self = this;
  dfrd = Q.defer();

  files = new FileList();

  this.listAllFiles(files)
    .then(function (files) {
      self.emit('files.length', files.length);
      return self.fixFiles(files);
    })
    .then(function (files) {
      files.sort(function (a, b) {
        if (a.path < b.path) {
          return -1;
        }
        if (a.path > b.path) {
          return 1;
        }
        return 0;
      });
      dfrd.resolve(files);
    })
    .done();

  return dfrd.promise;
};

// exports

CDN.prototype.test = function () {
  var bucket, dfrd;
  dfrd = Q.defer();
  bucket = this.cfg.Bucket;
  this.api.headBucket({ Bucket: bucket }, function (err) { // (err, res)
    if (err) {
      dfrd.reject(new Error('access denied or missing AWS bucket: ' + bucket));
      return;
    }
    dfrd.resolve();
  });
  return dfrd.promise;
};

module.exports = CDN;
<|endoftext|>