<commit_before>
// Load modules

var Url = require('url');
var Http = require('http');
var Https = require('https');
var Stream = require('stream');
var Zlib = require('zlib');
var Hoek = require('hoek');
var Boom = require('boom');

// Declare internals

var internals = {};

exports.request = function (method, url, options, callback, _trace) {

    options = options || {};

    Hoek.assert(options.payload === null || options.payload === undefined || typeof options.payload === 'string' || options.payload instanceof Stream || Buffer.isBuffer(options.payload), 'options.payload must be a string, a Buffer, or a Stream');

    // Setup request

    var uri = Url.parse(url);
    var timeoutId;
    uri.method = method.toUpperCase();
    uri.headers = options.headers;

    if (options.rejectUnauthorized !== undefined && uri.protocol === 'https:') {
        uri.rejectUnauthorized = options.rejectUnauthorized;
    }

    var redirects = (options.hasOwnProperty('redirects') ? options.redirects : false);      // Needed to allow 0 as valid value when passed recursively

    _trace = (_trace || []);
    _trace.push({ method: uri.method, url: url });

    var client = (uri.protocol === 'https:' ? Https : Http);
    if (options.agent) {
        uri.agent = options.agent;
    }

    var req = client.request(uri);

    var shadow = null;                                                                      // A copy of the streamed request payload when redirects are enabled

    // Register handlers

    var isFinished = false;
    var finish = function (err, res) {

        if (!callback || err) {
            if (res) {
                res.destroy();
            }

            req.abort();
        }

        if (!isFinished) {
            isFinished = true;

            req.removeAllListeners();
            req.on('error', Hoek.ignore);
            clearTimeout(timeoutId);

            if (callback) {
                return callback(err, res);
            }
        }
    };

    req.once('error', function (err) {

        err.trace = _trace;
        return finish(Boom.badGateway('Client request error', err));
    });

    req.once('response', function (res) {

        // Pass-through response

        if (redirects === false ||
            [301, 302, 307, 308].indexOf(res.statusCode) === -1) {

            return finish(null, res);
        }

        // Redirection

        var redirectMethod = (res.statusCode === 301 || res.statusCode === 302 ? 'GET' : uri.method);
        var location = res.headers.location;

        res.destroy();

        if (redirects === 0) {
            return finish(Boom.badGateway('Maximum redirections reached', _trace));
        }

        if (!location) {
            return finish(Boom.badGateway('Received redirection without location', _trace));
        }

        if (!location.match(/^https?:/i)) {
            location = Url.resolve(uri.href, location);
        }

        var redirectOptions = {
            headers: options.headers,
            payload: shadow || options.payload,         // shadow must be ready at this point if set
            redirects: --redirects
        };

        return exports.request(redirectMethod, location, redirectOptions, finish, _trace);
    });

    if (options.timeout) {
        timeoutId = setTimeout(function () {

            return finish(Boom.gatewayTimeout('Client request timeout'));
        }, options.timeout);
    }

    // Write payload

    if (uri.method !== 'GET' &&
        uri.method !== 'HEAD' &&
        options.payload !== null &&
        options.payload !== undefined) {            // Value can be falsey

        if (options.payload instanceof Stream) {
            var stream = options.payload;

            if (redirects) {
                var collector = new internals.Tap();
                collector.once('finish', function () {

                    shadow = collector.collect();
                });

                stream = options.payload.pipe(collector);
            }

            stream.pipe(req);
            return;
        }

        req.write(options.payload);
    }

    // Finalize request

    req.end();
};

// Tap

internals.Tap = function () {

    Stream.Transform.call(this);
    this.buffers = [];
};

Hoek.inherits(internals.Tap, Stream.Transform);

internals.Tap.prototype._transform = function (chunk, encoding, next) {

    this.buffers.push(chunk);
    next(null, chunk);
};

internals.Tap.prototype.collect = function () {

    return exports.toReadableStream(this.buffers);
};

// read()

exports.read = function (res /*, [options], callback */) {

    var options = (arguments.length === 3 ? arguments[1] : {});
    var callback = (arguments.length === 3 ? arguments[2] : arguments[1]);

    // Set stream timeout

    var clientTimeout = options.timeout;
    var clientTimeoutId = null;

    if (clientTimeout &&
        clientTimeout > 0) {

        clientTimeoutId = setTimeout(function () {

            finish(Boom.clientTimeout());
        }, clientTimeout);
    }

    // Finish once

    var finish = function (err, buffer) {

        clearTimeout(clientTimeoutId);
        reader.removeAllListeners();
        res.removeListener('error', onError);
        res.removeListener('close', onClose);
        res.on('error', Hoek.ignore);

        if (err ||
            !options.json) {

            return callback(err, buffer);
        }

        // Parse JSON

        var contentType = (res.headers && res.headers['content-type']) || '';
        var mime = contentType.split(';')[0].trim().toLowerCase();

        if (mime !== 'application/json') {
            return callback(null, buffer);
        }

        try {
            var json = JSON.parse(buffer.toString());
        }
        catch (err) {
            return callback(err, null);
        }

        return callback(null, json);
    };

    finish = Hoek.once(finish);

    // Hander errors

    var onError = function (err) {

        return finish(Boom.internal('Payload stream error', err));
    };

    var onClose = function () {

        return finish(Boom.internal('Payload stream closed prematurely'));
    };

    res.once('error', onError);
    res.once('close', onClose);

    // Read payload

    var reader = new internals.Recorder({ maxBytes: options.maxBytes });

    reader.once('error', function (err) {

        res.destroy();
        return finish(err);
    });

    reader.once('finish', function () {

        return finish(null, reader.collect());
    });

    res.pipe(reader);
};

// Recorder

internals.Recorder = function (options) {

    Stream.Writable.call(this);

    this.settings = Hoek.clone(options || {});
    this.buffers = [];
    this.length = 0;
};

Hoek.inherits(internals.Recorder, Stream.Writable);

internals.Recorder.prototype._write = function (chunk, encoding, next) {

    if (this.settings.maxBytes &&
        this.length + chunk.length > this.settings.maxBytes) {

        return this.emit('error', Boom.badRequest('Payload content length greater than maximum allowed: ' + this.settings.maxBytes));
    }

    this.length += chunk.length;
    this.buffers.push(chunk);
    next();
};

internals.Recorder.prototype.collect = function () {

    var buffer = (this.buffers.length === 0 ? new Buffer(0) : (this.buffers.length === 1 ? this.buffers[0] : Buffer.concat(this.buffers, this.length)));
    return buffer;
};

// toReadableStream()

exports.toReadableStream = function (payload, encoding) {

    return new internals.Payload(payload, encoding);
};

internals.Payload = function (payload, encoding) {

    Stream.Readable.call(this);
    this._data = [].concat(payload || '');
    this._encoding = encoding || 'utf8';
};

Hoek.inherits(internals.Payload, Stream.Readable);

internals.Payload.prototype._read = function (size) {

    for (var i = 0, il = this._data.length; i < il; ++i) {
        this.push(this._data[i], this._encoding);
    }

    this.push(null);
};

// parseCacheControl()

exports.parseCacheControl = function (field) {

    /*
        Cache-Control   = 1#cache-directive
        cache-directive = token [ "=" ( token / quoted-string ) ]
        token           = [^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+
        quoted-string   = "(?:[^"\\]|\\.)*"
    */

    //                             1: directive                                        =   2: token                                              3: quoted-string
    var regex = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;

    var header = {};
    var err = field.replace(regex, function ($0, $1, $2, $3) {

        var value = $2 || $3;
        header[$1] = value ? value.toLowerCase() : true;
        return '';
    });

    if (header['max-age']) {
        try {
            var maxAge = parseInt(header['max-age'], 10);
            if (isNaN(maxAge)) {
                return null;
            }

            header['max-age'] = maxAge;
        }
        catch (err) { }
    }

    return (err ? null : header);
};

// Shortcuts

internals.shortcut = function (method, uri /*, options, callback */) {

    var options = (typeof arguments[2] === 'function' ? {} : arguments[2]);
    var callback = (typeof arguments[2] === 'function' ? arguments[2] : arguments[3]);

    exports.request(method, uri, options, function (err, res) {

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

        exports.read(res, options, function (err, payload) {

            if (payload instanceof Buffer) {
                payload = payload.toString();
            }

            return callback(err, res, payload);
        });
    });
};

exports.get = function (uri, options, callback) { internals.shortcut('GET', uri, options, callback); };
exports.post = function (uri, options, callback) { internals.shortcut('POST', uri, options, callback); };
exports.put = function (uri, options, callback) { internals.shortcut('PUT', uri, options, callback); };
exports.delete = function (uri, options, callback) { internals.shortcut('DELETE', uri, options, callback); };
<commit_msg>match() -> test()<commit_after>
// Load modules

var Url = require('url');
var Http = require('http');
var Https = require('https');
var Stream = require('stream');
var Zlib = require('zlib');
var Hoek = require('hoek');
var Boom = require('boom');

// Declare internals

var internals = {};

exports.request = function (method, url, options, callback, _trace) {

    options = options || {};

    Hoek.assert(options.payload === null || options.payload === undefined || typeof options.payload === 'string' || options.payload instanceof Stream || Buffer.isBuffer(options.payload), 'options.payload must be a string, a Buffer, or a Stream');

    // Setup request

    var uri = Url.parse(url);
    var timeoutId;
    uri.method = method.toUpperCase();
    uri.headers = options.headers;

    if (options.rejectUnauthorized !== undefined && uri.protocol === 'https:') {
        uri.rejectUnauthorized = options.rejectUnauthorized;
    }

    var redirects = (options.hasOwnProperty('redirects') ? options.redirects : false);      // Needed to allow 0 as valid value when passed recursively

    _trace = (_trace || []);
    _trace.push({ method: uri.method, url: url });

    var client = (uri.protocol === 'https:' ? Https : Http);
    if (options.agent) {
        uri.agent = options.agent;
    }

    var req = client.request(uri);

    var shadow = null;                                                                      // A copy of the streamed request payload when redirects are enabled

    // Register handlers

    var isFinished = false;
    var finish = function (err, res) {

        if (!callback || err) {
            if (res) {
                res.destroy();
            }

            req.abort();
        }

        if (!isFinished) {
            isFinished = true;

            req.removeAllListeners();
            req.on('error', Hoek.ignore);
            clearTimeout(timeoutId);

            if (callback) {
                return callback(err, res);
            }
        }
    };

    req.once('error', function (err) {

        err.trace = _trace;
        return finish(Boom.badGateway('Client request error', err));
    });

    req.once('response', function (res) {

        // Pass-through response

        if (redirects === false ||
            [301, 302, 307, 308].indexOf(res.statusCode) === -1) {

            return finish(null, res);
        }

        // Redirection

        var redirectMethod = (res.statusCode === 301 || res.statusCode === 302 ? 'GET' : uri.method);
        var location = res.headers.location;

        res.destroy();

        if (redirects === 0) {
            return finish(Boom.badGateway('Maximum redirections reached', _trace));
        }

        if (!location) {
            return finish(Boom.badGateway('Received redirection without location', _trace));
        }

        if (!/^https?:/i.test(location)) {
            location = Url.resolve(uri.href, location);
        }

        var redirectOptions = {
            headers: options.headers,
            payload: shadow || options.payload,         // shadow must be ready at this point if set
            redirects: --redirects
        };

        return exports.request(redirectMethod, location, redirectOptions, finish, _trace);
    });

    if (options.timeout) {
        timeoutId = setTimeout(function () {

            return finish(Boom.gatewayTimeout('Client request timeout'));
        }, options.timeout);
    }

    // Write payload

    if (uri.method !== 'GET' &&
        uri.method !== 'HEAD' &&
        options.payload !== null &&
        options.payload !== undefined) {            // Value can be falsey

        if (options.payload instanceof Stream) {
            var stream = options.payload;

            if (redirects) {
                var collector = new internals.Tap();
                collector.once('finish', function () {

                    shadow = collector.collect();
                });

                stream = options.payload.pipe(collector);
            }

            stream.pipe(req);
            return;
        }

        req.write(options.payload);
    }

    // Finalize request

    req.end();
};

// Tap

internals.Tap = function () {

    Stream.Transform.call(this);
    this.buffers = [];
};

Hoek.inherits(internals.Tap, Stream.Transform);

internals.Tap.prototype._transform = function (chunk, encoding, next) {

    this.buffers.push(chunk);
    next(null, chunk);
};

internals.Tap.prototype.collect = function () {

    return exports.toReadableStream(this.buffers);
};

// read()

exports.read = function (res /*, [options], callback */) {

    var options = (arguments.length === 3 ? arguments[1] : {});
    var callback = (arguments.length === 3 ? arguments[2] : arguments[1]);

    // Set stream timeout

    var clientTimeout = options.timeout;
    var clientTimeoutId = null;

    if (clientTimeout &&
        clientTimeout > 0) {

        clientTimeoutId = setTimeout(function () {

            finish(Boom.clientTimeout());
        }, clientTimeout);
    }

    // Finish once

    var finish = function (err, buffer) {

        clearTimeout(clientTimeoutId);
        reader.removeAllListeners();
        res.removeListener('error', onError);
        res.removeListener('close', onClose);
        res.on('error', Hoek.ignore);

        if (err ||
            !options.json) {

            return callback(err, buffer);
        }

        // Parse JSON

        var contentType = (res.headers && res.headers['content-type']) || '';
        var mime = contentType.split(';')[0].trim().toLowerCase();

        if (mime !== 'application/json') {
            return callback(null, buffer);
        }

        try {
            var json = JSON.parse(buffer.toString());
        }
        catch (err) {
            return callback(err, null);
        }

        return callback(null, json);
    };

    finish = Hoek.once(finish);

    // Hander errors

    var onError = function (err) {

        return finish(Boom.internal('Payload stream error', err));
    };

    var onClose = function () {

        return finish(Boom.internal('Payload stream closed prematurely'));
    };

    res.once('error', onError);
    res.once('close', onClose);

    // Read payload

    var reader = new internals.Recorder({ maxBytes: options.maxBytes });

    reader.once('error', function (err) {

        res.destroy();
        return finish(err);
    });

    reader.once('finish', function () {

        return finish(null, reader.collect());
    });

    res.pipe(reader);
};

// Recorder

internals.Recorder = function (options) {

    Stream.Writable.call(this);

    this.settings = Hoek.clone(options || {});
    this.buffers = [];
    this.length = 0;
};

Hoek.inherits(internals.Recorder, Stream.Writable);

internals.Recorder.prototype._write = function (chunk, encoding, next) {

    if (this.settings.maxBytes &&
        this.length + chunk.length > this.settings.maxBytes) {

        return this.emit('error', Boom.badRequest('Payload content length greater than maximum allowed: ' + this.settings.maxBytes));
    }

    this.length += chunk.length;
    this.buffers.push(chunk);
    next();
};

internals.Recorder.prototype.collect = function () {

    var buffer = (this.buffers.length === 0 ? new Buffer(0) : (this.buffers.length === 1 ? this.buffers[0] : Buffer.concat(this.buffers, this.length)));
    return buffer;
};

// toReadableStream()

exports.toReadableStream = function (payload, encoding) {

    return new internals.Payload(payload, encoding);
};

internals.Payload = function (payload, encoding) {

    Stream.Readable.call(this);
    this._data = [].concat(payload || '');
    this._encoding = encoding || 'utf8';
};

Hoek.inherits(internals.Payload, Stream.Readable);

internals.Payload.prototype._read = function (size) {

    for (var i = 0, il = this._data.length; i < il; ++i) {
        this.push(this._data[i], this._encoding);
    }

    this.push(null);
};

// parseCacheControl()

exports.parseCacheControl = function (field) {

    /*
        Cache-Control   = 1#cache-directive
        cache-directive = token [ "=" ( token / quoted-string ) ]
        token           = [^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+
        quoted-string   = "(?:[^"\\]|\\.)*"
    */

    //                             1: directive                                        =   2: token                                              3: quoted-string
    var regex = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;

    var header = {};
    var err = field.replace(regex, function ($0, $1, $2, $3) {

        var value = $2 || $3;
        header[$1] = value ? value.toLowerCase() : true;
        return '';
    });

    if (header['max-age']) {
        try {
            var maxAge = parseInt(header['max-age'], 10);
            if (isNaN(maxAge)) {
                return null;
            }

            header['max-age'] = maxAge;
        }
        catch (err) { }
    }

    return (err ? null : header);
};

// Shortcuts

internals.shortcut = function (method, uri /*, options, callback */) {

    var options = (typeof arguments[2] === 'function' ? {} : arguments[2]);
    var callback = (typeof arguments[2] === 'function' ? arguments[2] : arguments[3]);

    exports.request(method, uri, options, function (err, res) {

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

        exports.read(res, options, function (err, payload) {

            if (payload instanceof Buffer) {
                payload = payload.toString();
            }

            return callback(err, res, payload);
        });
    });
};

exports.get = function (uri, options, callback) { internals.shortcut('GET', uri, options, callback); };
exports.post = function (uri, options, callback) { internals.shortcut('POST', uri, options, callback); };
exports.put = function (uri, options, callback) { internals.shortcut('PUT', uri, options, callback); };
exports.delete = function (uri, options, callback) { internals.shortcut('DELETE', uri, options, callback); };
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var ads = require('ad-params');
var clone = require('clone');
var cookie = require('cookie');
var extend = require('extend');
var integration = require('analytics.js-integration');
var json = require('segmentio/json@1.0.0');
var localstorage = require('store');
var md5 = require('SparkMD5').hash;
var protocol = require('protocol');
var send = require('send-json');
var topDomain = require('top-domain');
var utm = require('utm-params');
var uuid = require('uuid');

/**
 * Cookie options
 */

var cookieOptions = {
  // 1 year
  maxage: 31536000000,
  secure: false,
  path: '/'
};

/**
 * Expose `Scrubkit` integration.
 */

var Scrubkit = exports = module.exports = integration("scrubkit")
  .option('apiKey', '');

/**
 * Get the store.
 *
 * @return {Function}
 */

exports.storage = function() {
  return protocol() === 'file:' || protocol() === 'chrome-extension:' ? localstorage : cookie;
};

/**
 * Expose global for testing.
 */

exports.global = window;

/**
 * Initialize.
 *
 * @api public
 */

Scrubkit.prototype.initialize = function() {
  console.log("!");
  var self = this;
  this.ready();
  this.analytics.on('invoke', function(msg) {
    var action = msg.action();
    var listener = 'on' + msg.action();
    self.debug('%s %o', action, msg);
    if (self[listener]) self[listener](msg);
    self.ready();
  });
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */
/*
Scrubkit.prototype.loaded = function() {
  return true;
};
*/

/**
 * Page.
 *
 * @api public
 * @param {Page} page
 */

Scrubkit.prototype.page = function(page) {
  this.send('/p', page.json());
};

/**
 * Identify.
 *
 * @api public
 * @param {Identify} identify
 */

Scrubkit.prototype.identify = function(identify) {
  this.send('/i', identify.json());
};

/**
 * Group.
 *
 * @api public
 * @param {Group} group
 */

Scrubkit.prototype.group = function(group) {
  this.send('/g', group.json());
};

/**
 * ontrack.
 *
 * TODO: Document this.
 *
 * @api private
 * @param {Track} track
 */

Scrubkit.prototype.track = function(track, options) {
  console.log("track");
  var json = track.json();
  // TODO: figure out why we need traits.
  delete json.traits;
  this.send('/t', json);
};

/**
 * Alias.
 *
 * @api public
 * @param {Alias} alias
 */

Scrubkit.prototype.alias = function(alias) {
  var json = alias.json();
  var user = this.analytics.user();
  json.previousId = json.previousId || json.from || user.id() || user.anonymousId();
  json.userId = json.userId || json.to;
  delete json.from;
  delete json.to;
  this.send('/a', json);
};

/**
 * Normalize the given `msg`.
 *
 * @api private
 * @param {Object} msg
 */

Scrubkit.prototype.normalize = function(msg) {
  this.debug('normalize %o', msg);
  var user = this.analytics.user();
  var global = exports.global;
  var query = global.location.search;
  var ctx = msg.context = msg.context || msg.options || {};
  delete msg.options;
  msg.writeKey = this.options.apiKey;
  ctx.userAgent = navigator.userAgent;
  if (!ctx.library) ctx.library = { name: 'analytics.js', version: this.analytics.VERSION };
  if (query) ctx.campaign = utm(query);
  this.referrerId(query, ctx);
  msg.userId = msg.userId || user.id();
  msg.anonymousId = user.anonymousId();
  msg.sentAt = new Date();
  // add some randomness to the messageId checksum
  msg.messageId = 'ajs-' + md5(json.stringify(msg) + uuid());
  this.debug('normalized %o', msg);
  return msg;
};

/**
 * Send `obj` to `path`.
 *
 * @api private
 * @param {string} path
 * @param {Object} obj
 * @param {Function} fn
 */

Scrubkit.prototype.send = function(path, msg, fn) {
  var url = scheme() + '//api.scrubkit.com/v1' + path;
  var headers = { 'Content-Type': 'text/plain' };
  fn = fn || noop;
  var self = this;

  // msg
  msg = this.normalize(msg);

  // send
  send(url, msg, headers, function(err, res) {
    self.debug('sent %O, received %O', msg, arguments);
    if (err) return fn(err);
    res.url = url;
    fn(null, res);
  });
};

/**
 * Gets/sets cookies on the appropriate domain.
 *
 * @api private
 * @param {string} name
 * @param {*} val
 */

Scrubkit.prototype.cookie = function(name, val) {
  var store = Scrubkit.storage();
  if (arguments.length === 1) return store(name);
  var global = exports.global;
  var href = global.location.href;
  var domain = '.' + topDomain(href);
  if (domain === '.') domain = '';
  this.debug('store domain %s -> %s', href, domain);
  var opts = clone(cookieOptions);
  opts.domain = domain;
  this.debug('store %s, %s, %o', name, val, opts);
  store(name, val, opts);
  if (store(name)) return;
  delete opts.domain;
  this.debug('fallback store %s, %s, %o', name, val, opts);
  store(name, val, opts);
};

/**
 * Add referrerId to context.
 *
 * TODO: remove.
 *
 * @api private
 * @param {Object} query
 * @param {Object} ctx
 */

Scrubkit.prototype.referrerId = function(query, ctx) {
  var stored = this.cookie('s:context.referrer');
  var ad;

  if (stored) stored = json.parse(stored);
  if (query) ad = ads(query);

  ad = ad || stored;

  if (!ad) return;
  ctx.referrer = extend(ctx.referrer || {}, ad);
  this.cookie('s:context.referrer', json.stringify(ad));
};

/**
 * Get the scheme.
 *
 * The function returns `http:`
 * if the protocol is `http:` and
 * `https:` for other protocols.
 *
 * @api private
 * @return {string}
 */

function scheme() {
  return protocol() === 'http:' ? 'http:' : 'https:';
}

/**
 * Noop.
 */

function noop() {}
<commit_msg>Update index.js<commit_after>/**
 * Module dependencies.
 */

var ads = require('ad-params');
var clone = require('clone');
var cookie = require('cookie');
var extend = require('extend');
var integration = require('analytics.js-integration');
var json = require('segmentio/json@1.0.0');
var localstorage = require('store');
var md5 = require('SparkMD5').hash;
var protocol = require('protocol');
var send = require('send-json');
var topDomain = require('top-domain');
var utm = require('utm-params');
var uuid = require('uuid');

/**
 * Cookie options
 */

var cookieOptions = {
  // 1 year
  maxage: 31536000000,
  secure: false,
  path: '/'
};

/**
 * Expose `Pixelads` integration.
 */

var Pixelads = exports = module.exports = integration("pixelads")
  .option('apiKey', '');

/**
 * Get the store.
 *
 * @return {Function}
 */

exports.storage = function() {
  return protocol() === 'file:' || protocol() === 'chrome-extension:' ? localstorage : cookie;
};

/**
 * Expose global for testing.
 */

exports.global = window;

/**
 * Initialize.
 *
 * @api public
 */

Pixelads.prototype.initialize = function() {
  console.log("!");
  var self = this;
  this.ready();
  this.analytics.on('invoke', function(msg) {
    var action = msg.action();
    var listener = 'on' + msg.action();
    self.debug('%s %o', action, msg);
    if (self[listener]) self[listener](msg);
    self.ready();
  });
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */
/*
Pixelads.prototype.loaded = function() {
  return true;
};
*/

/**
 * Page.
 *
 * @api public
 * @param {Page} page
 */

Pixelads.prototype.page = function(page) {
  this.send('/p', page.json());
};

/**
 * Identify.
 *
 * @api public
 * @param {Identify} identify
 */

Pixelads.prototype.identify = function(identify) {
  this.send('/i', identify.json());
};

/**
 * Group.
 *
 * @api public
 * @param {Group} group
 */

Pixelads.prototype.group = function(group) {
  this.send('/g', group.json());
};

/**
 * ontrack.
 *
 * TODO: Document this.
 *
 * @api private
 * @param {Track} track
 */

Pixelads.prototype.track = function(track, options) {
  console.log("track");
  var json = track.json();
  // TODO: figure out why we need traits.
  delete json.traits;
  this.send('/t', json);
};

/**
 * Alias.
 *
 * @api public
 * @param {Alias} alias
 */

Pixelads.prototype.alias = function(alias) {
  var json = alias.json();
  var user = this.analytics.user();
  json.previousId = json.previousId || json.from || user.id() || user.anonymousId();
  json.userId = json.userId || json.to;
  delete json.from;
  delete json.to;
  this.send('/a', json);
};

/**
 * Normalize the given `msg`.
 *
 * @api private
 * @param {Object} msg
 */

Pixelads.prototype.normalize = function(msg) {
  this.debug('normalize %o', msg);
  var user = this.analytics.user();
  var global = exports.global;
  var query = global.location.search;
  var ctx = msg.context = msg.context || msg.options || {};
  delete msg.options;
  msg.writeKey = this.options.apiKey;
  ctx.userAgent = navigator.userAgent;
  if (!ctx.library) ctx.library = { name: 'analytics.js', version: this.analytics.VERSION };
  if (query) ctx.campaign = utm(query);
  this.referrerId(query, ctx);
  msg.userId = msg.userId || user.id();
  msg.anonymousId = user.anonymousId();
  msg.sentAt = new Date();
  // add some randomness to the messageId checksum
  msg.messageId = 'ajs-' + md5(json.stringify(msg) + uuid());
  this.debug('normalized %o', msg);
  return msg;
};

/**
 * Send `obj` to `path`.
 *
 * @api private
 * @param {string} path
 * @param {Object} obj
 * @param {Function} fn
 */

Pixelads.prototype.send = function(path, msg, fn) {
  var url = scheme() + '//api.pixelads.com/v1' + path;
  var headers = { 'Content-Type': 'text/plain' };
  fn = fn || noop;
  var self = this;

  // msg
  msg = this.normalize(msg);

  // send
  send(url, msg, headers, function(err, res) {
    self.debug('sent %O, received %O', msg, arguments);
    if (err) return fn(err);
    res.url = url;
    fn(null, res);
  });
};

/**
 * Gets/sets cookies on the appropriate domain.
 *
 * @api private
 * @param {string} name
 * @param {*} val
 */

Pixelads.prototype.cookie = function(name, val) {
  var store = Pixelads.storage();
  if (arguments.length === 1) return store(name);
  var global = exports.global;
  var href = global.location.href;
  var domain = '.' + topDomain(href);
  if (domain === '.') domain = '';
  this.debug('store domain %s -> %s', href, domain);
  var opts = clone(cookieOptions);
  opts.domain = domain;
  this.debug('store %s, %s, %o', name, val, opts);
  store(name, val, opts);
  if (store(name)) return;
  delete opts.domain;
  this.debug('fallback store %s, %s, %o', name, val, opts);
  store(name, val, opts);
};

/**
 * Add referrerId to context.
 *
 * TODO: remove.
 *
 * @api private
 * @param {Object} query
 * @param {Object} ctx
 */

Pixelads.prototype.referrerId = function(query, ctx) {
  var stored = this.cookie('s:context.referrer');
  var ad;

  if (stored) stored = json.parse(stored);
  if (query) ad = ads(query);

  ad = ad || stored;

  if (!ad) return;
  ctx.referrer = extend(ctx.referrer || {}, ad);
  this.cookie('s:context.referrer', json.stringify(ad));
};

/**
 * Get the scheme.
 *
 * The function returns `http:`
 * if the protocol is `http:` and
 * `https:` for other protocols.
 *
 * @api private
 * @return {string}
 */

function scheme() {
  return protocol() === 'http:' ? 'http:' : 'https:';
}

/**
 * Noop.
 */

function noop() {}
<|endoftext|>


<commit_before>var cp = require('child_process');
var path = require('path');
var Q = require('q');
var EventEmitter = require('events').EventEmitter;
var util = require('./util');
var HEARTBEAT_INTERVAL = util.HEARTBEAT_INTERVAL;
var HEARTBEAT_TIMEOUT = util.HEARTBEAT_TIMEOUT;
var MESSAGE = util.MESSAGE;
var DATA = util.DATA;
var MAIN = path.join(__dirname, 'main');
var cache = {};

function getKey(options) {
	var key = options && options.script;
	if (typeof key != 'string' || !(key = key.trim())) {
		return;
	}

	if (typeof options.value == 'string') {
		key = encodeURIComponent(key) + '?value=' + encodeURIComponent(options.value);
	}
	return key;
}

function fork(options, callback) {
	var key = getKey(options);
	if (!key) {
		return callback('options.script is required.');
	}
	var promise = cache[key];
	var defer;

	if (!promise) {
		defer = Q.defer();
		cache[key] = promise = defer.promise;
	}

	promise.done(function(result) {
		callback(null, result[0], result[1]);
	}, function(err) {
		callback(err);
	});

	if (!defer) {
		return;
	}

	var timeout, heartbeatTimeout, done;
	var emitter = new EventEmitter();
	var args = Array.isArray(options._args) ? options._args : [];
	delete options._args;
	args.push(MAIN, JSON.stringify(options));
	var child = cp.spawn('node', args, {
		detached: true,
		stdio: ['ipc']
	});

	child.on('error', errorHandler);
	child.on('close', errorHandler);
	child.on('exit', errorHandler);
	child.on('disconnect', errorHandler);
	child.on('message', function(msg) {
		clearTimeout(heartbeatTimeout);
		heartbeatTimeout = null;
		if (msg == MESSAGE) {
			return;
		}

		try {
			if (msg = JSON.parse(msg)) {
				if (msg.type == MESSAGE) {
					callbackHandler(null, msg.data);
				} else if (msg.type == DATA) {
					emitter.emit('data', msg.data);
				}
			}
		} catch(e) {}
	});
	child.stderr.on('data', function(err) {
		if (done) {
			return;
		}
		killChild();
		callbackHandler(err + '');
	});
	child.unref();
	keepAlive();
	promise.kill = killChild;

	function keepAlive() {
		timeout = setTimeout(function() {
			child.send(MESSAGE);
			keepAlive();
		}, HEARTBEAT_INTERVAL);
		if (!heartbeatTimeout) {
			heartbeatTimeout = setTimeout(errorHandler, HEARTBEAT_TIMEOUT);
		}
	}

	function errorHandler(err) {
		killChild();
		process.nextTick(function() {
			callbackHandler(err && err.stack || 'Error');
		});
	}

	function killChild(delay) {
		clearTimeout(heartbeatTimeout);
		clearTimeout(timeout);
		delete cache[key];
		var _kill = function() {
			try {
				process.kill(child.pid);
				child.removeAllListeners();
				child.on('error', util.noop);
				emitter.kill = util.noop;
				emitter.sendData = util.noop;
				emitter.emit('exit');
				child.stderr.removeAllListeners();
			} catch(e) {}
		};
		delay > 0 ? setTimeout(_kill, delay) : _kill();
	}

	function callbackHandler(err, data) {
		if (done) {
			return;
		}
		done = true;
		if (err) {
			defer.reject(err);
		} else {
			emitter.kill = killChild;
			emitter.sendData = function(data) {
				try {
					child.send(JSON.stringify({
						type: DATA,
						data: data
					}));
				} catch(e) {}
			};
			defer.resolve([data, emitter]);
		}
	}
}

exports.fork = fork;

function kill(options) {
	var key = getKey(options);
	if (!key) {
		return;
	}
	var child = cache[key];
	if (!child) {
		return;
	}
	child.kill();
}

exports.kill = kill;

function exists(options) {
	var key = getKey(options);
	if (!key || !cache[key]) {
		return false;
	}

	return true;
}

exports.exists = exists;

<commit_msg>enable delay to kill child process<commit_after>var cp = require('child_process');
var path = require('path');
var Q = require('q');
var EventEmitter = require('events').EventEmitter;
var util = require('./util');
var HEARTBEAT_INTERVAL = util.HEARTBEAT_INTERVAL;
var HEARTBEAT_TIMEOUT = util.HEARTBEAT_TIMEOUT;
var MESSAGE = util.MESSAGE;
var DATA = util.DATA;
var MAIN = path.join(__dirname, 'main');
var cache = {};

function getKey(options) {
	var key = options && options.script;
	if (typeof key != 'string' || !(key = key.trim())) {
		return;
	}

	if (typeof options.value == 'string') {
		key = encodeURIComponent(key) + '?value=' + encodeURIComponent(options.value);
	}
	return key;
}

function fork(options, callback) {
	var key = getKey(options);
	if (!key) {
		return callback('options.script is required.');
	}
	var promise = cache[key];
	var defer;

	if (!promise) {
		defer = Q.defer();
		cache[key] = promise = defer.promise;
	}

	promise.done(function(result) {
		callback(null, result[0], result[1]);
	}, function(err) {
		callback(err);
	});

	if (!defer) {
		return;
	}

	var timeout, heartbeatTimeout, done;
	var emitter = new EventEmitter();
	var args = Array.isArray(options._args) ? options._args : [];
	delete options._args;
	args.push(MAIN, JSON.stringify(options));
	var child = cp.spawn('node', args, {
		detached: true,
		stdio: ['ipc']
	});

	child.on('error', errorHandler);
	child.on('close', errorHandler);
	child.on('exit', errorHandler);
	child.on('disconnect', errorHandler);
	child.on('message', function(msg) {
		clearTimeout(heartbeatTimeout);
		heartbeatTimeout = null;
		if (msg == MESSAGE) {
			return;
		}

		try {
			if (msg = JSON.parse(msg)) {
				if (msg.type == MESSAGE) {
					callbackHandler(null, msg.data);
				} else if (msg.type == DATA) {
					emitter.emit('data', msg.data);
				}
			}
		} catch(e) {}
	});
	child.stderr.on('data', function(err) {
		if (done) {
			return;
		}
		killChild();
		callbackHandler(err + '');
	});
	child.unref();
	keepAlive();
	promise.kill = killChild;

	function keepAlive() {
		timeout = setTimeout(function() {
			child.send(MESSAGE);
			keepAlive();
		}, HEARTBEAT_INTERVAL);
		if (!heartbeatTimeout) {
			heartbeatTimeout = setTimeout(errorHandler, HEARTBEAT_TIMEOUT);
		}
	}

	function errorHandler(err) {
		killChild();
		process.nextTick(function() {
			callbackHandler(err && err.stack || 'Error');
		});
	}

	function killChild(delay) {
		clearTimeout(heartbeatTimeout);
		clearTimeout(timeout);
		delete cache[key];
		var _kill = function() {
			try {
				process.kill(child.pid);
				child.removeAllListeners();
				child.on('error', util.noop);
				emitter.kill = util.noop;
				emitter.sendData = util.noop;
				emitter.emit('exit');
				child.stderr.removeAllListeners();
			} catch(e) {}
		};
		delay > 0 ? setTimeout(_kill, delay) : _kill();
	}

	function callbackHandler(err, data) {
		if (done) {
			return;
		}
		done = true;
		if (err) {
			defer.reject(err);
		} else {
			emitter.kill = killChild;
			emitter.sendData = function(data) {
				try {
					child.send(JSON.stringify({
						type: DATA,
						data: data
					}));
				} catch(e) {}
			};
			defer.resolve([data, emitter]);
		}
	}
}

exports.fork = fork;

function kill(options, delay) {
	var key = getKey(options);
	if (!key) {
		return;
	}
	var child = cache[key];
	if (!child) {
		return;
	}
	child.kill(delay);
}

exports.kill = kill;

function exists(options) {
	var key = getKey(options);
	if (!key || !cache[key]) {
		return false;
	}

	return true;
}

exports.exists = exists;

<|endoftext|>


<commit_before>// Dependencies
var Ul = require("ul");

/**
 * CliGraph
 * Creates a new CliGraph instance.
 *
 * Example:
 *
 * ```js
 * var g = new CliGraph();
 * ```
 *
 * @name CliGraph
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `height` (Number): The graph height (default: `40`).
 *  - `width` (Number): The graph width (default: `60`).
 *  - `center` (Object): An object containing:
 *    - `x` (Number): The `x` origin (default: `width / 2`)
 *    - `y` (Number): The `y` origin (default: `height / 2`)
 *  - `marks` (Object): An object containing:
 *    - `hAxis` (String): The character for drawing horizontal axis (default `"─"`).
 *    - `vAxis` (String): The character for drawing vertical axis (default "│").
 *    - `center` (String): The character for axis intersection (default `"┼"`).
 *    - `point` (String): The character for drawing points (default `"•"`).
 *    - `rightArrow` (String): The character for drawing the right arrow (default `"▶"`).
 *    - `topArrow` (String): The character for drawing the top arrow (default `"▲"`).
 *    - `background` (String): The background character (default `" "`).
 *
 * @return {CliGraph} The CliGraph instance.
 */
function CliGraph(options) {

    // Initialize variables
    var self = this
      , settings = self.options = Ul.merge(options, Ul.clone(CliGraph.defaults))
      , i = 0
      , character = null
      , str = ""
      ;

    self.graph = [];
    settings.width *= settings.aRatio;

    // Set the center of the graph
    settings.center = Ul.merge(settings.center, {
        x: settings.width  / 2
      , y: settings.height / 2
    });

    settings.center.x = parseInt(settings.center.x);
    settings.center.y = parseInt(settings.center.y);

    // Background
    for (i = 0; i < settings.height; ++i) {
        self.graph[i] = new Array(settings.width).join(settings.marks.background).split("");
    }

    // Center
    self.graph[settings.center.y][settings.center.x] = settings.marks.center;

    // Ox axis
    for (i = 0; i < settings.width; ++i) {
        character = settings.marks.hAxis;
        if (i === settings.center.x) {
            character = settings.marks.center;
        } else if (i === settings.width - 1) {
            character = settings.marks.rightArrow;
        }

        self.graph[settings.center.y][i] = character;
    }

    // Oy asis
    for (i = 0; i < settings.height; ++i) {
        character = settings.marks.vAxis;
        if (i === settings.center.y) {
            character = settings.marks.center;
        } else if (i === 0) {
            character = settings.marks.topArrow;
        }

        self.graph[i][settings.center.x] = character;
    }

};

/**
 * addPoint
 * Adds a point on the `x` and `y` coordinates.
 *
 * @name addPoint
 * @function
 * @param {Number} x The `x` coordinate.
 * @param {Number} y The `y` coordinate.
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.addPoint = function (x, y) {

    var self = this;

    x = self.options.center.x + parseInt(x) * self.options.aRatio;
    y = self.options.center.y - parseInt(y);

    if (x >= self.options.width || x < 0
        || y >= self.options.height || y < 0) {
        return;
    }

    if (!self.graph[y]) {
        return;
    }

    self.graph[y][x] = self.options.marks.point;
    return self;
};

/**
 * toString
 * Stringifies the graph.
 *
 * @name toString
 * @function
 * @return {String} The stringified graph.
 */
CliGraph.prototype.toString = function () {
    var self = this
      , str = ""
      ;

    for (var i = 0; i < self.graph.length; ++i) {
        str += self.graph[i].join("") + "\n";
    }

    return str;
};

/**
 * setFunctionX
 * Adds the function on the graph, iterating the x axis.
 *
 * @name setFunctionX
 * @function
 * @param {Function} foo A function that receives `x` as the first parameter and returns the `y` value.
 * @param {Number} min The minimum `x` (default: the lowest possible value).
 * @param {Number} max The maximum `x`.(default: the highest possible value).
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.setFunctionX = function (foo, min, max) {
    var self = this;

    min = min || - (self.options.width + self.options.center.x) / 2;
    max = max || (self.options.width + self.options.center.x) / 2;

    for (var i = min; i <= max; ++i) {
        self.addPoint(i, foo(i));
    }

    return self;
};

/**
 * setFunctionY
 * Adds the function on the graph, iterating the y axis.
 *
 * @name setFunctionY
 * @function
 * @param {Function} foo A function that receives `y` as the first parameter and returns the `x` value.
 * @param {Number} min The minimum `y` (default: the lowest possible value).
 * @param {Number} max The maximum `y`.(default: the highest possible value).
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.setFunctionY = function (foo, min, max) {
    var self = this;

    min = min || - (self.options.height + self.options.center.y) / 2;
    max = max || (self.options.height + self.options.center.y) / 2;

    for (var i = min; i <= max; ++i) {
        self.addPoint(foo(i), i);
    }

    return self;
};

// Defaults
CliGraph.defaults = {
    width: 60
  , height: 40
  , marks: {
        hAxis: "─"
      , vAxis: "│"
      , center: "┼"
      , point: "•"
      , rightArrow: "▶"
      , topArrow: "▲"
      , background: " "
    }
  , center: {}
  , aRatio: 2
};

module.exports = CliGraph;
<commit_msg>Handle zero values for min and max variables.<commit_after>// Dependencies
var Ul = require("ul");

/**
 * CliGraph
 * Creates a new CliGraph instance.
 *
 * Example:
 *
 * ```js
 * var g = new CliGraph();
 * ```
 *
 * @name CliGraph
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `height` (Number): The graph height (default: `40`).
 *  - `width` (Number): The graph width (default: `60`).
 *  - `center` (Object): An object containing:
 *    - `x` (Number): The `x` origin (default: `width / 2`)
 *    - `y` (Number): The `y` origin (default: `height / 2`)
 *  - `marks` (Object): An object containing:
 *    - `hAxis` (String): The character for drawing horizontal axis (default `"─"`).
 *    - `vAxis` (String): The character for drawing vertical axis (default "│").
 *    - `center` (String): The character for axis intersection (default `"┼"`).
 *    - `point` (String): The character for drawing points (default `"•"`).
 *    - `rightArrow` (String): The character for drawing the right arrow (default `"▶"`).
 *    - `topArrow` (String): The character for drawing the top arrow (default `"▲"`).
 *    - `background` (String): The background character (default `" "`).
 *
 * @return {CliGraph} The CliGraph instance.
 */
function CliGraph(options) {

    // Initialize variables
    var self = this
      , settings = self.options = Ul.merge(options, Ul.clone(CliGraph.defaults))
      , i = 0
      , character = null
      , str = ""
      ;

    self.graph = [];
    settings.width *= settings.aRatio;

    // Set the center of the graph
    settings.center = Ul.merge(settings.center, {
        x: settings.width  / 2
      , y: settings.height / 2
    });

    settings.center.x = parseInt(settings.center.x);
    settings.center.y = parseInt(settings.center.y);

    // Background
    for (i = 0; i < settings.height; ++i) {
        self.graph[i] = new Array(settings.width).join(settings.marks.background).split("");
    }

    // Center
    self.graph[settings.center.y][settings.center.x] = settings.marks.center;

    // Ox axis
    for (i = 0; i < settings.width; ++i) {
        character = settings.marks.hAxis;
        if (i === settings.center.x) {
            character = settings.marks.center;
        } else if (i === settings.width - 1) {
            character = settings.marks.rightArrow;
        }

        self.graph[settings.center.y][i] = character;
    }

    // Oy asis
    for (i = 0; i < settings.height; ++i) {
        character = settings.marks.vAxis;
        if (i === settings.center.y) {
            character = settings.marks.center;
        } else if (i === 0) {
            character = settings.marks.topArrow;
        }

        self.graph[i][settings.center.x] = character;
    }

};

/**
 * addPoint
 * Adds a point on the `x` and `y` coordinates.
 *
 * @name addPoint
 * @function
 * @param {Number} x The `x` coordinate.
 * @param {Number} y The `y` coordinate.
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.addPoint = function (x, y) {

    var self = this;

    x = self.options.center.x + parseInt(x) * self.options.aRatio;
    y = self.options.center.y - parseInt(y);

    if (x >= self.options.width || x < 0
        || y >= self.options.height || y < 0) {
        return;
    }

    if (!self.graph[y]) {
        return;
    }

    self.graph[y][x] = self.options.marks.point;
    return self;
};

/**
 * toString
 * Stringifies the graph.
 *
 * @name toString
 * @function
 * @return {String} The stringified graph.
 */
CliGraph.prototype.toString = function () {
    var self = this
      , str = ""
      ;

    for (var i = 0; i < self.graph.length; ++i) {
        str += self.graph[i].join("") + "\n";
    }

    return str;
};

/**
 * setFunctionX
 * Adds the function on the graph, iterating the x axis.
 *
 * @name setFunctionX
 * @function
 * @param {Function} foo A function that receives `x` as the first parameter and returns the `y` value.
 * @param {Number} min The minimum `x` (default: the lowest possible value).
 * @param {Number} max The maximum `x`.(default: the highest possible value).
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.setFunctionX = function (foo, min, max) {
    var self = this;

    min = min === undefined ? - (self.options.width + self.options.center.x) / 2 : min;
    max = max === undefined ? (self.options.width + self.options.center.x) / 2 : max;

    for (var i = min; i <= max; ++i) {
        self.addPoint(i, foo(i));
    }

    return self;
};

/**
 * setFunctionY
 * Adds the function on the graph, iterating the y axis.
 *
 * @name setFunctionY
 * @function
 * @param {Function} foo A function that receives `y` as the first parameter and returns the `x` value.
 * @param {Number} min The minimum `y` (default: the lowest possible value).
 * @param {Number} max The maximum `y`.(default: the highest possible value).
 * @return {CliGraph} The CliGraph instance.
 */
CliGraph.prototype.setFunctionY = function (foo, min, max) {
    var self = this;

    min = min === undefined ? - (self.options.height + self.options.center.y) / 2 : min;
    max = max === undefined ? (self.options.height + self.options.center.y) / 2 : max;

    for (var i = min; i <= max; ++i) {
        self.addPoint(foo(i), i);
    }

    return self;
};

// Defaults
CliGraph.defaults = {
    width: 60
  , height: 40
  , marks: {
        hAxis: "─"
      , vAxis: "│"
      , center: "┼"
      , point: "•"
      , rightArrow: "▶"
      , topArrow: "▲"
      , background: " "
    }
  , center: {}
  , aRatio: 2
};

module.exports = CliGraph;
<|endoftext|>


<commit_before>"use strict";

// Dependencies
const EngineTools = require("engine-tools")
    , SameTime = require("same-time")
    , EngineParser = require("engine-parser")
    , Parser = require("./parser")
    , IterateObject = require("iterate-object")
    , Typpy = require("typpy")
    ;

/**
 * EngineParserGen
 * Creates a new instance of `EngineParserGen`.
 *
 *
 * @name EngineParserGen
 * @function
 * @param {String} app The application name.
 * @return {EngineParserGen} The `EngineParserGen` instance.
 */
class EngineParserGen {

    constructor (app) {
        if (typeof app !== "string" || !app) {
            throw new TypeError("The app parameter should be a string.");
        }
        this.app = app;
        this.path = EngineTools.getAppPath(this.app);
    }

    /**
     * parse
     * Parses the instances in a format that Enny can understand and stringify.
     *
     * @name parse
     * @function
     * @param {Function} cb The callback function.
     */
    parse (cb) {

        // Read the instances
        EngineTools.getComposition(this.app, { iName: true }, (err, data) => {
            if (err) { return cb(err); }

            // Parse the raw json
            this.parser = new Parser(data);
            cb(null, this.parser.parse());
        });
    }

    /**
     * renameInstance
     * Renames an instance.
     *
     * @name renameInstance
     * @function
     * @param {String} oldName The old instance name.
     * @param {String} newName The new instance name.
     * @param {Function} cb The callback function.
     * @return {EngineParserGen} The `EngineParserGen` instance.
     */
    renameInstance (oldName, newName, cb) {
        this.parse((err, data) => {
            if (err) { return cb(err); }
            this.parser.data.renameInstance(oldName, newName, (err, changedInstances) => {
                if (err) { return cb(err); }
                this.parser.instances = this.parser.data.toObject();
                changedInstances[newName] = true;
                cb(null, changedInstances, oldName);
            });
        });
        return this;
    }

    /**
     * save
     *
     * @name save
     * @function
     * @param {Object} options An object containing the following fields:
     *
     *  - `save` (Object|String): The instance name to save or an object with the instance names (e.g. `{ "layout": true }`).
     *  - `delete` (Object|String): The instance name to delete or an object with the instance names (e.g. `{ "layout": true }`).
     *
     * @param {Function} cb The callback function.
     */
    save (options, cb) {
        var foos = [];

        if (!options.save && !options.delete) {
            return cb(null, null);
        }

        // { save: "layout" }
        if (typeof options.save === "string") {
            let s = options.save;
            options.save = {};
            options.save[s] = true;
        }

        // { delete: "layout" }
        if (typeof options.delete === "string") {
            let d = options.delete;
            options.delete = {};
            options.delete[d] = true;
        }

        // Collect delete
        IterateObject(options.delete, (_, cDelete) => {
            foos.push(done => {
                EngineTools.deleteInstance(this.app, cDelete, done);
            });
        });

        // Collect save
        IterateObject(options.save, (_, _cSave) => {
            var cSave = this.parser.instances[_cSave] || _cSave;

            // Validate the instance to save
            if (!Typpy(cSave, Object)) {
                foos.push(done => {
                    done(new Error("Instance doesn't exist: " + _cSave));
                });
                return;
            }

            // Push the new function
            foos.push(done => {
                EngineTools.saveInstance(this.app, cSave, done);
            });
        });

        SameTime(foos, cb);
    }
}

module.exports = EngineParserGen;
<commit_msg>Check the old and new names<commit_after>"use strict";

// Dependencies
const EngineTools = require("engine-tools")
    , SameTime = require("same-time")
    , EngineParser = require("engine-parser")
    , Parser = require("./parser")
    , IterateObject = require("iterate-object")
    , Typpy = require("typpy")
    ;

/**
 * EngineParserGen
 * Creates a new instance of `EngineParserGen`.
 *
 *
 * @name EngineParserGen
 * @function
 * @param {String} app The application name.
 * @return {EngineParserGen} The `EngineParserGen` instance.
 */
class EngineParserGen {

    constructor (app) {
        if (typeof app !== "string" || !app) {
            throw new TypeError("The app parameter should be a string.");
        }
        this.app = app;
        this.path = EngineTools.getAppPath(this.app);
    }

    /**
     * parse
     * Parses the instances in a format that Enny can understand and stringify.
     *
     * @name parse
     * @function
     * @param {Function} cb The callback function.
     */
    parse (cb) {

        // Read the instances
        EngineTools.getComposition(this.app, { iName: true }, (err, data) => {
            if (err) { return cb(err); }

            // Parse the raw json
            this.parser = new Parser(data);
            cb(null, this.parser.parse());
        });
    }

    /**
     * renameInstance
     * Renames an instance.
     *
     * @name renameInstance
     * @function
     * @param {String} oldName The old instance name.
     * @param {String} newName The new instance name.
     * @param {Function} cb The callback function.
     * @return {EngineParserGen} The `EngineParserGen` instance.
     */
    renameInstance (oldName, newName, cb) {
        if (typeof oldName !== "string") {
            return cb(new TypeError("The old name should be a string."));
        }
        if (typeof newName !== "string") {
            return cb(new TypeError("The new name should be a string."));
        }
        this.parse((err, data) => {
            if (err) { return cb(err); }
            this.parser.data.renameInstance(oldName, newName, (err, changedInstances) => {
                if (err) { return cb(err); }
                this.parser.instances = this.parser.data.toObject();
                changedInstances[newName] = true;
                cb(null, changedInstances, oldName);
            });
        });
        return this;
    }

    /**
     * save
     *
     * @name save
     * @function
     * @param {Object} options An object containing the following fields:
     *
     *  - `save` (Object|String): The instance name to save or an object with the instance names (e.g. `{ "layout": true }`).
     *  - `delete` (Object|String): The instance name to delete or an object with the instance names (e.g. `{ "layout": true }`).
     *
     * @param {Function} cb The callback function.
     */
    save (options, cb) {
        var foos = [];

        if (!options.save && !options.delete) {
            return cb(null, null);
        }

        // { save: "layout" }
        if (typeof options.save === "string") {
            let s = options.save;
            options.save = {};
            options.save[s] = true;
        }

        // { delete: "layout" }
        if (typeof options.delete === "string") {
            let d = options.delete;
            options.delete = {};
            options.delete[d] = true;
        }

        // Collect delete
        IterateObject(options.delete, (_, cDelete) => {
            foos.push(done => {
                EngineTools.deleteInstance(this.app, cDelete, done);
            });
        });

        // Collect save
        IterateObject(options.save, (_, _cSave) => {
            var cSave = this.parser.instances[_cSave] || _cSave;

            // Validate the instance to save
            if (!Typpy(cSave, Object)) {
                foos.push(done => {
                    done(new Error("Instance doesn't exist: " + _cSave));
                });
                return;
            }

            // Push the new function
            foos.push(done => {
                EngineTools.saveInstance(this.app, cSave, done);
            });
        });

        SameTime(foos, cb);
    }
}

module.exports = EngineParserGen;
<|endoftext|>


<commit_before>/*!
 * nodejs ios-xr grpc connection library
 * Copyright(c) 2016 Cisco Systems
 * Apache v2 Licensed
 */

 'use strict';

/**
 * Module Dependencies
 * @private
 */

var grpc = require('grpc');
var ems_grpc = require(__dirname + '/proto/ems_grpc_grpc_pb.js');
var ems_grpc_msgs = require(__dirname + '/proto/ems_grpc_pb.js');

/**
 * Module Exports
 * @public
 */

module.exports = xrGrpc;

/**
 * Module Source
 * @private
 */

function xrGrpc(address, port, credentials, metadata, options) {
	if (!(this instanceof xrGrpc)) return new xrGrpc(address, port, credentials, username, password);

	this.address = server;
	this.port = port.toString();
	// Just default to insecure right now, fix in the future.
	this.credentials = grpc.credentials.createInsecure();
	// Set default parameters
	this.default = {};
	this.default.metadata = this.createMetadata(metadata);
	this.default.options = options;
	// Create client object
	this.xrGrpcClient = new ems_grpc.gRPCConfigOperClient(this.getAddress(), this.credentials);
	this.xrGrpcCliClient = new ems_grpc.gRPCExecClient(this.getAddress(), this.credentials);
}

xrGrpc.prototype.getAddress = function() {
	return this.serverAddress + ':' + this.serverPort.toString();
}

/**
 * Change the default metadata values.
 */
xrGrpc.prototype.setMetadata = function(metadata) {
	this.default.metadata = this.createMetadata(metadata);
}

/**
 * Create metadata for gRPC calls.
 * Accepts an "associative array" to translate into metadata.
 */
xrGrpc.prototype.createMetadata = function(metadata) {
	var meta = new grpc.Metadata();
	for (var key in metadata)
		meta.add(key, metadata[key]);
	return meta;
}

xrGrpc.prototype.getConfig = function() {

}

xrGrpc.prototype.mergeConfig = function() {

}

xrGrpc.prototype.deleteConfig = function() {

}

xrGrpc.prototype.replaceConfig = function() {

}

xrGrpc.prototype.cliConfig = function() {

}

xrGrpc.prototype.commitReplace = function() {

}

xrGrpc.prototype.commitConfig = function() {

}

xrGrpc.prototype.configDiscardChanges = function() {

}

xrGrpc.prototype.getOper = function() {

}

xrGrpc.prototype.showCmdTextOutput = function() {

}

xrGrpc.prototype.showCmdJSONOutput = function() {

}

<commit_msg>XRCL-13 gRPC SSL Authentication<commit_after>/*!
 * nodejs ios-xr grpc connection library
 * Copyright(c) 2016 Cisco Systems
 * Apache v2 Licensed
 */

 'use strict';

/**
 * Module Dependencies
 * @private
 */

var grpc = require('grpc');
var ems_grpc = require(__dirname + '/proto/ems_grpc_grpc_pb.js');
var ems_grpc_msgs = require(__dirname + '/proto/ems_grpc_pb.js');

/**
 * Module Exports
 * @public
 */

module.exports = xrGrpc;

/**
 * Module Source
 * @private
 */

/**
 * Constructor for connection library.
 * Need to implement parameter checking.
 * @param {string} address Address of IOS-XR gRPC server.
 * @param {int} port Port of IOS-XR gRPC server.
 * @param {object} rootCert Root SSL certificate. Needs clarification.
 * @param {object} metadata Object in associative array format containing username, password...
 * @param {object} options Object in associative array format containing options.
 */
function xrGrpc(address, port, rootCert, metadata, options) {
	if (!(this instanceof xrGrpc)) return new xrGrpc(address, port, rootCert, metadata, options);
	// Set params parameters
	this.params = {};
	this.params.address = address;
	this.params.port = port;
	this.params.credentials = rootCert ? grpc.credentials.createSsl(rootCert) : grpc.credentials.createInsecure();
	this.params.metadata = this.createMetadata(metadata);
	this.params.options = options;
	// Create client object
	this.xrGrpcClient = new ems_grpc.gRPCConfigOperClient(this.getAddress(), this.params.credentials);
	this.xrGrpcCliClient = new ems_grpc.gRPCExecClient(this.getAddress(), this.params.credentials);
}

/**
 * Return the client parameters
 */
xrGrpc.prototype.toString = function xrGrpcToString() {
	return JSON.stringify(this.params);
}

xrGrpc.prototype.getAddress = function() {
	return this.params.address + ':' + this.params.port.toString();
}

/**
 * Change the params metadata values.
 */
xrGrpc.prototype.setMetadata = function(metadata) {
	this.params.metadata = this.createMetadata(metadata);
}

/**
 * Create metadata for gRPC calls.
 * Accepts an "associative array" to translate into metadata.
 */
xrGrpc.prototype.createMetadata = function(metadata) {
	var meta = new grpc.Metadata();
	for (var key in metadata)
		meta.add(key, metadata[key]);
	return meta;
}

xrGrpc.prototype.getConfig = function() {

}

xrGrpc.prototype.mergeConfig = function() {

}

xrGrpc.prototype.deleteConfig = function() {

}

xrGrpc.prototype.replaceConfig = function() {

}

xrGrpc.prototype.cliConfig = function() {

}

xrGrpc.prototype.commitReplace = function() {

}

xrGrpc.prototype.commitConfig = function() {

}

xrGrpc.prototype.configDiscardChanges = function() {

}

xrGrpc.prototype.getOper = function() {

}

xrGrpc.prototype.showCmdTextOutput = function() {

}

xrGrpc.prototype.showCmdJSONOutput = function() {

}

<|endoftext|>


<commit_before>var Q = require("q");
var _ = require("lodash");
var path = require("path");
var tinylr = require('tiny-lr-fork');
var color = require('bash-color');

var Book = require("./book");
var Plugin = require("./plugin");
var Server = require("./utils/server");
var stringUtils = require("./utils/string");
var watch = require("./utils/watch");
var logger = require("./utils/logger");

var LOG_OPTION = {
	name: "log",
	description: "Minimum log level to display",
	values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(),
	defaults: "info"
};

var FORMAT_OPTION = {
	name: "format",
	description: "Format to build to",
	values: ["website", "json", "ebook"],
	defaults: "website"
};

module.exports = {
	Book: Book,
	LOG_LEVELS: logger.LEVELS,

	commands: _.flatten([
		{
			name: "build [book] [output]",
			description: "build a book",
			options: [
				FORMAT_OPTION,
				LOG_OPTION
			],
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();
				var output = args[1] || path.join(input, "_book");

				var book = new Book(input, _.extend({}, {
					'config': {
						'output': output
					},
					'logLevel': kwargs.log
				}));

				return book.parse()
				.then(function() {
					return book.generate(kwargs.format);
				})
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		},

		_.map(["pdf", "epub", "mobi"], function(ebookType) {
			return {
				name: ebookType+" [book] [output]",
				description: "build a book to "+ebookType,
				options: [
					LOG_OPTION
				],
				exec: function(args, kwargs) {
					var input = args[0] || process.cwd();
					var output = args[1];

					var book = new Book(input, _.extend({}, {
						'logLevel': Book.LOG_LEVELS[(kwargs.log).toUpperCase()]
					}));

					return book.parse()
					.then(function() {
						return book.generateFile(output, {
							ebookFormat: ebookType
						});
					})
					.then(function(){
						console.log("");
						console.log(color.green("Done, without error"));
					});
				}
			};
		}),

		{
			name: "serve [book]",
			description: "Build then serve a gitbook from a directory",
			options: [
				{
					name: "port",
					description: "Port for server to listen on",
					defaults: 4000
				},
				{
					name: "lrport",
					description: "Port for livereload server to listen on",
					defaults: 35729
				},
				{
					name: "watch",
					description: "Enable/disable file watcher",
					defaults: true
				},
				FORMAT_OPTION,
				LOG_OPTION
			],
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();
				var server = new Server();

				// Init livereload server
				var lrServer = tinylr({});
				var lrPath = undefined;

				var generate = function() {
			        if (server.isRunning()) console.log("Stopping server");

			        return server.stop()
			        .then(function() {
			        	var book = new Book(input, _.extend({}, {
							'config': {
								'defaultsPlugins': ["livereload"]
							},
							'logLevel': kwargs.log
						}));

						return book.parse()
						.then(function() {
							return book.generate(kwargs.format);
						})
						.thenResolve(book);
			        })
			        .then(function(book) {
			            console.log();
			            console.log('Starting server ...');
			            return server.start(book.options.output, kwargs.port)
			            .then(function() {
			                console.log('Serving book on http://localhost:'+kwargs.port);

			                if (lrPath) {
			                	// trigger livereload
			                	lrServer.changed({
			                		body: {
			                			files: [lrPath]
			                		}
			                	});
			                }

			                if (!kwargs.watch) return;

			                return watch(book.root)
			                .then(function(filepath) {
			                    // set livereload path
			                    lrPath = filepath;
			                    console.log("Restart after change in files");
			                    console.log('');
			                    return generate();
			                })
			            })
			        });
			    };

				return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
				.then(function() {
					console.log('Live reload server started on port:', kwargs.lrport);
					console.log('Press CTRL+C to quit ...');
    				console.log('')
					return generate();
				});
			}
		},

		{
			name: "install [book]",
			description: "install plugins dependencies",
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();

				var book = new Book(input);

				return book.config.load()
				.then(function() {
					return book.config.installPlugins({
						log: true
					});
				})
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		},

		{
			name: "init [directory]",
			description: "create files and folders based on contents of SUMMARY.md",
			exec: function(args, kwargs) {
				return Book.init(args[0] || process.cwd())
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		}
	])
};
<commit_msg>Fix ebook commands<commit_after>var Q = require("q");
var _ = require("lodash");
var path = require("path");
var tinylr = require('tiny-lr-fork');
var color = require('bash-color');

var Book = require("./book");
var Plugin = require("./plugin");
var Server = require("./utils/server");
var stringUtils = require("./utils/string");
var watch = require("./utils/watch");
var logger = require("./utils/logger");

var LOG_OPTION = {
	name: "log",
	description: "Minimum log level to display",
	values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(),
	defaults: "info"
};

var FORMAT_OPTION = {
	name: "format",
	description: "Format to build to",
	values: ["website", "json", "ebook"],
	defaults: "website"
};

module.exports = {
	Book: Book,
	LOG_LEVELS: logger.LEVELS,

	commands: _.flatten([
		{
			name: "build [book] [output]",
			description: "build a book",
			options: [
				FORMAT_OPTION,
				LOG_OPTION
			],
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();
				var output = args[1] || path.join(input, "_book");

				var book = new Book(input, _.extend({}, {
					'config': {
						'output': output
					},
					'logLevel': kwargs.log
				}));

				return book.parse()
				.then(function() {
					return book.generate(kwargs.format);
				})
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		},

		_.map(["pdf", "epub", "mobi"], function(ebookType) {
			return {
				name: ebookType+" [book] [output]",
				description: "build a book to "+ebookType,
				options: [
					LOG_OPTION
				],
				exec: function(args, kwargs) {
					var input = args[0] || process.cwd();
					var output = args[1];

					var book = new Book(input, _.extend({}, {
						'logLevel': kwargs.log
					}));

					return book.parse()
					.then(function() {
						return book.generateFile(output, {
							ebookFormat: ebookType
						});
					})
					.then(function(){
						console.log("");
						console.log(color.green("Done, without error"));
					});
				}
			};
		}),

		{
			name: "serve [book]",
			description: "Build then serve a gitbook from a directory",
			options: [
				{
					name: "port",
					description: "Port for server to listen on",
					defaults: 4000
				},
				{
					name: "lrport",
					description: "Port for livereload server to listen on",
					defaults: 35729
				},
				{
					name: "watch",
					description: "Enable/disable file watcher",
					defaults: true
				},
				FORMAT_OPTION,
				LOG_OPTION
			],
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();
				var server = new Server();

				// Init livereload server
				var lrServer = tinylr({});
				var lrPath = undefined;

				var generate = function() {
			        if (server.isRunning()) console.log("Stopping server");

			        return server.stop()
			        .then(function() {
			        	var book = new Book(input, _.extend({}, {
							'config': {
								'defaultsPlugins': ["livereload"]
							},
							'logLevel': kwargs.log
						}));

						return book.parse()
						.then(function() {
							return book.generate(kwargs.format);
						})
						.thenResolve(book);
			        })
			        .then(function(book) {
			            console.log();
			            console.log('Starting server ...');
			            return server.start(book.options.output, kwargs.port)
			            .then(function() {
			                console.log('Serving book on http://localhost:'+kwargs.port);

			                if (lrPath) {
			                	// trigger livereload
			                	lrServer.changed({
			                		body: {
			                			files: [lrPath]
			                		}
			                	});
			                }

			                if (!kwargs.watch) return;

			                return watch(book.root)
			                .then(function(filepath) {
			                    // set livereload path
			                    lrPath = filepath;
			                    console.log("Restart after change in files");
			                    console.log('');
			                    return generate();
			                })
			            })
			        });
			    };

				return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
				.then(function() {
					console.log('Live reload server started on port:', kwargs.lrport);
					console.log('Press CTRL+C to quit ...');
    				console.log('')
					return generate();
				});
			}
		},

		{
			name: "install [book]",
			description: "install plugins dependencies",
			exec: function(args, kwargs) {
				var input = args[0] || process.cwd();

				var book = new Book(input);

				return book.config.load()
				.then(function() {
					return book.config.installPlugins({
						log: true
					});
				})
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		},

		{
			name: "init [directory]",
			description: "create files and folders based on contents of SUMMARY.md",
			exec: function(args, kwargs) {
				return Book.init(args[0] || process.cwd())
				.then(function(){
					console.log("");
					console.log(color.green("Done, without error"));
				});
			}
		}
	])
};
<|endoftext|>


<commit_before>/*jshint strict:true node:true es5:true onevar:true laxcomma:true laxbreak:true eqeqeq:true immed:true latedef:true*/
(function () {
  "use strict";

  var xml2js = require('xml2js')
    , path = require('path')
    , parser = new xml2js.Parser()
    , posts = {}
    , postsArr = []
    , untitledCount = 0
    ;

  function defaultPermalinkify(link) {
    // get everything except the domain
    return link.$.href.replace(/https?:\/\/[^\/]*/, '');
  }

  function otherPermalinkify(link) {
    // get nothing except the filename
    return link.$.href.split('/').pop();
  }

  function parse(data, eachPost, opts) {
    opts = opts || {};
    var prefix = opts.prefix || ''
      , permalinkify = opts.permalinkify || defaultPermalinkify
      ;

    function templatePosts() {
      postsArr.forEach(function (post) {
        var contents
          , allSubcontents = ''
          , subcontents = []
          , yaml = []
          ;

        post.comments.forEach(function (comment) {
          subcontents.push(
              '
'
            , '
'
            , '  '
            , '
'
            , '    ' + (comment.name || 'anonymous')
            , '
'
            , '  '
            , '
'
            , '    ' + comment.published.toISOString()
            , '
'
            , '
'
          );

          if (comment.title.substr(0, 10) !== comment.content.substr(0, 10)) {
            subcontents.push(
                '
'
              , '    ' + comment.title
              , '
'
            );
          }

          subcontents.push(
              '
'
            , '    ' + comment.content
            , '
'
            , '
'
            , '
'
          );
        });

        yaml = [
            'title: "' + post.title.replace(/"/g, '\\"') + '"'
          , 'layout: "' + post.postType + '"'
          , 'permalink: "' + path.normalize(prefix + '/' + post.permalink).replace(/\\+/g, '/') + '"'
          , 'uuid: "' + post.uuid + '"'
          , 'guid: "' + post.guid + '"'
          , 'date: "' + post.published.toISOString().replace('T', ' ').replace(/\..+/g,'') + '"'
          ];

        if ( post.published != post.updated )
          yaml.push( 'updated: "' + post.updated.toISOString().replace('T', ' ').replace(/\..+/g,'') + '"' );

        if ( post.thumbnail )
          yaml.push( 'thumbnail: "' + post.thumbnail + '"' );

        if ( post.link )
          yaml.push( 'link: "' + post.link + '"' );

        yaml.push(
            'description: '
        );

        yaml.push(
            'blogger:'
          , '    siteid: "' + post.siteid + '"'
          , '    postid: "' + post.uuid + '"'
        );

        if (post.commentcount)
        	yaml.push( '    comments: "' + post.commentcount + '"' );

        if ( typeof post.category != 'undefined' )
        	yaml.push( 'categories: [' + post.category.join(', ') + ']' );
        else
        	yaml.push( 'categories: ' );

        yaml.push(
            'author: '
          , '    name: "' + post.authorname + '"'
          , '    url: "' + post.authoruri + '?rel=author"'
          , '    image: "' + post.authorimage + '"'
        );

        if (post.draft)
          yaml.push( 'published: "false"' );

        if (post.location) {
        	yaml.push( 'location:' );
        	if ( typeof post.locationName != 'undefined' )
        		yaml.push( '    name: "' + post.locationName + '"' );
        	yaml.push( '    latitude: "' + post.locationPoint[0] + '"' );
        	yaml.push( '    longitude: "' + post.locationPoint[1] + '"' );
        	if ( typeof post.locationBox != 'undefined' )
        		yaml.push( '    box: [' + post.locationBox.join(', ') + ']' );
        }

        contents = ['---'];

        contents = contents.concat(yaml);

        contents.push(
            '---'
          , ''
          , '{% raw %}'
          , '
'
          , post.content
          , '
'
        );

        if ( subcontents.length > 0 ) {
          contents.push(
          	  '
'
          	, subcontents.join('\n')
          	, '
'
          );
        }

        contents.push('{% endraw %}');

        eachPost(post.permalink, contents.join('\n'));
      });
    }

    function translateFile(err, obj) {
      if (err) { throw err; }
      obj.feed.entry.forEach(function (entry) {
        var uuid
          , post = { comments: [] }
          , comment = {}
          ;

        function getUuid() {
          uuid = entry.id[0].split(':').pop().replace(/.*post-(.*)/, '$1');
        }

        function getBasics(obj) {
          obj.guid = entry.id[0];
          obj.published = new Date(entry.published[0]);
          obj.updated = new Date(entry.updated[0]);
          obj.title = entry.title[0]._;
          obj.content = entry.content[0]._;
          obj.commentcount = entry['thr:total'] || false;
          obj.authorname = entry.author[0].name;
          obj.authoruri = entry.author[0].uri;
          obj.authorimage = entry.author[0]['gd:image'][0].$['src'];
          obj.postType = 'post';
          obj.category = [];
          obj.siteid = entry.id[0].split(':').pop().replace(/blog-([0-9]+)\.post-.*/, '$1');
          obj.draft = ( typeof entry['app:control'] != 'undefined'  &&  typeof entry['app:control'][0] != 'undefined'  && entry['app:control'][0]['app:draft'] == 'yes' );

          obj.thumbnail = false;
          if ( typeof entry['media:thumbnail'] != 'undefined' ) {
	          obj.thumbnail = entry['media:thumbnail'][0].$['url'];
	        }

          obj.link = false;
        	entry['link'].forEach(function (link) {
        		if ( link.$['rel'] == 'related' )
	          	obj.link = link.$['href'];
        	});

          if ( typeof entry['georss:point'] != 'undefined' ) {
          	obj.location = true;
          	obj.locationPoint = entry['georss:point'][0].split(' ');
          	if ( typeof entry['georss:featurename'] != 'undefined' )
          		obj.locationName = entry['georss:featurename'][0];
          	if ( typeof entry['georss:box'] != 'undefined' )
          		obj.locationBox = entry['georss:box'][0].split(' ');
          }

          if ( typeof entry['category'] != 'undefined' ) {
          	obj.category = [];
          	entry['category'].forEach(function (category) {
          		if ( category.$['scheme'] == 'http://www.blogger.com/atom/ns#' )
	          		obj.category.push( category.$['term'] );
          		if ( category.$['scheme'] == 'http://schemas.google.com/g/2005#kind' )
	          		obj.postType = category.$['term'].replace( 'http://schemas.google.com/blogger/2008/kind#', '' );
          	});
          	if ( obj.category.length == 0 )
          		delete obj.category;
          }

        }

        if (/kind#post/.test(entry.category[0].$.term)) {
          getUuid();
          getBasics(post);

          post.uuid = uuid;
          entry.link.forEach(function (link) {
            if ('alternate' === link.$.rel) {
              post.permalink = permalinkify(link);
            }
          });

          if (!post.permalink) {
            if (!post.title) {
              if (!post.content) {
                // console.log(entry);
                // empty unpublished draft post
              }
              post.title = 'untitled ' + untitledCount.toString();
              untitledCount += 1;
              // unpublished draft post
              return;
            }
            // permalink is optional
            post.permalink = post.title
              .replace(/\W/g, '-')
              .replace(/-+/g, '-')
              .replace(/-$/, '')
              + '.html'
              ;
          }

          if (!post.title) {
            post.title = (post.permalink).split('/').pop().replace(/\.[^\.]*$/g, '');
          }

          posts[uuid] = post;
          postsArr.push(post);
        }

        if (/kind#comment/.test(entry.category[0].$.term) && entry['thr:in-reply-to']) {
          getUuid();
          comment.uuid = uuid;
          uuid = entry['thr:in-reply-to'][0].$.ref.replace(/.*post-(.*)/, '$1');
          if (entry.author) {
            if (entry.author[0].name) {
              comment.name = entry.author[0].name[0];
            }
            if (entry.author[0].uri) {
              comment.uri = entry.author[0].uri[0];
            }
          }
          post = posts[uuid];
          post.comments.push(comment);
          getBasics(comment);
        }
      });

      templatePosts();
    }

    parser.parseString(data, translateFile);
  }

  module.exports.parse = parse;
}());
<commit_msg>Add opts.skipComments to ignore comments<commit_after>/*jshint strict:true node:true es5:true onevar:true laxcomma:true laxbreak:true eqeqeq:true immed:true latedef:true*/
(function () {
  "use strict";

  var xml2js = require('xml2js')
    , path = require('path')
    , parser = new xml2js.Parser()
    , posts = {}
    , postsArr = []
    , untitledCount = 0
    ;

  function defaultPermalinkify(link) {
    // get everything except the domain
    return link.$.href.replace(/https?:\/\/[^\/]*/, '');
  }

  function otherPermalinkify(link) {
    // get nothing except the filename
    return link.$.href.split('/').pop();
  }

  function parse(data, eachPost, opts) {
    opts = opts || {};
    var prefix = opts.prefix || ''
      , permalinkify = opts.permalinkify || defaultPermalinkify
      ;

    function templatePosts() {
      postsArr.forEach(function (post) {
        var contents
          , allSubcontents = ''
          , subcontents = []
          , yaml = []
          ;

        if (!opts.skipComments) {
          post.comments.forEach(function (comment) {
            subcontents.push(
                '
'
              , '
'
              , '  '
              , '
'
              , '    ' + (comment.name || 'anonymous')
              , '
'
              , '  '
              , '
'
              , '    ' + comment.published.toISOString()
              , '
'
              , '
'
            );

            if (comment.title.substr(0, 10) !== comment.content.substr(0, 10)) {
              subcontents.push(
                  '
'
                , '    ' + comment.title
                , '
'
              );
            }

            subcontents.push(
                '
'
              , '    ' + comment.content
              , '
'
              , '
'
              , '
'
            );
          });
        }

        yaml = [
            'title: "' + post.title.replace(/"/g, '\\"') + '"'
          , 'layout: "' + post.postType + '"'
          , 'permalink: "' + path.normalize(prefix + '/' + post.permalink).replace(/\\+/g, '/') + '"'
          , 'uuid: "' + post.uuid + '"'
          , 'guid: "' + post.guid + '"'
          , 'date: "' + post.published.toISOString().replace('T', ' ').replace(/\..+/g,'') + '"'
          ];

        if ( post.published != post.updated )
          yaml.push( 'updated: "' + post.updated.toISOString().replace('T', ' ').replace(/\..+/g,'') + '"' );

        if ( post.thumbnail )
          yaml.push( 'thumbnail: "' + post.thumbnail + '"' );

        if ( post.link )
          yaml.push( 'link: "' + post.link + '"' );

        yaml.push(
            'description: '
        );

        yaml.push(
            'blogger:'
          , '    siteid: "' + post.siteid + '"'
          , '    postid: "' + post.uuid + '"'
        );

        if (post.commentcount)
        	yaml.push( '    comments: "' + post.commentcount + '"' );

        if ( typeof post.category != 'undefined' )
        	yaml.push( 'categories: [' + post.category.join(', ') + ']' );
        else
        	yaml.push( 'categories: ' );

        yaml.push(
            'author: '
          , '    name: "' + post.authorname + '"'
          , '    url: "' + post.authoruri + '?rel=author"'
          , '    image: "' + post.authorimage + '"'
        );

        if (post.draft)
          yaml.push( 'published: "false"' );

        if (post.location) {
        	yaml.push( 'location:' );
        	if ( typeof post.locationName != 'undefined' )
        		yaml.push( '    name: "' + post.locationName + '"' );
        	yaml.push( '    latitude: "' + post.locationPoint[0] + '"' );
        	yaml.push( '    longitude: "' + post.locationPoint[1] + '"' );
        	if ( typeof post.locationBox != 'undefined' )
        		yaml.push( '    box: [' + post.locationBox.join(', ') + ']' );
        }

        contents = ['---'];

        contents = contents.concat(yaml);

        contents.push(
            '---'
          , ''
          , '{% raw %}'
          , '
'
          , post.content
          , '
'
        );

        if ( subcontents.length > 0 ) {
          contents.push(
          	  '
'
          	, subcontents.join('\n')
          	, '
'
          );
        }

        contents.push('{% endraw %}');

        eachPost(post.permalink, contents.join('\n'));
      });
    }

    function translateFile(err, obj) {
      if (err) { throw err; }
      obj.feed.entry.forEach(function (entry) {
        var uuid
          , post = { comments: [] }
          , comment = {}
          ;

        function getUuid() {
          uuid = entry.id[0].split(':').pop().replace(/.*post-(.*)/, '$1');
        }

        function getBasics(obj) {
          obj.guid = entry.id[0];
          obj.published = new Date(entry.published[0]);
          obj.updated = new Date(entry.updated[0]);
          obj.title = entry.title[0]._;
          obj.content = entry.content[0]._;
          obj.commentcount = entry['thr:total'] || false;
          obj.authorname = entry.author[0].name;
          obj.authoruri = entry.author[0].uri;
          obj.authorimage = entry.author[0]['gd:image'][0].$['src'];
          obj.postType = 'post';
          obj.category = [];
          obj.siteid = entry.id[0].split(':').pop().replace(/blog-([0-9]+)\.post-.*/, '$1');
          obj.draft = ( typeof entry['app:control'] != 'undefined'  &&  typeof entry['app:control'][0] != 'undefined'  && entry['app:control'][0]['app:draft'] == 'yes' );

          obj.thumbnail = false;
          if ( typeof entry['media:thumbnail'] != 'undefined' ) {
	          obj.thumbnail = entry['media:thumbnail'][0].$['url'];
	        }

          obj.link = false;
        	entry['link'].forEach(function (link) {
        		if ( link.$['rel'] == 'related' )
	          	obj.link = link.$['href'];
        	});

          if ( typeof entry['georss:point'] != 'undefined' ) {
          	obj.location = true;
          	obj.locationPoint = entry['georss:point'][0].split(' ');
          	if ( typeof entry['georss:featurename'] != 'undefined' )
          		obj.locationName = entry['georss:featurename'][0];
          	if ( typeof entry['georss:box'] != 'undefined' )
          		obj.locationBox = entry['georss:box'][0].split(' ');
          }

          if ( typeof entry['category'] != 'undefined' ) {
          	obj.category = [];
          	entry['category'].forEach(function (category) {
          		if ( category.$['scheme'] == 'http://www.blogger.com/atom/ns#' )
	          		obj.category.push( category.$['term'] );
          		if ( category.$['scheme'] == 'http://schemas.google.com/g/2005#kind' )
	          		obj.postType = category.$['term'].replace( 'http://schemas.google.com/blogger/2008/kind#', '' );
          	});
          	if ( obj.category.length == 0 )
          		delete obj.category;
          }

        }

        if (/kind#post/.test(entry.category[0].$.term)) {
          getUuid();
          getBasics(post);

          post.uuid = uuid;
          entry.link.forEach(function (link) {
            if ('alternate' === link.$.rel) {
              post.permalink = permalinkify(link);
            }
          });

          if (!post.permalink) {
            if (!post.title) {
              if (!post.content) {
                // console.log(entry);
                // empty unpublished draft post
              }
              post.title = 'untitled ' + untitledCount.toString();
              untitledCount += 1;
              // unpublished draft post
              return;
            }
            // permalink is optional
            post.permalink = post.title
              .replace(/\W/g, '-')
              .replace(/-+/g, '-')
              .replace(/-$/, '')
              + '.html'
              ;
          }

          if (!post.title) {
            post.title = (post.permalink).split('/').pop().replace(/\.[^\.]*$/g, '');
          }

          posts[uuid] = post;
          postsArr.push(post);
        }

        if (/kind#comment/.test(entry.category[0].$.term) && entry['thr:in-reply-to']) {
          getUuid();
          comment.uuid = uuid;
          uuid = entry['thr:in-reply-to'][0].$.ref.replace(/.*post-(.*)/, '$1');
          if (entry.author) {
            if (entry.author[0].name) {
              comment.name = entry.author[0].name[0];
            }
            if (entry.author[0].uri) {
              comment.uri = entry.author[0].uri[0];
            }
          }
          post = posts[uuid];
          post.comments.push(comment);
          getBasics(comment);
        }
      });

      templatePosts();
    }

    parser.parseString(data, translateFile);
  }

  module.exports.parse = parse;
}());
<|endoftext|>