<commit_before>var _ = require('lodash')
var EventEmitter = require('events').EventEmitter
var util = require('util')
var debug = require('debug')('stellar-client')
var ReconWs = require('recon-ws')
var assert = require('assert')
var num = require('num')

function StellarClient(opts) {
    this.opts = _.extend({
        uri: 'wss://live.stellar.org:9001/',
        allTransactions: false
    }, opts)

    this.connected = false

    this.conn = new ReconWs(this.opts.uri)
    this.conn.on('open', this.connOpen.bind(this))
    this.conn.on('close', this.connClose.bind(this))
    this.conn.on('message', this.connMessage.bind(this))
}

util.inherits(StellarClient, EventEmitter)

StellarClient.prototype.connOpen = function() {
    debug('connected')
    this.commandIndex = 0
    this.requests = {}
    this.connected = true
    this.emit('open')
}

StellarClient.prototype.connClose = function() {
    debug('disconnected')
    this.connected = false

    // Resolve pending requests as error from disconnect
    _.each(this.requests, function(cb) {
        cb(new Error('Disconnected during request'))
    })

    this.emit('close')
}

StellarClient.prototype.connMessage = function(msg) {
    var data = JSON.parse(msg)
    debug('<-- %s', util.inspect(data))

    // Is this a response to a request?
    var id = data.id
    if (id !== undefined) {
        var request = this.requests[id]
        if (request) {
            delete this.requests[id]
            assert.equal(data.type, 'response')

            if (data.status == 'success') {
                return request(null, data.result)
            }

            if (data.status == 'error') {
                return request(new Error(data.error_message || data.error))
            }

            request(new Error('Unknown result: ' + data.result))
        }
    }

    if (data.type == 'response') return

    // Is this the result of a subscription?
    if (data.type == 'transaction') {
        assert.equal(data.status, 'closed')
        assert.equal(data.validated, true)

        if (this.allTransactions || data.engine_result == 'tesSUCCESS') {
            return this.emit('transaction', data.transaction)
        } else {
            return
        }
    }

    if (data.type == 'ledgerClosed') {
        return this.emit('ledgerclosed', data)
    }

    console.error('unhandled transaction type %s', data.type)
}

StellarClient.prototype.request = function(cmd, opts, cb) {
    if (typeof opts == 'function') {
        cb = opts
        opts = null
    }
    var id = this.commandIndex++
    , request = _.extend({
        id: id,
        command: cmd
    }, opts)

    debug('--> %s', util.inspect(request))

    this.conn.send(JSON.stringify(request, null, 4), function(err) {
        if (err) return cb ? cb(err) : null
        if (!cb) return
        this.requests[id] = cb
    }.bind(this))
}

function censor(s) {
    return s.replace(/secret\: ['"]?[A-Za-z0-9]+["']?/g, 'secret: *** SECRET ***')
}

StellarClient.prototype.submit = function(tx, cb) {
    assert(this.opts.secrets[tx.Account], 'secret missing for ' + tx.Account)
    assert(tx.TransactionType)

    var tx_json = _.defaults(tx, {
        Flags: 0
    })

    debug('tx_json %s', censor(util.inspect(tx_json, null, 4)))

    this.request('submit', {
        secret: this.opts.secrets[tx.Account],
        tx_json: tx_json
    }, function(err, res) {
        if (err) return cb(err)

        if (res.engine_result == 'tesSUCCESS') {
            return cb(null, res.tx_json.hash, res.tx_json.Sequence)
        }

        err = new Error(res.engine_result_message)
        err.name = res.engine_result
        err.code = res.engine_result_code
        return cb(err)
    })
}

function removeTrailingZeroes(s) {
    return s.replace(/\.?0+$/, '')
}

function toTheirPayment(our) {
    assert(our.currency)
    assert(our.amount)

    if (our.currency == 'XRP') {
        var n = num(our.amount).mul(1e6)
        n.set_precision(0)
        return n.toString()
    }

    var res = {
        value: removeTrailingZeroes(our.amount),
        currency: our.currency
    }

    if (our.issuer) res.issuer = our.issuer

    return res
}

StellarClient.prototype.payment = function(details, cb) {
    assert(details.from)
    assert(details.to)
    assert(details.amount)
    assert(details.currency)

    var tx = {
        TransactionType: 'Payment',
        Account: details.from,
        Amount: toTheirPayment({
            currency: details.currency,
            issuer: details.issuer,
            amount: details.amount
        }),
        Destination: details.to
    }

    if (details.dt) {
        tx.DestinationTag = details.dt
    }

    if (details.st) {
        tx.SourceTag = details.st
    }

    debug('submitting payment...')
    this.submit(tx, cb)
}

module.exports = StellarClient
<commit_msg>fix currency check in payment<commit_after>var _ = require('lodash')
var EventEmitter = require('events').EventEmitter
var util = require('util')
var debug = require('debug')('stellar-client')
var ReconWs = require('recon-ws')
var assert = require('assert')
var num = require('num')

function StellarClient(opts) {
    this.opts = _.extend({
        uri: 'wss://live.stellar.org:9001/',
        allTransactions: false
    }, opts)

    this.connected = false

    this.conn = new ReconWs(this.opts.uri)
    this.conn.on('open', this.connOpen.bind(this))
    this.conn.on('close', this.connClose.bind(this))
    this.conn.on('message', this.connMessage.bind(this))
}

util.inherits(StellarClient, EventEmitter)

StellarClient.prototype.connOpen = function() {
    debug('connected')
    this.commandIndex = 0
    this.requests = {}
    this.connected = true
    this.emit('open')
}

StellarClient.prototype.connClose = function() {
    debug('disconnected')
    this.connected = false

    // Resolve pending requests as error from disconnect
    _.each(this.requests, function(cb) {
        cb(new Error('Disconnected during request'))
    })

    this.emit('close')
}

StellarClient.prototype.connMessage = function(msg) {
    var data = JSON.parse(msg)
    debug('<-- %s', util.inspect(data))

    // Is this a response to a request?
    var id = data.id
    if (id !== undefined) {
        var request = this.requests[id]
        if (request) {
            delete this.requests[id]
            assert.equal(data.type, 'response')

            if (data.status == 'success') {
                return request(null, data.result)
            }

            if (data.status == 'error') {
                return request(new Error(data.error_message || data.error))
            }

            request(new Error('Unknown result: ' + data.result))
        }
    }

    if (data.type == 'response') return

    // Is this the result of a subscription?
    if (data.type == 'transaction') {
        assert.equal(data.status, 'closed')
        assert.equal(data.validated, true)

        if (this.allTransactions || data.engine_result == 'tesSUCCESS') {
            return this.emit('transaction', data.transaction)
        } else {
            return
        }
    }

    if (data.type == 'ledgerClosed') {
        return this.emit('ledgerclosed', data)
    }

    console.error('unhandled transaction type %s', data.type)
}

StellarClient.prototype.request = function(cmd, opts, cb) {
    if (typeof opts == 'function') {
        cb = opts
        opts = null
    }
    var id = this.commandIndex++
    , request = _.extend({
        id: id,
        command: cmd
    }, opts)

    debug('--> %s', util.inspect(request))

    this.conn.send(JSON.stringify(request, null, 4), function(err) {
        if (err) return cb ? cb(err) : null
        if (!cb) return
        this.requests[id] = cb
    }.bind(this))
}

function censor(s) {
    return s.replace(/secret\: ['"]?[A-Za-z0-9]+["']?/g, 'secret: *** SECRET ***')
}

StellarClient.prototype.submit = function(tx, cb) {
    assert(this.opts.secrets[tx.Account], 'secret missing for ' + tx.Account)
    assert(tx.TransactionType)

    var tx_json = _.defaults(tx, {
        Flags: 0
    })

    debug('tx_json %s', censor(util.inspect(tx_json, null, 4)))

    this.request('submit', {
        secret: this.opts.secrets[tx.Account],
        tx_json: tx_json
    }, function(err, res) {
        if (err) return cb(err)

        if (res.engine_result == 'tesSUCCESS') {
            return cb(null, res.tx_json.hash, res.tx_json.Sequence)
        }

        err = new Error(res.engine_result_message)
        err.name = res.engine_result
        err.code = res.engine_result_code
        return cb(err)
    })
}

function removeTrailingZeroes(s) {
    return s.replace(/\.?0+$/, '')
}

function toTheirPayment(our) {
    assert(our.currency)
    assert(our.amount)

    if (our.currency == 'STR') {
        var n = num(our.amount).mul(1e6)
        n.set_precision(0)
        return n.toString()
    }

    var res = {
        value: removeTrailingZeroes(our.amount),
        currency: our.currency
    }

    if (our.issuer) res.issuer = our.issuer

    return res
}

StellarClient.prototype.payment = function(details, cb) {
    assert(details.from)
    assert(details.to)
    assert(details.amount)
    assert(details.currency)

    var tx = {
        TransactionType: 'Payment',
        Account: details.from,
        Amount: toTheirPayment({
            currency: details.currency,
            issuer: details.issuer,
            amount: details.amount
        }),
        Destination: details.to
    }

    if (details.dt) {
        tx.DestinationTag = details.dt
    }

    if (details.st) {
        tx.SourceTag = details.st
    }

    debug('submitting payment...')
    this.submit(tx, cb)
}

module.exports = StellarClient
<|endoftext|>


<commit_before>// Copyright (C) 2016 Glamping Hub (https://glampinghub.com)
// License: BSD 3-Clause

/*jslint node: true, single: true, this: true */

'use strict';

var path = require('path');
var fs = require('fs');
var util = require('util');
var BaseStore = require('../../../core/server/storage/base');
var config = require('../../../core/server/config');
var Promise = require('bluebird');
var tmp = require('tmp');
var sharp = require('sharp');
var imagemin = require('imagemin');
var imageminGifsicle = require('imagemin-gifsicle');
var imageminJpegtran = require('imagemin-jpegtran');
var imageminOptipng = require('imagemin-optipng');

tmp.setGracefulCleanup();

function MinifyStore(config) {
    BaseStore.call(this);
    this.constructor(config);
}

util.inherits(MinifyStore, BaseStore);

MinifyStore.prototype.constructor = function (storageConfig) {
    // Configure next storage instance
    if (!storageConfig || !storageConfig.hasOwnProperty('nextStorage')) {
        throw 'You must configure the "nextStorage" property for the "Ghost Minified Storage"!';
    }
    var NextStorage;
    try {
        // CASE: load adapter from custom path  (.../content/storage)
        NextStorage = require(config.paths.storagePath.custom + storageConfig.nextStorage);
    } catch (err) {
        // CASE: only throw error if module does exist
        if (err.code !== 'MODULE_NOT_FOUND') {
            throw err.message;
        }

        // CASE: load adapter from default path
        NextStorage = require(config.paths.storagePath.default + storageConfig.nextStorage);
    }
    this.nextStorageInstance = new NextStorage(config.storage[storageConfig.nextStorage]);

    // Configure each property
    var that = this;
    [
        {name: 'saveOriginalFile', defaultValue: 'true'},
        {name: 'deleteOriginalFile', defaultValue: true},
        {name: 'maxWidth', defaultValue: false},
        {name: 'maxHeight', defaultValue: false},
        {name: 'regExWithoutSuffix', defaultValue: /^.+(\.[^\.]+)$/},
        {name: 'regExResultWithoutSuffix', defaultValue: '$1$2'},
        {name: 'regExWithSuffix', defaultValue: /^.+_resized(\.[^\.]+)$/},
        {name: 'regExResultWithSuffix', defaultValue: '$1_resized$2'}
    ].forEach(function (property) {
        that[property.name] = storageConfig.hasOwnProperty(property.name)
            ? storageConfig[property.name]
            : property.defaultValue;
    });
};

MinifyStore.prototype.save = function (file, targetDir) {
    /* file =
    < { fieldname: 'uploadimage',
    <   originalname: 'example.png',
    <   encoding: '7bit',
    <   mimetype: 'image/png',
    <   destination: '/tmp',
    <   filename: '67cc4b2c69cbf07d5839fbdb8ec76c44',
    <   path: '/tmp/67cc4b2c69cbf07d5839fbdb8ec76c44',
    <   size: 371703,
    <   name: 'example.png',
    <   type: 'image/png',
    <   context: { user: 1, client: null } }
    */

    var that = this;
    var resizeImageIfNeeds = function (src, resolve, reject) {
        try {
            // Resize image
            var buffer = sharp(src)
                .png({
                    progressive: true,
                    compressionLevel: 9
                })
                .jpeg({
                    quality: 80,
                    progressive: true,
                    optimizeScans: true
                });

            if (that.maxWidth || that.maxHeight) {
                buffer = buffer.resize(that.maxWidth, that.maxHeight).max();
            }
            buffer.toBuffer(function (err, buffer, info) {
                if (err) {
                    throw err;
                }
                resolve(buffer, info);
            });
        } catch (e) {
            reject(e);
        }
    };
    var minifyImage = function (buffer, resolve, reject) {
        tmp.file(function (err, temporalFilePath, ignore, cleanupCallback) {
            if (err) {
                throw err;
            }

            try {
                imagemin.buffer(buffer, {
                    plugins: [
                        imageminGifsicle(),
                        imageminJpegtran(),
                        imageminOptipng()
                    ]
                }).then(function (buffer) {  // files = [{data: <Buffer 89 50 4e …>, path: 'build/images/foo.jpg'}, …]
                    fs.writeFile(temporalFilePath, buffer, function (err) {
                        if (err) {
                            throw err;
                        }

                        var newFileObject = JSON.parse(JSON.stringify(file)); // JS clone stuff
                        newFileObject.originalname = file.originalname.replace(that.regExWithoutSuffix, that.regExResultWithSuffix);
                        newFileObject.filename = path.basename(temporalFilePath);
                        newFileObject.path = temporalFilePath;
                        newFileObject.size = buffer.length;

                        resolve(newFileObject)
                            .then(cleanupCallback, cleanupCallback)
                            .catch(cleanupCallback);
                    });
                });
            } catch (e) {
                cleanupCallback();
                reject(e);
            }
        });
    };

    return new Promise(function (resolve, reject) {
        // Save original image if needs
        if (that.saveOriginalFile) {
            that.nextStorageInstance.save(file, targetDir);
        }

        resizeImageIfNeeds(file.path, function (buffer) {
            minifyImage(buffer, function (file) {
                return that.nextStorageInstance
                    .save(file, targetDir)
                    .then(function (file2) {
                        resolve(file2);
                    });
            }, reject);
        }, reject);
    });
};

MinifyStore.prototype.exists = function () {
    return this.nextStorageInstance.exists.apply(this.nextStorageInstance, arguments);
};

MinifyStore.prototype.serve = function () {
    return this.nextStorageInstance.serve.apply(this.nextStorageInstance, arguments);
};

MinifyStore.prototype.delete = function (fileName, targetDir) {
    var promises = [this.nextStorageInstance.delete.apply(this.nextStorageInstance, arguments)];

    // Delete original image if needs
    if (this.deleteOriginalFile) {
        promises.push(this.nextStorageInstance.delete(fileName.replace(this.regExWithSuffix, this.regExResultWithoutSuffix), targetDir));
    }

    return Promise.all(promises);
};

module.exports = MinifyStore;
<commit_msg>Fix Ghost imports by requireFromGhost function<commit_after>// Copyright (C) 2016 Glamping Hub (https://glampinghub.com)
// License: BSD 3-Clause

/*jslint node: true, single: true, this: true */

'use strict';

var path = require('path');

// From: https://github.com/aorcsik/ghost-s3-storage-adapter/blob/master/index.js#L5
var requireFromGhost = function (moduleName, blocking) {
    try {
        return require('ghost/' + moduleName);
    } catch (e) {
        if (e.code !== 'MODULE_NOT_FOUND') {
            throw e;
        }
        try {
            return require(path.join(process.cwd(), moduleName));
        } catch (e2) {
            if (e2.code !== 'MODULE_NOT_FOUND' || blocking) {
                throw e;
            }
            return null;
        }
    }
};

var fs = require('fs');
var util = require('util');
var BaseStore = requireFromGhost('core/server/storage/base', false);
var config = requireFromGhost('core/server/config', false);
var Promise = require('bluebird');
var tmp = require('tmp');
var sharp = require('sharp');
var imagemin = require('imagemin');
var imageminGifsicle = require('imagemin-gifsicle');
var imageminJpegtran = require('imagemin-jpegtran');
var imageminOptipng = require('imagemin-optipng');

tmp.setGracefulCleanup();

function MinifyStore(config) {
    BaseStore.call(this);
    this.constructor(config);
}

util.inherits(MinifyStore, BaseStore);

MinifyStore.prototype.constructor = function (storageConfig) {
    // Configure next storage instance
    if (!storageConfig || !storageConfig.hasOwnProperty('nextStorage')) {
        throw 'You must configure the "nextStorage" property for the "Ghost Minified Storage"!';
    }
    var NextStorage;
    try {
        // CASE: load adapter from custom path  (.../content/storage)
        NextStorage = require(config.paths.storagePath.custom + storageConfig.nextStorage);
    } catch (err) {
        // CASE: only throw error if module does exist
        if (err.code !== 'MODULE_NOT_FOUND') {
            throw err.message;
        }

        // CASE: load adapter from default path
        NextStorage = require(config.paths.storagePath.default + storageConfig.nextStorage);
    }
    this.nextStorageInstance = new NextStorage(config.storage[storageConfig.nextStorage]);

    // Configure each property
    var that = this;
    [
        {name: 'saveOriginalFile', defaultValue: 'true'},
        {name: 'deleteOriginalFile', defaultValue: true},
        {name: 'maxWidth', defaultValue: false},
        {name: 'maxHeight', defaultValue: false},
        {name: 'regExWithoutSuffix', defaultValue: /^.+(\.[^\.]+)$/},
        {name: 'regExResultWithoutSuffix', defaultValue: '$1$2'},
        {name: 'regExWithSuffix', defaultValue: /^.+_resized(\.[^\.]+)$/},
        {name: 'regExResultWithSuffix', defaultValue: '$1_resized$2'}
    ].forEach(function (property) {
        that[property.name] = storageConfig.hasOwnProperty(property.name)
            ? storageConfig[property.name]
            : property.defaultValue;
    });
};

MinifyStore.prototype.save = function (file, targetDir) {
    /* file =
    < { fieldname: 'uploadimage',
    <   originalname: 'example.png',
    <   encoding: '7bit',
    <   mimetype: 'image/png',
    <   destination: '/tmp',
    <   filename: '67cc4b2c69cbf07d5839fbdb8ec76c44',
    <   path: '/tmp/67cc4b2c69cbf07d5839fbdb8ec76c44',
    <   size: 371703,
    <   name: 'example.png',
    <   type: 'image/png',
    <   context: { user: 1, client: null } }
    */

    var that = this;
    var resizeImageIfNeeds = function (src, resolve, reject) {
        try {
            // Resize image
            var buffer = sharp(src)
                .png({
                    progressive: true,
                    compressionLevel: 9
                })
                .jpeg({
                    quality: 80,
                    progressive: true,
                    optimizeScans: true
                });

            if (that.maxWidth || that.maxHeight) {
                buffer = buffer.resize(that.maxWidth, that.maxHeight).max();
            }
            buffer.toBuffer(function (err, buffer, info) {
                if (err) {
                    throw err;
                }
                resolve(buffer, info);
            });
        } catch (e) {
            reject(e);
        }
    };
    var minifyImage = function (buffer, resolve, reject) {
        tmp.file(function (err, temporalFilePath, ignore, cleanupCallback) {
            if (err) {
                throw err;
            }

            try {
                imagemin.buffer(buffer, {
                    plugins: [
                        imageminGifsicle(),
                        imageminJpegtran(),
                        imageminOptipng()
                    ]
                }).then(function (buffer) {  // files = [{data: <Buffer 89 50 4e …>, path: 'build/images/foo.jpg'}, …]
                    fs.writeFile(temporalFilePath, buffer, function (err) {
                        if (err) {
                            throw err;
                        }

                        var newFileObject = JSON.parse(JSON.stringify(file)); // JS clone stuff
                        newFileObject.originalname = file.originalname.replace(that.regExWithoutSuffix, that.regExResultWithSuffix);
                        newFileObject.filename = path.basename(temporalFilePath);
                        newFileObject.path = temporalFilePath;
                        newFileObject.size = buffer.length;

                        resolve(newFileObject)
                            .then(cleanupCallback, cleanupCallback)
                            .catch(cleanupCallback);
                    });
                });
            } catch (e) {
                cleanupCallback();
                reject(e);
            }
        });
    };

    return new Promise(function (resolve, reject) {
        // Save original image if needs
        if (that.saveOriginalFile) {
            that.nextStorageInstance.save(file, targetDir);
        }

        resizeImageIfNeeds(file.path, function (buffer) {
            minifyImage(buffer, function (file) {
                return that.nextStorageInstance
                    .save(file, targetDir)
                    .then(function (file2) {
                        resolve(file2);
                    });
            }, reject);
        }, reject);
    });
};

MinifyStore.prototype.exists = function () {
    return this.nextStorageInstance.exists.apply(this.nextStorageInstance, arguments);
};

MinifyStore.prototype.serve = function () {
    return this.nextStorageInstance.serve.apply(this.nextStorageInstance, arguments);
};

MinifyStore.prototype.delete = function (fileName, targetDir) {
    var promises = [this.nextStorageInstance.delete.apply(this.nextStorageInstance, arguments)];

    // Delete original image if needs
    if (this.deleteOriginalFile) {
        promises.push(this.nextStorageInstance.delete(fileName.replace(this.regExWithSuffix, this.regExResultWithoutSuffix), targetDir));
    }

    return Promise.all(promises);
};

module.exports = MinifyStore;
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var Orchestrator = require('orchestrator');
var gutil = require('gulp-util');
var deprecated = require('deprecated');
var vfs = require('vinyl-fs');

function Gulp() {
  Orchestrator.call(this);
}
util.inherits(Gulp, Orchestrator);

Gulp.prototype.task = Gulp.prototype.add;
Gulp.prototype.run = function() {
  // run() is deprecated as of 3.5 and will be removed in 4.0
  // use task dependencies instead

  // impose our opinion of "default" tasks onto orchestrator
  var tasks = arguments.length ? arguments : ['default'];

  this.start.apply(this, tasks);
};

Gulp.prototype.src = vfs.src;
Gulp.prototype.dest = vfs.dest;
Gulp.prototype.watch = function(glob, opt, fn) {
  if (typeof opt === 'function' || Array.isArray(opt)) {
    fn = opt;
    opt = null;
  }

  // array of tasks given
  if (Array.isArray(fn)) {
    return vfs.watch(glob, opt, function() {
      this.start.apply(this, fn);
    }.bind(this));
  }

  return vfs.watch(glob, opt, fn);
};

// let people use this class from our instance
Gulp.prototype.Gulp = Gulp;

// deprecations
deprecated.field('gulp.env has been deprecated. Use your own CLI parser instead. We recommend using yargs or minimist.', console.log, Gulp.prototype, 'env', gutil.env);
Gulp.prototype.run = deprecated.method('gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.', console.log, Gulp.prototype.run);

var inst = new Gulp();
module.exports = inst;
<commit_msg>console.warn deprecation errs<commit_after>'use strict';

var util = require('util');
var Orchestrator = require('orchestrator');
var gutil = require('gulp-util');
var deprecated = require('deprecated');
var vfs = require('vinyl-fs');

function Gulp() {
  Orchestrator.call(this);
}
util.inherits(Gulp, Orchestrator);

Gulp.prototype.task = Gulp.prototype.add;
Gulp.prototype.run = function() {
  // run() is deprecated as of 3.5 and will be removed in 4.0
  // use task dependencies instead

  // impose our opinion of "default" tasks onto orchestrator
  var tasks = arguments.length ? arguments : ['default'];

  this.start.apply(this, tasks);
};

Gulp.prototype.src = vfs.src;
Gulp.prototype.dest = vfs.dest;
Gulp.prototype.watch = function(glob, opt, fn) {
  if (typeof opt === 'function' || Array.isArray(opt)) {
    fn = opt;
    opt = null;
  }

  // array of tasks given
  if (Array.isArray(fn)) {
    return vfs.watch(glob, opt, function() {
      this.start.apply(this, fn);
    }.bind(this));
  }

  return vfs.watch(glob, opt, fn);
};

// let people use this class from our instance
Gulp.prototype.Gulp = Gulp;

// deprecations
deprecated.field('gulp.env has been deprecated. Use your own CLI parser instead. We recommend using yargs or minimist.', console.warn, Gulp.prototype, 'env', gutil.env);
Gulp.prototype.run = deprecated.method('gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.', console.warn, Gulp.prototype.run);

var inst = new Gulp();
module.exports = inst;
<|endoftext|>


<commit_before>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WEATHER BOT by dugup46!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

if (!process.env.token) {
    console.log('Error: Specify token in environment');
    process.exit(1);
}

var Botkit = require('./resources/botkit/lib/Botkit.js');
var os = require('os');

var controller = Botkit.slackbot({
    debug: false
});

var bot = controller.spawn({
    token: process.env.token
}).startRTM();

controller.hears(['help'], 'direct_message,direct_mention,mention', function(bot, message) {

    bot.api.reactions.add({
        timestamp: message.ts,
        channel: message.channel,
        name: 'sos',
    }, function(err, res) {
        if (err) {
            bot.botkit.log('Failed to add emoji reaction :(', err);
        }
    });

    var help = 'I will respond to the following messages: \n' +
      '`@' + bot.identity.name + ' radar <location>` to provide a base reflectivity scan of a given location.\n' +
      '`@' + bot.identity.name + ' bvscan <location>` to provide a base velocity scan of a given location.\n' +
      '`@' + bot.identity.name + ' What\'s the weather in <location>` provide temperature and conditions.\n' +
      '`@' + bot.identity.name + ' help` to see this again.'
	bot.reply(message, help)
});

controller.hears(['radar'], ['direct_message', 'direct_mention'], function (bot, message) {

    controller.storage.users.get(message.user, function(err, user) {

	bot.startConversation(message, function(err, convo) {

		convo.ask('Which radar site do you want?', function(response, convo) {

			convo.next();

		}, {'key': 'radarsite'}); // store the results in a field called nickname

		convo.ask('Which type of radar scan do you want?', function(response, convo) {

			convo.next();

		}, {'key': 'scantype'}); // store the results in a field called nickname

		convo.on('end', function(convo) {
			if (convo.status == 'completed') {

				var scantype = convo.extractResponse('scantype');
				var radarsite = convo.extractResponse('radarsite');

				switch(scantype) {
				case "reflect":
					var scantype = "N0R"
					break;
				case "velocity":
					var scantype = "N0V"
					break;
				case "motion":
					var scantype = "N0S"
					break;
				case "1hour":
					var scantype = "N1P"
					break;
				case "composite":
					var scantype = "NCR"
					break;
				case "total":
					var scantype = "NTP"
					break;
				default:
					scantype = "N0R"
				}

				var text = "Here is the " + scantype + " scan from your requested location: "
				var attachment = [{
						"title": "For a direct link to the NWS page for " + radarsite + ", click here.",
						"title_link": "http://www.weather.gov/" + radarsite + "/",
						"text": text,
						"fallback": text,
						"image_url": "http://radar.weather.gov/ridge/RadarImg/" + scantype + "/" + radarsite + "_" + scantype + "_0.gif",
						"color": "#7CD197",
				}]

				bot.reply(message, {
					attachments: attachment
				}, function (err, resp) {
					console.log(err, resp)
					})
				}
			});
		});
    });
})
<commit_msg>Main file for bot edits.  Last update 6/25<commit_after>/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WEATHER BOT by dugup46!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

if (!process.env.token) {
    console.log('Error: Specify token in environment');
    process.exit(1);
}

var Botkit = require('./resources/botkit/lib/Botkit.js');
var os = require('os');

var controller = Botkit.slackbot({
    debug: false
});

var bot = controller.spawn({
    token: process.env.token
}).startRTM();

controller.hears(['help'], 'direct_message,direct_mention,mention', function(bot, message) {

    bot.api.reactions.add({
        timestamp: message.ts,
        channel: message.channel,
        name: 'sos',
    }, function(err, res) {
        if (err) {
            bot.botkit.log('Failed to add emoji reaction :(', err);
        }
    });

    var help = '*1)* I will initiate by you typing the following message: \n' +
        '*`@' + bot.identity.name + ' radar`* After initial call, I will ask for site and type of scan.\n' +
	'*2)* You must provide the exact 3 letter NWS site ID - You can find that list here:\n' +
	'http://www.nws.noaa.gov/emwin/sitename.htm\n\n' +
        '*3)* Here is a list of all the types of scans I can currently run:\n' +
        '*`reflect` Base Reflecivity* - Lower level scan, most common.\n' +
        '*`velocity` Base Velocity* - Provides wind speeds and direction.\n' +
	'*`motion` Relative Storm Motion* - Provides small scale rotations and mesocyclones.\n' +
	'*`composite` Base Reflectivity* Composite - Composite scan of all BR level scans.\n' +
	'*`1hour` 1 Hour Precipitation* - Provides the level of rainfall in the past 1 hour.\n' +
	'*`total` Total Storm Precipitation* - Provides total precipitation from a storm.'
	bot.reply(message, help)
});

controller.hears(['radar'], ['direct_message', 'direct_mention'], function (bot, message) {

    controller.storage.users.get(message.user, function(err, user) {

	bot.startConversation(message, function(err, convo) {

		convo.ask('Which radar site do you want?', function(response, convo) {

			convo.next();

		}, {'key': 'radarsite'}); // store the results in a field called nickname

		convo.ask('Which type of radar scan do you want?', function(response, convo) {

			convo.next();

		}, {'key': 'scantype'}); // store the results in a field called nickname

		convo.on('end', function(convo) {
			if (convo.status == 'completed') {

				var scantype = convo.extractResponse('scantype');
				scantype = scantype.toLowerCase();
				var radarsite = convo.extractResponse('radarsite');
				radarsite = radarsite.toUpperCase();

				switch(scantype) {
				case "reflect":
					var scantype = "N0R"
					break;
				case "velocity":
					var scantype = "N0V"
					break;
				case "motion":
					var scantype = "N0S"
					break;
				case "1hour":
					var scantype = "N1P"
					break;
				case "composite":
					var scantype = "NCR"
					break;
				case "total":
					var scantype = "NTP"
					break;
				default:
					scantype = "N0R"
				}

				var text = "Here is the " + scantype + " scan from your requested location: "
				var attachment = [{
						"title": "For a direct link to the NWS page for " + radarsite + ", click here.",
						"title_link": "http://www.weather.gov/" + radarsite + "/",
						"text": text,
						"fallback": text,
						"image_url": "http://radar.weather.gov/ridge/RadarImg/" + scantype + "/" + radarsite + "_" + scantype + "_0.gif",
						"color": "#7CD197",
				}]

				bot.reply(message, {
					attachments: attachment
				}, function (err, resp) {
					console.log(err, resp)
					})
				}
			});
		});
    });
})
<|endoftext|>


<commit_before>var ogs = require('open-graph-scraper');
var express = require('express');
var ElasticSearch = require('elasticsearch');
var moment = require("moment-timezone");
var camoUrl = require('camo-url')({
	host : process.env.CAMO_HOST,
	key : process.env.CAMO_KEY
});
var URL = require('url');
var app = express();
var es = new ElasticSearch.Client({
	host : process.env.ES_URL,
	apiVersion : process.env.ES_VERSION
});

var esIndex = process.env.ES_INDEX;
var esType = process.env.ES_TYPE;

var INFO = "INFO";
var WARN = "WARN";
var ERR = "ERROR";

var BLOCKED_EXTENSIONS = ['pdf', 'gif', 'jpg', 'jpeg', 'png', 'svg'];

var CACHABLE_ERRORS = ['Page Not Found'];

var cacheInDays = parseInt(process.env.CACHE_IN_DAYS, 10) || 28;

function stringToUnderscore(input) {
	return input.replace(/([A-Z])/g, function ($1) {
		return "_" + $1.toLowerCase();
	});
}

function log(level, message) {
	console.log(JSON.stringify({time : moment(new Date()).format(), severity : level, message : message}));
}

function cacheExpired(date) {
	return moment(date).add(cacheInDays, 'days').isBefore(moment(new Date()));
}

function defaultOutput(url) {
	return Object.assign({}, {
		_url : url,
		_scrapedAt : parseInt(moment(new Date()).format('x'), 10),
		_cacheResponse : false,
		data : {}
	});
}

function postProcess(url, data) {
	var result = defaultOutput(url);

	// Format images for their special cases
	['ogImage', 'twitterImage'].forEach(function (key) {
		if (data[key]) {
			if (!data[key].url) {
				delete data[key];
			} else if (data[key].url) {
				var imageUrl = resolveRelative(data[key].url, url);
				if (process.env.CAMO_KEY && process.env.CAMO_HOST) {
					imageUrl = camoUrl(imageUrl);
				}
				var image = Object.assign({}, {value : imageUrl});
				Object.keys(data[key]).filter(function (e) {
					return e !== 'url';
				}).forEach(function (innerKey) {
					image[innerKey] = [{value : data[key][innerKey]}];
				});
				data[key] = image;
			}
		}
	});

	// Now map this to useful structures
	Object.keys(data).forEach(function (originalKey) {
		if (data[originalKey] === null || typeof data[originalKey] === 'undefined') {
			return;
		}

		var key;
		if (originalKey.startsWith('og')) {
			key = stringToUnderscore(originalKey.substring(2)).substring(1);
		}
		else if (originalKey.startsWith('twitter')) {
			key = stringToUnderscore(originalKey);
		} else {
			return;
		}

		if (data[originalKey].value) {
			result.data[key] = [data[originalKey]]
		} else {
			result.data[key] = [{value : data[originalKey]}]
		}
	});

	if (!result.data.url) {
		result.data.url = [{value : url}];
	}

	return result;
}

function resolveRelative(path, base) {
	// Absolute URL
	if (path.match(/^[a-z]*:\/\//)) {
		return path;
	}
	// Protocol relative URL
	if (path.indexOf("//") === 0) {
		return base.replace(/\/\/.*/, path)
	}
	// Upper directory
	if (path.indexOf("../") === 0) {
		return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
	}
	// Relative to the root
	if (path.indexOf('/') === 0) {
		if (!base.endsWith('/')) {
			base += '/';
		}
		var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
		return match[0] + path.slice(1);
	}
	//relative to the current directory
	return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}

if (process.env.ES_URL) {
	log(INFO, "Connected to Elasticsearch " + process.env.ES_VERSION + " on " + process.env.ES_URL + " using index '" + esIndex + "' with type '" + esType + "'. Using a cache of " + cacheInDays + " days.");
}

function cacheEntryIsValid(error, response, url) {
	if (!process.env.ES_URL) {
		// No ES cache entry is set
		log(WARN, "No ES cache specified, so skipping it");
		return false;
	}
	if (error) {
		if (error.status !== 404) {
			log(WARN, "Got an error [" + error.status + "] while fetching URL '" + url + "' from ES cache");
		}
		return false;
	}
	if (!response._source || !response._source._scrapedAt || cacheExpired(response._source._scrapedAt)) {
		log(WARN, 'Formatting error in cache, refetching ' + url);
		return false;
	}
	if (cacheExpired(response._source._scrapedAt)) {
		// cache is just expired
		log(INFO, "Getting new value for '" + url + "' since the cache expired");
		return false;
	}
	return true;
}

function workWorkWork(req, res) {
	var urlToFetch = req.query.url;
	var pathname = URL.parse(urlToFetch).pathname;
	var blockedResource = BLOCKED_EXTENSIONS.filter(function (extension) {
			return pathname.endsWith(extension);
		}).length > 0;
	if (blockedResource) {
		// Return standard format for misbehaving clients
		var blockedError = defaultOutput(urlToFetch);
		blockedError.error = 'This resource is blocked from fetching opengraph data';
		res.status(403).json(blockedError);
		return;
	}

	var encodedUrl = encodeURI(urlToFetch);
	es.get({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (cacheEntryIsValid(err, response, urlToFetch)) {
			// If there is an error, we do not have the opengraph data so we return a 404
			var statusCode = !response._source.error ? 200 : 404;
			res.status(statusCode).json(response._source);
		} else {
			var options = {
				url : urlToFetch,
				timeout : 5000
			};
			ogs(options, function (err, ogData) {
				var resultData;
				if (err || !ogData.success) {
					// Return the data to the client
					resultData = defaultOutput(urlToFetch);
					resultData.err = ogData.err;

					res.status(404).json(resultData);

					if (CACHABLE_ERRORS.indexOf(ogData.err) === -1) {
						// If this is a more permanent failure, we cache it
						log(ERR, 'Error while fetching OG data: ' + JSON.stringify(ogData));
						return;
					}
				} else {
					// All went well, postprocess and send to client
					resultData = postProcess(urlToFetch, ogData.data);
					res.json(resultData);
				}

				if (process.env.ES_URL) {
					resultData._cacheResponse = true;
					es.index({index : esIndex, type : esType, id : encodedUrl, body : resultData}, function (err) {
						if (err) {
							log(WARN, 'Could not save value to cache due to error: ' + err);
						}
					});
				}
			});
		}
	});
}

app.get('/opengraph', workWorkWork);
app.get('/_health', function (req, res) {
	res.end('Jolly good here');
});
app.listen(7070, function () {
	log(INFO, 'Server is listening');
});

<commit_msg>Log the failing url<commit_after>var ogs = require('open-graph-scraper');
var express = require('express');
var ElasticSearch = require('elasticsearch');
var moment = require("moment-timezone");
var camoUrl = require('camo-url')({
	host : process.env.CAMO_HOST,
	key : process.env.CAMO_KEY
});
var URL = require('url');
var app = express();
var es = new ElasticSearch.Client({
	host : process.env.ES_URL,
	apiVersion : process.env.ES_VERSION
});

var esIndex = process.env.ES_INDEX;
var esType = process.env.ES_TYPE;

var INFO = "INFO";
var WARN = "WARN";
var ERR = "ERROR";

var BLOCKED_EXTENSIONS = ['pdf', 'gif', 'jpg', 'jpeg', 'png', 'svg'];

var CACHABLE_ERRORS = ['Page Not Found'];

var cacheInDays = parseInt(process.env.CACHE_IN_DAYS, 10) || 28;

function stringToUnderscore(input) {
	return input.replace(/([A-Z])/g, function ($1) {
		return "_" + $1.toLowerCase();
	});
}

function log(level, message) {
	console.log(JSON.stringify({time : moment(new Date()).format(), severity : level, message : message}));
}

function cacheExpired(date) {
	return moment(date).add(cacheInDays, 'days').isBefore(moment(new Date()));
}

function defaultOutput(url) {
	return Object.assign({}, {
		_url : url,
		_scrapedAt : parseInt(moment(new Date()).format('x'), 10),
		_cacheResponse : false,
		data : {}
	});
}

function postProcess(url, data) {
	var result = defaultOutput(url);

	// Format images for their special cases
	['ogImage', 'twitterImage'].forEach(function (key) {
		if (data[key]) {
			if (!data[key].url) {
				delete data[key];
			} else if (data[key].url) {
				var imageUrl = resolveRelative(data[key].url, url);
				if (process.env.CAMO_KEY && process.env.CAMO_HOST) {
					imageUrl = camoUrl(imageUrl);
				}
				var image = Object.assign({}, {value : imageUrl});
				Object.keys(data[key]).filter(function (e) {
					return e !== 'url';
				}).forEach(function (innerKey) {
					image[innerKey] = [{value : data[key][innerKey]}];
				});
				data[key] = image;
			}
		}
	});

	// Now map this to useful structures
	Object.keys(data).forEach(function (originalKey) {
		if (data[originalKey] === null || typeof data[originalKey] === 'undefined') {
			return;
		}

		var key;
		if (originalKey.startsWith('og')) {
			key = stringToUnderscore(originalKey.substring(2)).substring(1);
		}
		else if (originalKey.startsWith('twitter')) {
			key = stringToUnderscore(originalKey);
		} else {
			return;
		}

		if (data[originalKey].value) {
			result.data[key] = [data[originalKey]]
		} else {
			result.data[key] = [{value : data[originalKey]}]
		}
	});

	if (!result.data.url) {
		result.data.url = [{value : url}];
	}

	return result;
}

function resolveRelative(path, base) {
	// Absolute URL
	if (path.match(/^[a-z]*:\/\//)) {
		return path;
	}
	// Protocol relative URL
	if (path.indexOf("//") === 0) {
		return base.replace(/\/\/.*/, path)
	}
	// Upper directory
	if (path.indexOf("../") === 0) {
		return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
	}
	// Relative to the root
	if (path.indexOf('/') === 0) {
		if (!base.endsWith('/')) {
			base += '/';
		}
		var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
		return match[0] + path.slice(1);
	}
	//relative to the current directory
	return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}

if (process.env.ES_URL) {
	log(INFO, "Connected to Elasticsearch " + process.env.ES_VERSION + " on " + process.env.ES_URL + " using index '" + esIndex + "' with type '" + esType + "'. Using a cache of " + cacheInDays + " days.");
}

function cacheEntryIsValid(error, response, url) {
	if (!process.env.ES_URL) {
		// No ES cache entry is set
		log(WARN, "No ES cache specified, so skipping it");
		return false;
	}
	if (error) {
		if (error.status !== 404) {
			log(WARN, "Got an error [" + error.status + "] while fetching URL '" + url + "' from ES cache");
		}
		return false;
	}
	if (!response._source || !response._source._scrapedAt || cacheExpired(response._source._scrapedAt)) {
		log(WARN, 'Formatting error in cache, refetching ' + url);
		return false;
	}
	if (cacheExpired(response._source._scrapedAt)) {
		// cache is just expired
		log(INFO, "Getting new value for '" + url + "' since the cache expired");
		return false;
	}
	return true;
}

function workWorkWork(req, res) {
	var urlToFetch = req.query.url;
	var pathname = URL.parse(urlToFetch).pathname;
	var blockedResource = BLOCKED_EXTENSIONS.filter(function (extension) {
			return pathname.endsWith(extension);
		}).length > 0;
	if (blockedResource) {
		// Return standard format for misbehaving clients
		var blockedError = defaultOutput(urlToFetch);
		blockedError.error = 'This resource is blocked from fetching opengraph data';
		res.status(403).json(blockedError);
		return;
	}

	var encodedUrl = encodeURI(urlToFetch);
	es.get({index : esIndex, type : esType, id : encodedUrl}, function (err, response) {
		if (cacheEntryIsValid(err, response, urlToFetch)) {
			// If there is an error, we do not have the opengraph data so we return a 404
			var statusCode = !response._source.error ? 200 : 404;
			res.status(statusCode).json(response._source);
		} else {
			var options = {
				url : urlToFetch,
				timeout : 5000
			};
			ogs(options, function (err, ogData) {
				var resultData;
				if (err || !ogData.success) {
					// Return the data to the client
					resultData = defaultOutput(urlToFetch);
					resultData.err = ogData.err;

					res.status(404).json(resultData);

					if (CACHABLE_ERRORS.indexOf(ogData.err) === -1) {
						// If this is a more permanent failure, we cache it
						log(ERR, 'Error while fetching OG data for ' + urlToFetch + ': ' + JSON.stringify(ogData));
						return;
					}
				} else {
					// All went well, postprocess and send to client
					resultData = postProcess(urlToFetch, ogData.data);
					res.json(resultData);
				}

				if (process.env.ES_URL) {
					resultData._cacheResponse = true;
					es.index({index : esIndex, type : esType, id : encodedUrl, body : resultData}, function (err) {
						if (err) {
							log(WARN, 'Could not save value to cache due to error: ' + err);
						}
					});
				}
			});
		}
	});
}

app.get('/opengraph', workWorkWork);
app.get('/_health', function (req, res) {
	res.end('Jolly good here');
});
app.listen(7070, function () {
	log(INFO, 'Server is listening');
});

<|endoftext|>


<commit_before>import errors from './errors';

// Returns `true` if the given array is not empty and at least one element is not `undefined`.
// hasContent :: any[] -> boolean
const hasContent = array => array.reduce(
  (hasContent, value) => hasContent || value !== undefined,
  false
);

// Remove all array indices for `undefined` values (besides the last element).
// removeUndefined :: any[] -> any[]
const removeUndefined = array => {
  const result = [];
  array.forEach((value, index) => {
    if (value !== undefined || index === array.length - 1) {
      result[index] = value;
    }
  });
  return result;
};

// Removes all empty observations and also undefined values from observations.
// cleanResult :: {}<any[]> -> {}<any[]>
const cleanResult = observed => Object.keys(observed).reduce(
  (cleanedObserved, name) => {
    const observation = observed[name];
    if (hasContent(observation)) {
      cleanedObserved[name] = removeUndefined(observation);
    }
    return cleanedObserved;
  }, {}
);

// Create on value handler function for an Observable with the given name. Add each value to the value event list for
// this Observable and add `undefined` to the value event lists of all other Observables.
// Also assure that the observed value is never undefined.
// addValue :: {}<any[]> -> string -> any -> void
const addValue = (observing, name) => value => {
  expect(value).not.toBe(undefined);
  Object.keys(observing).forEach(oname => {
    observing[oname].push(oname === name ? value : undefined);
  });
};

// Can be used to set trailing undefined value in observable test results.
global.undef = undefined;

// The name of the global error stream in the test results.
const errorsName = 'errors';

// Collects all events emitted by the given observables until all observables are ended. Calls the given callback
// with the result.
// observe :: {}<Observable<any>> -> ({}<any[]> -> void) -> void
global.observe = (observables, callback) => {
  // All value events for ended Observables.
  const observed = {}; // {}<any[]>
  // Collect all value events for all active Observables here.
  const observing = {}; // {}<any[]>
  observing[errorsName] = [];
  errors.onValue(addValue(observing, errorsName));
  // Iterate all observables
  Object.keys(observables).forEach(name => {
    // Get observable
    const observable = observables[name];
    if (observing[name] != null) {
      throw Error('Naming conflict');
    }
    // Initialize arrays to collect events of the current observable
    observing[name] = [];
    // Register listener to collect events
    observable
      .onValue(addValue(observing, name))
      .onEnd(() => {
        // Move key/value
        observed[name] = observing[name];
        delete observing[name];
        // If all observables are done
        if (Object.keys(observing).length === 1) {
          observed[errorsName] = observing[errorsName];
          callback(cleanResult(observed));
          callback = null; // Make sure callback is only called once
        } else {
          Object.keys(observing).forEach(oname => {
            observing[oname].push(undefined);
          });
        }
      });
  });
};
<commit_msg>Rename function; add ToDo<commit_after>import errors from './errors';

// Returns `true` if the given array is not empty and at least one element is not `undefined`.
// hasContent :: any[] -> boolean
const hasContent = array => array.reduce(
  (hasContent, value) => hasContent || value !== undefined,
  false
);

// Remove all array indices for `undefined` values (besides the last element).
// removeUndefined :: any[] -> any[]
const removeUndefined = array => {
  const result = [];
  array.forEach((value, index) => {
    if (value !== undefined || index === array.length - 1) {
      result[index] = value;
    }
  });
  return result;
};

// Removes all empty observations and also undefined values from observations.
// removeEmptyAndUndefined :: {}<any[]> -> {}<any[]>
const removeEmptyAndUndefined = observed => Object.keys(observed).reduce(
  (cleanedObserved, name) => {
    const observation = observed[name];
    if (hasContent(observation)) {
      cleanedObserved[name] = removeUndefined(observation);
    }
    return cleanedObserved;
  }, {}
);

// Create on value handler function for an Observable with the given name. Add each value to the value event list for
// this Observable and add `undefined` to the value event lists of all other Observables.
// Also assure that the observed value is never undefined.
// addValue :: {}<any[]> -> string -> any -> void
const addValue = (observing, name) => value => {
  expect(value).not.toBe(undefined);
  Object.keys(observing).forEach(oname => {
    observing[oname].push(oname === name ? value : undefined);
  });
};

// Can be used to set trailing undefined value in observable test results.
global.undef = undefined;

// The name of the global error stream in the test results.
const errorsName = 'errors';

// Collects all events emitted by the given observables until all observables are ended. Calls the given callback
// with the result.
// observe :: {}<Observable<any>> -> ({}<any[]> -> void) -> void
global.observe = (observables, callback) => {
  // All value events for ended Observables.
  const observed = {}; // {}<any[]>
  // Collect all value events for all active Observables here.
  const observing = {}; // {}<any[]>
  observing[errorsName] = [];
  //TODO: Unregister error listener when all observables end
  errors.onValue(addValue(observing, errorsName));
  // Iterate all observables
  Object.keys(observables).forEach(name => {
    // Get observable
    const observable = observables[name];
    if (observing[name] != null) {
      throw Error('Naming conflict');
    }
    // Initialize arrays to collect events of the current observable
    observing[name] = [];
    // Register listener to collect events
    observable
      .onValue(addValue(observing, name))
      .onEnd(() => {
        // Move key/value
        observed[name] = observing[name];
        delete observing[name];
        // If all observables are done
        if (Object.keys(observing).length === 1) {
          observed[errorsName] = observing[errorsName];
          callback(removeEmptyAndUndefined(observed));
          callback = null; // Make sure callback is only called once
        } else {
          Object.keys(observing).forEach(oname => {
            observing[oname].push(undefined);
          });
        }
      });
  });
};
<|endoftext|>


<commit_before>'use strict';

var each = require('each-async');
var fs = require('fs-extra');
var path = require('path');
var trashdir = require('xdg-trashdir');
var uuid = require('uuid');

/**
 * Safely move files and directories to trash on Linux
 *
 * @param {String} src
 * @param {Function} cb
 * @api private
 */

function trash(src, cb) {
	trashdir(src, function (err, dir) {
		if (err) {
			if (err.code === 'ENOENT') {
				err.noStack = true;
			}

			cb(err);
			return;
		}

		var name = uuid.v4();
		var dest = path.join(dir, 'files', name);
		var info = path.join(dir, 'info', name + '.trashinfo');

		var msg = [
			'[Trash Info]',
			'Path=' + src.replace(/\s/g, '%20'),
			'DeletionDate=' + new Date().toISOString()
		].join('\n');

		fs.move(src, dest, { mkdirp: true }, function (err) {
			if (err) {
				cb(err);
				return;
			}

			fs.outputFile(info, msg, function (err) {
				if (err) {
					cb(err);
					return;
				}

				cb(null, { path: dest, info: info });
			});
		});
	});
}

/**
 * Module exports
 *
 * @param {Array} paths
 * @param {Function} cb
 * @api public
 */

module.exports = function (paths, cb) {
	var files = [];
	cb = cb || function () {};

	if (process.platform !== 'linux') {
		cb(new Error('Only Linux systems are supported'));
		return;
	}

	if (!Array.isArray(paths)) {
		cb(new Error('`paths` is required'));
		return;
	}

	paths = paths.map(function (p) {
		return path.resolve(String(p));
	});

	each(paths, function (path, i, next) {
		trash(path, function (err, file) {
			if (err) {
				next(err);
				return;
			}

			files.push(file);
			next();
		});
	}, function (err) {
		if (err) {
			cb(err);
			return;
		}

		cb(null, files);
	});
};
<commit_msg>Throw error instead of returning it<commit_after>'use strict';

var each = require('each-async');
var fs = require('fs-extra');
var path = require('path');
var trashdir = require('xdg-trashdir');
var uuid = require('uuid');

/**
 * Safely move files and directories to trash on Linux
 *
 * @param {String} src
 * @param {Function} cb
 * @api private
 */

function trash(src, cb) {
	trashdir(src, function (err, dir) {
		if (err) {
			if (err.code === 'ENOENT') {
				err.noStack = true;
			}

			cb(err);
			return;
		}

		var name = uuid.v4();
		var dest = path.join(dir, 'files', name);
		var info = path.join(dir, 'info', name + '.trashinfo');

		var msg = [
			'[Trash Info]',
			'Path=' + src.replace(/\s/g, '%20'),
			'DeletionDate=' + new Date().toISOString()
		].join('\n');

		fs.move(src, dest, { mkdirp: true }, function (err) {
			if (err) {
				cb(err);
				return;
			}

			fs.outputFile(info, msg, function (err) {
				if (err) {
					cb(err);
					return;
				}

				cb(null, { path: dest, info: info });
			});
		});
	});
}

/**
 * Module exports
 *
 * @param {Array} paths
 * @param {Function} cb
 * @api public
 */

module.exports = function (paths, cb) {
	var files = [];
	cb = cb || function () {};

	if (process.platform !== 'linux') {
		throw new Error ('Only Linux systems are supported');
	}

	if (!Array.isArray(paths)) {
		cb(new Error('`paths` is required'));
		return;
	}

	paths = paths.map(function (p) {
		return path.resolve(String(p));
	});

	each(paths, function (path, i, next) {
		trash(path, function (err, file) {
			if (err) {
				next(err);
				return;
			}

			files.push(file);
			next();
		});
	}, function (err) {
		if (err) {
			cb(err);
			return;
		}

		cb(null, files);
	});
};
<|endoftext|>


<commit_before>module.exports = function(api) {
  var validEnv = ['development', 'test', 'production']
  var currentEnv = api.env()
  var isDevelopmentEnv = api.env('development')
  var isProductionEnv = api.env('production')
  var isTestEnv = api.env('test')

  if (!validEnv.includes(currentEnv)) {
    throw new Error(
      'Please specify a valid `NODE_ENV` or ' +
        '`BABEL_ENV` environment variables. Valid values are "development", ' +
        '"test", and "production". Instead, received: ' +
        JSON.stringify(env) +
        '.'
    )
  }

  return {
    presets: [
      isTestEnv && [
        require('@babel/preset-env').default,
        {
          targets: {
            node: 'current'
          }
        }
      ],
      (isProductionEnv || isDevelopmentEnv) && [
        require('@babel/preset-env').default,
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ],
      [
        require('@babel/preset-react').default,
        {
          development: isDevelopmentEnv || isTestEnv,
          useBuiltIns: true
        }
      ]
    ].filter(Boolean),
    plugins: [
      require('babel-plugin-macros'),
      require('@babel/plugin-syntax-dynamic-import').default,
      isTestEnv && require('babel-plugin-dynamic-import-node'),
      require('@babel/plugin-transform-destructuring').default,
      [
        require('@babel/plugin-proposal-class-properties').default,
        {
          loose: true
        }
      ],
      [
        require('@babel/plugin-proposal-object-rest-spread').default,
        {
          useBuiltIns: true
        }
      ],
      [
        require('@babel/plugin-transform-runtime').default,
        {
          helpers: false,
          regenerator: true
        }
      ],
      [
        require('@babel/plugin-transform-regenerator').default,
        {
          async: false
        }
      ],
      isProductionEnv && [
        require('babel-plugin-transform-react-remove-prop-types').default,
        {
          removeImport: true
        }
      ]
    ].filter(Boolean)
  }
}
<commit_msg>Typo in react babel config (#1881)<commit_after>module.exports = function(api) {
  var validEnv = ['development', 'test', 'production']
  var currentEnv = api.env()
  var isDevelopmentEnv = api.env('development')
  var isProductionEnv = api.env('production')
  var isTestEnv = api.env('test')

  if (!validEnv.includes(currentEnv)) {
    throw new Error(
      'Please specify a valid `NODE_ENV` or ' +
        '`BABEL_ENV` environment variables. Valid values are "development", ' +
        '"test", and "production". Instead, received: ' +
        JSON.stringify(currentEnv) +
        '.'
    )
  }

  return {
    presets: [
      isTestEnv && [
        require('@babel/preset-env').default,
        {
          targets: {
            node: 'current'
          }
        }
      ],
      (isProductionEnv || isDevelopmentEnv) && [
        require('@babel/preset-env').default,
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ],
      [
        require('@babel/preset-react').default,
        {
          development: isDevelopmentEnv || isTestEnv,
          useBuiltIns: true
        }
      ]
    ].filter(Boolean),
    plugins: [
      require('babel-plugin-macros'),
      require('@babel/plugin-syntax-dynamic-import').default,
      isTestEnv && require('babel-plugin-dynamic-import-node'),
      require('@babel/plugin-transform-destructuring').default,
      [
        require('@babel/plugin-proposal-class-properties').default,
        {
          loose: true
        }
      ],
      [
        require('@babel/plugin-proposal-object-rest-spread').default,
        {
          useBuiltIns: true
        }
      ],
      [
        require('@babel/plugin-transform-runtime').default,
        {
          helpers: false,
          regenerator: true
        }
      ],
      [
        require('@babel/plugin-transform-regenerator').default,
        {
          async: false
        }
      ],
      isProductionEnv && [
        require('babel-plugin-transform-react-remove-prop-types').default,
        {
          removeImport: true
        }
      ]
    ].filter(Boolean)
  }
}
<|endoftext|>


<commit_before>var Steam = require('steam-client');
var AppDirectory = require('appdirectory');
var FileStorage = require('file-manager');

require('util').inherits(SteamUser, require('events').EventEmitter);

module.exports = SteamUser;

SteamUser.Steam = Steam;
SteamUser.CurrencyData = require('./resources/CurrencyData.js');
SteamUser.EMachineIDType = require('./resources/EMachineIDType.js');
SteamUser.EPurchaseResult = require('./resources/EPurchaseResult.js');
SteamUser.EClientUIMode = require('./resources/EClientUIMode.js');

require('./resources/enums.js');

try {
	SteamUser.Steam.servers = require('./resources/servers.json');
} catch(e) {
	// It's okay if it isn't there
}

function SteamUser(client, options) {
	if(client && client.constructor.name !== 'SteamClient' && client.constructor.name !== 'CMClient') {
		options = client;
		client = null;
	}

	this.client = client ? client : new Steam.CMClient();
	this.steamID = null;

	// Account info
	this.limitations = null;
	this.vac = null;
	this.wallet = null;
	this.emailInfo = null;
	this.licenses = null;

	// Friends and users info
	this.users = {};
	this.groups = {};
	this.chats = {};
	this.myFriends = {};
	this.myGroups = {};
	this.myFriendGroups = {};

	this._gcTokens = []; // game connect tokens
	this._connectTime = 0;
	this._connectionCount = 0;
	this._authSeqMe = 0;
	this._authSeqThem = 0;
	this._hSteamPipe = Math.floor(Math.random() * 1000000) + 1;

	// App and package cache
	this._changelistUpdateTimer = null;
	this.picsCache = {
		"changenumber": 0,
		"apps": {},
		"packages": {}
	};

	this._sentry = null;

	var appdir = new AppDirectory({
		"appName": "node-steamuser",
		"appAuthor": "doctormckay"
	});

	this.options = options || {};

	var defaultOptions = {
		"dataDirectory": process.env.OPENSHIFT_DATA_DIR ? process.env.OPENSHIFT_DATA_DIR + "/node-steamuser" : appdir.userData(),
		"autoRelogin": true,
		"singleSentryfile": false,
		"promptSteamGuardCode": true,
		"machineIdType": SteamUser.EMachineIDType.AccountNameGenerated,
		"machineIdFormat": ["SteamUser Hash BB3 {account_name}", "SteamUser Hash FF2 {account_name}", "SteamUser Hash 3B3 {account_name}"],
		"enablePicsCache": false,
		"picsCacheAll": false,
		"changelistUpdateInterval": 60000,
		"saveAppTickets": true,
		"debug": false
	};

	for(var i in defaultOptions) {
		if(!defaultOptions.hasOwnProperty(i)) {
			continue;
		}

		if(typeof this.options[i] === 'undefined') {
			this.options[i] = defaultOptions[i];
		}
	}

	this.storage = new FileStorage(this.options.dataDirectory);

	this.client.on('message', this._handleMessage.bind(this));

	var self = this;
	this.client.on('error', function(e) {
		if(!self.steamID) {
			return; // We've already handled this
		}

		self._handleLogOff(e.eresult || SteamUser.EResult.NoConnection, e.message || "NoConnection");
	});

	this.client.on('servers', function(servers) {
		self.storage.writeFile('servers.json', JSON.stringify(servers, null, "\t"));
		if(!client) {
			// It's an internal client, so we know that our Steam has an up-to-date server list
			Steam['__SteamUserServersSet__'] = true;
		}
	});
}

SteamUser.prototype.setOption = function(option, value) {
	this.options[option] = value;

	// Handle anything that needs to happen when particular options update
	switch(option) {
		case 'dataDirectory':
			this.storage.directory = value;
			break;

		case 'enablePicsCache':
			this._resetChangelistUpdateTimer();
			this._getLicenseInfo();
			break;

		case 'changelistUpdateInterval':
			this._resetChangelistUpdateTimer();
			break;
	}
};

SteamUser.prototype.setOptions = function(options) {
	for(var i in options) {
		if(!options.hasOwnProperty(i)) {
			continue;
		}

		this.setOption(i, options[i]);
	}
};

require('./components/messages.js');
require('./components/logon.js');
require('./components/sentry.js');
require('./components/web.js');
require('./components/notifications.js');
require('./components/apps.js');
//require('./components/appauth.js');
require('./components/account.js');
require('./components/gameservers.js');
require('./components/utility.js');
require('./components/trading.js');
require('./components/friends.js');
require('./components/chat.js');
require('./components/twofactor.js');

/**
 * Called when the request completes.
 * @callback SteamUser~genericEResultCallback
 * @param {EResult} eresult - The result of the operation
 */
<commit_msg>Only use appdir for dataDirectory if not already provided<commit_after>var Steam = require('steam-client');
var AppDirectory = require('appdirectory');
var FileStorage = require('file-manager');

require('util').inherits(SteamUser, require('events').EventEmitter);

module.exports = SteamUser;

SteamUser.Steam = Steam;
SteamUser.CurrencyData = require('./resources/CurrencyData.js');
SteamUser.EMachineIDType = require('./resources/EMachineIDType.js');
SteamUser.EPurchaseResult = require('./resources/EPurchaseResult.js');
SteamUser.EClientUIMode = require('./resources/EClientUIMode.js');

require('./resources/enums.js');

try {
	SteamUser.Steam.servers = require('./resources/servers.json');
} catch(e) {
	// It's okay if it isn't there
}

function SteamUser(client, options) {
	if(client && client.constructor.name !== 'SteamClient' && client.constructor.name !== 'CMClient') {
		options = client;
		client = null;
	}

	this.client = client ? client : new Steam.CMClient();
	this.steamID = null;

	// Account info
	this.limitations = null;
	this.vac = null;
	this.wallet = null;
	this.emailInfo = null;
	this.licenses = null;

	// Friends and users info
	this.users = {};
	this.groups = {};
	this.chats = {};
	this.myFriends = {};
	this.myGroups = {};
	this.myFriendGroups = {};

	this._gcTokens = []; // game connect tokens
	this._connectTime = 0;
	this._connectionCount = 0;
	this._authSeqMe = 0;
	this._authSeqThem = 0;
	this._hSteamPipe = Math.floor(Math.random() * 1000000) + 1;

	// App and package cache
	this._changelistUpdateTimer = null;
	this.picsCache = {
		"changenumber": 0,
		"apps": {},
		"packages": {}
	};

	this._sentry = null;

	var appdir = new AppDirectory({
		"appName": "node-steamuser",
		"appAuthor": "doctormckay"
	});

	this.options = options || {};

	var defaultOptions = {
		"autoRelogin": true,
		"singleSentryfile": false,
		"promptSteamGuardCode": true,
		"machineIdType": SteamUser.EMachineIDType.AccountNameGenerated,
		"machineIdFormat": ["SteamUser Hash BB3 {account_name}", "SteamUser Hash FF2 {account_name}", "SteamUser Hash 3B3 {account_name}"],
		"enablePicsCache": false,
		"picsCacheAll": false,
		"changelistUpdateInterval": 60000,
		"saveAppTickets": true,
		"debug": false
	};

	for(var i in defaultOptions) {
		if(!defaultOptions.hasOwnProperty(i)) {
			continue;
		}

		if(typeof this.options[i] === 'undefined') {
			this.options[i] = defaultOptions[i];
		}
	}

	this.options.dataDirectory = this.options.dataDirectory || (process.env.OPENSHIFT_DATA_DIR ? process.env.OPENSHIFT_DATA_DIR + "/node-steamuser" : appdir.userData());

	this.storage = new FileStorage(this.options.dataDirectory);

	this.client.on('message', this._handleMessage.bind(this));

	var self = this;
	this.client.on('error', function(e) {
		if(!self.steamID) {
			return; // We've already handled this
		}

		self._handleLogOff(e.eresult || SteamUser.EResult.NoConnection, e.message || "NoConnection");
	});

	this.client.on('servers', function(servers) {
		self.storage.writeFile('servers.json', JSON.stringify(servers, null, "\t"));
		if(!client) {
			// It's an internal client, so we know that our Steam has an up-to-date server list
			Steam['__SteamUserServersSet__'] = true;
		}
	});
}

SteamUser.prototype.setOption = function(option, value) {
	this.options[option] = value;

	// Handle anything that needs to happen when particular options update
	switch(option) {
		case 'dataDirectory':
			this.storage.directory = value;
			break;

		case 'enablePicsCache':
			this._resetChangelistUpdateTimer();
			this._getLicenseInfo();
			break;

		case 'changelistUpdateInterval':
			this._resetChangelistUpdateTimer();
			break;
	}
};

SteamUser.prototype.setOptions = function(options) {
	for(var i in options) {
		if(!options.hasOwnProperty(i)) {
			continue;
		}

		this.setOption(i, options[i]);
	}
};

require('./components/messages.js');
require('./components/logon.js');
require('./components/sentry.js');
require('./components/web.js');
require('./components/notifications.js');
require('./components/apps.js');
//require('./components/appauth.js');
require('./components/account.js');
require('./components/gameservers.js');
require('./components/utility.js');
require('./components/trading.js');
require('./components/friends.js');
require('./components/chat.js');
require('./components/twofactor.js');

/**
 * Called when the request completes.
 * @callback SteamUser~genericEResultCallback
 * @param {EResult} eresult - The result of the operation
 */
<|endoftext|>


<commit_before>// Example express application adding the parse-server module to expose Parse
// compatible API routes.

//var postmark = require('postmark');

//require('newrelic');
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');

var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'myAppId',
  masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
  serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',  // Don't forget to change to https if needed
  liveQuery: {
    classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
  }
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();

// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
  res.status(200).send('Oh shit, wuddup!');
});

// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
  res.sendFile(path.join(__dirname, '/public/test.html'));
});

var client = new postmark.Client("10d4cbd2-e5f1-40d9-a3c9-3e027797fef3");

client.sendEmailWithTemplate({
  "From": "Shaun.dougherty@study-buddy-app.herokuapp.com",
  "To": userEmail,
  "TemplateId": 709801,
  "TemplateModel": {
    "product_name": "Study Buddy",
    "name": userFirstName,
    "action_url": "study-buddy-app.herokuapp.com/confirm",
    "username": userEmail,
    "sender_name": "Shaun Dougherty"
  }
});

var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
    console.log('parse-server-example running on port ' + port + '.');
});

// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
<commit_msg>Comment out Postmark<commit_after>// Example express application adding the parse-server module to expose Parse
// compatible API routes.

//var postmark = require('postmark');

//require('newrelic');
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');

var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'myAppId',
  masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
  serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',  // Don't forget to change to https if needed
  liveQuery: {
    classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
  }
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();

// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
  res.status(200).send('Oh shit, wuddup!');
});

// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
  res.sendFile(path.join(__dirname, '/public/test.html'));
});

//var client = new postmark.Client("10d4cbd2-e5f1-40d9-a3c9-3e027797fef3");

//client.sendEmailWithTemplate({
//  "From": "Shaun.dougherty@study-buddy-app.herokuapp.com",
//  "To": userEmail,
//  "TemplateId": 709801,
//  "TemplateModel": {
//    "product_name": "Study Buddy",
//    "name": userFirstName,
//    "action_url": "study-buddy-app.herokuapp.com/confirm",
//    "username": userEmail,
//    "sender_name": "Shaun Dougherty"
//  }
//});

var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
    console.log('parse-server-example running on port ' + port + '.');
});

// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
<|endoftext|>


<commit_before>/*!
 * minimist-plugins <https://github.com/jonschlinkert/minimist-plugins>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */

'use strict';

var Emitter = require('component-emitter');
var plugins = require('plugins');

function Plugins(minimist, options) {
  if (!(this instanceof Plugins)) {
    return new Plugins(minimist);
  }
  Emitter.call(this);
  this.options = options || {};
  this.plugins = new plugins();
  this.minimist = minimist;
}

Plugins.prototype = Emitter({
  constructor: Plugins,

  use: function (fn) {
    this.plugins.use(fn(this));
    return this;
  },

  parse: function (argv, opts, next) {
    if (typeof opts === 'function') {
      next = opts;
      opts = null;
    }
    argv = this.minimist(argv, opts);
    this.plugins.run(argv, function (err, args) {
      if (err) return next(err);
      args = Array.isArray(args) ? args[0] : args;
      this.emit('end', args);
      next(null, args);
    }.bind(this));
    return this;
  }
});

/**
 * Expose `Plugins`
 */

module.exports = Plugins;
<commit_msg>type checking<commit_after>/*!
 * minimist-plugins <https://github.com/jonschlinkert/minimist-plugins>
 *
 * Copyright (c) 2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */

'use strict';

var Emitter = require('component-emitter');
var plugins = require('plugins');

function Plugins(minimist, options) {
  if (!(this instanceof Plugins)) {
    return new Plugins(minimist);
  }
  if (typeof minimist !== 'function') {
    throw new TypeError('expect `minimist` be function');
  }

  Emitter.call(this);
  this.options = typeof options === 'object' ? options : {};
  this.plugins = new plugins();
  this.minimist = minimist;
}

Plugins.prototype = Emitter({
  constructor: Plugins,

  use: function (fn) {
    this.plugins.use(fn(this));
    return this;
  },

  parse: function (argv, opts, next) {
    if (typeof opts === 'function') {
      next = opts;
      opts = null;
    }
    argv = this.minimist(argv, opts);
    this.plugins.run(argv, function (err, args) {
      if (err) return next(err);
      args = Array.isArray(args) ? args[0] : args;
      this.emit('end', args);
      next(null, args);
    }.bind(this));
    return this;
  }
});

/**
 * Expose `Plugins`
 */

module.exports = Plugins;
<|endoftext|>


<commit_before>'use strict';
var split = require('split2');
var through = require('through2');
var pumpify = require('pumpify');
var repeating = require('repeating');

module.exports = function (indent, count) {
	indent = indent || ' ';
	count = typeof count === 'number' ? count : 1;

	return pumpify([split(), through(function (data, enc, cb) {
		cb(null, repeating(indent, count) + data + '\n');
	})]);
};
<commit_msg>simplify<commit_after>'use strict';
var split = require('split2');
var through = require('through2');
var pumpify = require('pumpify');
var repeating = require('repeating');

module.exports = function (indent, count) {
	indent = indent || ' ';
	count = typeof count === 'number' ? count : 1;

	return pumpify(split(), through(function (data, enc, cb) {
		cb(null, repeating(indent, count) + data + '\n');
	}));
};
<|endoftext|>