<commit_before>// Load modules

var Fs = require('fs');
var Path = require('path');
var Escape = require('./escape');

// Declare internals

var internals = {};

// Clone object or array

exports.clone = function (obj, seen) {

    if (typeof obj !== 'object' ||
        obj === null) {

        return obj;
    }

    seen = seen || { orig: [], copy: [] };

    var lookup = seen.orig.indexOf(obj);
    if (lookup !== -1) {
        return seen.copy[lookup];
    }

    if (obj instanceof Buffer) {
        return new Buffer(obj);
    }
    else if (obj instanceof Date) {
        return new Date(obj.getTime());
    }
    else if (obj instanceof RegExp) {
        var flags = '' + (obj.global ? 'g' : '') + (obj.ignoreCase ? 'i' : '') + (obj.multiline ? 'm' : '');
        return new RegExp(obj.source, flags);
    }

    var newObj = (obj instanceof Array ? [] : {});

    seen.orig.push(obj);
    seen.copy.push(newObj);

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            newObj[i] = exports.clone(obj[i], seen);
        }
    }

    return newObj;
};

// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied

exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {

    exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');

    if (!source) {
        return target;
    }

    if (source instanceof Array) {
        exports.assert(target instanceof Array, 'Cannot merge array onto an object');
        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
            target.length = 0;                                                          // Must not change target assignment
        }

        for (var i = 0, il = source.length; i < il; ++i) {
            target.push(source[i]);
        }

        return target;
    }

    var keys = Object.keys(source);
    for (var k = 0, kl = keys.length; k < kl; ++k) {
        var key = keys[k];
        var value = source[key];
        if (value &&
            typeof value === 'object') {

            if (!target[key] ||
                typeof target[key] !== 'object' ||
                value instanceof Date ||
                value instanceof Buffer ||
                value instanceof RegExp) {

                target[key] = exports.clone(value);
            }
            else {
                exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
            }
        }
        else {
            if (value !== null && value !== undefined) {            // Explicit to preserve empty strings
                target[key] = value;
            }
            else if (isNullOverride !== false) {                    // Defaults to true
                target[key] = value;
            }
        }
    }

    return target;
};

// Apply options to a copy of the defaults

exports.applyToDefaults = function (defaults, options) {

    exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');

    if (!options) {                                                 // If no options, return null
        return null;
    }

    var copy = exports.clone(defaults);

    if (options === true) {                                         // If options is set to true, use defaults
        return copy;
    }

    return exports.merge(copy, options, false, false);
};

// Remove duplicate items from array

exports.unique = function (array, key) {

    var index = {};
    var result = [];

    for (var i = 0, il = array.length; i < il; ++i) {
        var id = (key ? array[i][key] : array[i]);
        if (index[id] !== true) {

            result.push(array[i]);
            index[id] = true;
        }
    }

    return result;
};

// Convert array into object

exports.mapToObject = function (array, key) {

    if (!array) {
        return null;
    }

    var obj = {};
    for (var i = 0, il = array.length; i < il; ++i) {
        if (key) {
            if (array[i][key]) {
                obj[array[i][key]] = true;
            }
        }
        else {
            obj[array[i]] = true;
        }
    }

    return obj;
};

// Find the common unique items in two arrays

exports.intersect = function (array1, array2, justFirst) {

    if (!array1 || !array2) {
        return [];
    }

    var common = [];
    var hash = (array1 instanceof Array ? exports.mapToObject(array1) : array1);
    var found = {};
    for (var i = 0, il = array2.length; i < il; ++i) {
        if (hash[array2[i]] && !found[array2[i]]) {
            if (justFirst) {
                return array2[i];
            }

            common.push(array2[i]);
            found[array2[i]] = true;
        }
    }

    return (justFirst ? null : common);
};

// Find which keys are present

exports.matchKeys = function (obj, keys) {

    var matched = [];
    for (var i = 0, il = keys.length; i < il; ++i) {
        if (obj.hasOwnProperty(keys[i])) {
            matched.push(keys[i]);
        }
    }
    return matched;
};

// Flatten array

exports.flatten = function (array, target) {

    var result = target || [];

    for (var i = 0, il = array.length; i < il; ++i) {
        if (Array.isArray(array[i])) {
            exports.flatten(array[i], result);
        }
        else {
            result.push(array[i]);
        }
    }

    return result;
};

// Remove keys

exports.removeKeys = function (object, keys) {

    for (var i = 0, il = keys.length; i < il; i++) {
        delete object[keys[i]];
    }
};

// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])

exports.reach = function (obj, chain, separator) {

    var path = chain.split(separator || '.');
    var ref = obj;
    for (var i = 0, il = path.length; i < il; ++i) {
        if (ref) {
            ref = ref[path[i]];
        }
    }

    return ref;
};

// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors

exports.inheritAsync = function (self, obj, keys) {

    keys = keys || null;

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (keys instanceof Array &&
                keys.indexOf(i) < 0) {

                continue;
            }

            self.prototype[i] = (function (fn) {

                return function (next) {

                    var result = null;
                    try {
                        result = fn();
                    }
                    catch (err) {
                        return next(err);
                    }

                    return next(null, result);
                };
            })(obj[i]);
        }
    }
};

exports.formatStack = function (stack) {

    var trace = [];
    for (var i = 0, il = stack.length; i < il; ++i) {
        var item = stack[i];
        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
    }

    return trace;
};

exports.formatTrace = function (trace) {

    var display = [];

    for (var i = 0, il = trace.length; i < il; ++i) {
        var row = trace[i];
        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
    }

    return display;
};

exports.callStack = function (slice) {

    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

    var v8 = Error.prepareStackTrace;
    Error.prepareStackTrace = function (err, stack) {

        return stack;
    };

    var capture = {};
    Error.captureStackTrace(capture, arguments.callee);
    var stack = capture.stack;

    Error.prepareStackTrace = v8;

    var trace = exports.formatStack(stack);

    if (slice) {
        return trace.slice(slice);
    }

    return trace;
};

exports.displayStack = function (slice) {

    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);

    return exports.formatTrace(trace);
};

exports.abortThrow = false;

exports.abort = function (message, hideStack) {

    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
        throw new Error(message || 'Unknown error');
    }

    var stack = '';
    if (!hideStack) {
        stack = exports.displayStack(1).join('\n\t');
    }
    console.log('ABORT: ' + message + '\n\t' + stack);
    process.exit(1);
};

exports.assert = function (condition /*, msg1, msg2, msg3 */) {

    if (condition) {
        return;
    }

    var msgs = Array.prototype.slice.call(arguments, 1);
    msgs = msgs.map(function (msg) {

        return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : JSON.stringify(msg);
    });
    throw new Error(msgs.join(' ') || 'Unknown error');
};

exports.loadDirModules = function (path, excludeFiles, target) {      // target(filename, name, capName)

    var exclude = {};
    for (var i = 0, il = excludeFiles.length; i < il; ++i) {
        exclude[excludeFiles[i] + '.js'] = true;
    }

    var files = Fs.readdirSync(path);
    for (i = 0, il = files.length; i < il; ++i) {
        var filename = files[i];
        if (/\.js$/.test(filename) &&
            !exclude[filename]) {

            var name = filename.substr(0, filename.lastIndexOf('.'));
            var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();

            if (typeof target !== 'function') {
                target[capName] = require(path + '/' + name);
            }
            else {
                target(path + '/' + name, name, capName);
            }
        }
    }
};

exports.rename = function (obj, from, to) {

    obj[to] = obj[from];
    delete obj[from];
};

exports.Timer = function () {

    this.reset();
};

exports.Timer.prototype.reset = function () {

    this.ts = Date.now();
};

exports.Timer.prototype.elapsed = function () {

    return Date.now() - this.ts;
};

// Load and parse package.json process root or given directory

exports.loadPackage = function (dir) {

    var result = {};
    var filepath = Path.normalize((dir || process.env.PWD) + '/package.json');
    if (Fs.existsSync(filepath)) {
        try {
            result = JSON.parse(Fs.readFileSync(filepath));
        }
        catch (e) { }
    }

    return result;
};

// Escape string for Regex construction

exports.escapeRegex = function (string) {

    // Escape ^$.*+-?=!:|\/()[]{},
    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
};

// Return an error as first argument of a callback

exports.toss = function (condition /*, [message], next */) {

    var message = (arguments.length === 3 ? arguments[1] : '');
    var next = (arguments.length === 3 ? arguments[2] : arguments[1]);

    var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));

    if (condition instanceof Error ||
        !condition) {

        return next(err);
    }
};

// Base64url (RFC 4648) encode

exports.base64urlEncode = function (value) {

    return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
};

// Base64url (RFC 4648) decode

exports.base64urlDecode = function (encoded) {

    if (encoded &&
        !encoded.match(/^[\w\-]*$/)) {

        return new Error('Invalid character');
    }

    try {
        return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
    }
    catch (err) {
        return err;
    }
};

// Escape attribute value for use in HTTP header

exports.escapeHeaderAttribute = function (attribute) {

    // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "

    exports.assert(attribute.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/), 'Bad attribute value (' + attribute + ')');

    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');                             // Escape quotes and slash
};

exports.escapeHtml = function (string) {

    return Escape.escapeHtml(string);
};

exports.escapeJavaScript = function (string) {

    return Escape.escapeJavaScript(string);
};

/*
var event = {
    timestamp: now.getTime(),
    tags: ['tag'],
    data: { some: 'data' }
};
*/

exports.consoleFunc = console.log;

exports.printEvent = function (event) {

    var pad = function (value) {

        return (value < 10 ? '0' : '') + value;
    };

    var now = new Date(event.timestamp);
    var timestring = (now.getYear() - 100).toString() +
        pad(now.getMonth() + 1) +
        pad(now.getDate()) +
        '/' +
        pad(now.getHours()) +
        pad(now.getMinutes()) +
        pad(now.getSeconds()) +
        '.' +
        now.getMilliseconds();

    var data = event.data;
    if (typeof event.data !== 'string') {
        try {
            data = JSON.stringify(event.data);
        }
        catch (e) {
            data = 'JSON Error: ' + e.message;
        }
    }

    var output = timestring + ', ' + event.tags[0] + ', ' + data;
    exports.consoleFunc(output);
};

exports.nextTick = function (callback) {

    return function () {

        var args = arguments;
        process.nextTick(function () {

            callback.apply(null, args);
        });
    };
};

exports.readStream = function (stream, callback) {

    var result = '';

    stream.on('readable', function () {

        var read = stream.read();
        if (read) {
            result += read.toString();
        }
    });

    stream.once('end', function () {

        callback(result);
    });
};
<commit_msg>Closes #35<commit_after>// Load modules

var Fs = require('fs');
var Path = require('path');
var Escape = require('./escape');

// Declare internals

var internals = {};

// Clone object or array

exports.clone = function (obj, seen) {

    if (typeof obj !== 'object' ||
        obj === null) {

        return obj;
    }

    seen = seen || { orig: [], copy: [] };

    var lookup = seen.orig.indexOf(obj);
    if (lookup !== -1) {
        return seen.copy[lookup];
    }

    if (obj instanceof Buffer) {
        return new Buffer(obj);
    }
    else if (obj instanceof Date) {
        return new Date(obj.getTime());
    }
    else if (obj instanceof RegExp) {
        var flags = '' + (obj.global ? 'g' : '') + (obj.ignoreCase ? 'i' : '') + (obj.multiline ? 'm' : '');
        return new RegExp(obj.source, flags);
    }

    var newObj = (obj instanceof Array ? [] : {});

    seen.orig.push(obj);
    seen.copy.push(newObj);

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            newObj[i] = exports.clone(obj[i], seen);
        }
    }

    return newObj;
};

// Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied

exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {

    exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
    exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');

    if (!source) {
        return target;
    }

    if (source instanceof Array) {
        exports.assert(target instanceof Array, 'Cannot merge array onto an object');
        if (isMergeArrays === false) {                                                  // isMergeArrays defaults to true
            target.length = 0;                                                          // Must not change target assignment
        }

        for (var i = 0, il = source.length; i < il; ++i) {
            target.push(source[i]);
        }

        return target;
    }

    var keys = Object.keys(source);
    for (var k = 0, kl = keys.length; k < kl; ++k) {
        var key = keys[k];
        var value = source[key];
        if (value &&
            typeof value === 'object') {

            if (!target[key] ||
                typeof target[key] !== 'object' ||
                value instanceof Date ||
                value instanceof Buffer ||
                value instanceof RegExp) {

                target[key] = exports.clone(value);
            }
            else {
                exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
            }
        }
        else {
            if (value !== null && value !== undefined) {            // Explicit to preserve empty strings
                target[key] = value;
            }
            else if (isNullOverride !== false) {                    // Defaults to true
                target[key] = value;
            }
        }
    }

    return target;
};

// Apply options to a copy of the defaults

exports.applyToDefaults = function (defaults, options) {

    exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
    exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');

    if (!options) {                                                 // If no options, return null
        return null;
    }

    var copy = exports.clone(defaults);

    if (options === true) {                                         // If options is set to true, use defaults
        return copy;
    }

    return exports.merge(copy, options, false, false);
};

// Remove duplicate items from array

exports.unique = function (array, key) {

    var index = {};
    var result = [];

    for (var i = 0, il = array.length; i < il; ++i) {
        var id = (key ? array[i][key] : array[i]);
        if (index[id] !== true) {

            result.push(array[i]);
            index[id] = true;
        }
    }

    return result;
};

// Convert array into object

exports.mapToObject = function (array, key) {

    if (!array) {
        return null;
    }

    var obj = {};
    for (var i = 0, il = array.length; i < il; ++i) {
        if (key) {
            if (array[i][key]) {
                obj[array[i][key]] = true;
            }
        }
        else {
            obj[array[i]] = true;
        }
    }

    return obj;
};

// Find the common unique items in two arrays

exports.intersect = function (array1, array2, justFirst) {

    if (!array1 || !array2) {
        return [];
    }

    var common = [];
    var hash = (array1 instanceof Array ? exports.mapToObject(array1) : array1);
    var found = {};
    for (var i = 0, il = array2.length; i < il; ++i) {
        if (hash[array2[i]] && !found[array2[i]]) {
            if (justFirst) {
                return array2[i];
            }

            common.push(array2[i]);
            found[array2[i]] = true;
        }
    }

    return (justFirst ? null : common);
};

// Find which keys are present

exports.matchKeys = function (obj, keys) {

    var matched = [];
    for (var i = 0, il = keys.length; i < il; ++i) {
        if (obj.hasOwnProperty(keys[i])) {
            matched.push(keys[i]);
        }
    }
    return matched;
};

// Flatten array

exports.flatten = function (array, target) {

    var result = target || [];

    for (var i = 0, il = array.length; i < il; ++i) {
        if (Array.isArray(array[i])) {
            exports.flatten(array[i], result);
        }
        else {
            result.push(array[i]);
        }
    }

    return result;
};

// Remove keys

exports.removeKeys = function (object, keys) {

    for (var i = 0, il = keys.length; i < il; i++) {
        delete object[keys[i]];
    }
};

// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])

exports.reach = function (obj, chain, separator) {

    var path = chain.split(separator || '.');
    var ref = obj;
    for (var i = 0, il = path.length; i < il; ++i) {
        if (ref) {
            ref = ref[path[i]];
        }
    }

    return ref;
};

// Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors

exports.inheritAsync = function (self, obj, keys) {

    keys = keys || null;

    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            if (keys instanceof Array &&
                keys.indexOf(i) < 0) {

                continue;
            }

            self.prototype[i] = (function (fn) {

                return function (next) {

                    var result = null;
                    try {
                        result = fn();
                    }
                    catch (err) {
                        return next(err);
                    }

                    return next(null, result);
                };
            })(obj[i]);
        }
    }
};

exports.formatStack = function (stack) {

    var trace = [];
    for (var i = 0, il = stack.length; i < il; ++i) {
        var item = stack[i];
        trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
    }

    return trace;
};

exports.formatTrace = function (trace) {

    var display = [];

    for (var i = 0, il = trace.length; i < il; ++i) {
        var row = trace[i];
        display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
    }

    return display;
};

exports.callStack = function (slice) {

    // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

    var v8 = Error.prepareStackTrace;
    Error.prepareStackTrace = function (err, stack) {

        return stack;
    };

    var capture = {};
    Error.captureStackTrace(capture, arguments.callee);
    var stack = capture.stack;

    Error.prepareStackTrace = v8;

    var trace = exports.formatStack(stack);

    if (slice) {
        return trace.slice(slice);
    }

    return trace;
};

exports.displayStack = function (slice) {

    var trace = exports.callStack(slice === undefined ? 1 : slice + 1);

    return exports.formatTrace(trace);
};

exports.abortThrow = false;

exports.abort = function (message, hideStack) {

    if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
        throw new Error(message || 'Unknown error');
    }

    var stack = '';
    if (!hideStack) {
        stack = exports.displayStack(1).join('\n\t');
    }
    console.log('ABORT: ' + message + '\n\t' + stack);
    process.exit(1);
};

exports.assert = function (condition /*, msg1, msg2, msg3 */) {

    if (condition) {
        return;
    }

    var msgs = Array.prototype.slice.call(arguments, 1);
    msgs = msgs.map(function (msg) {

        return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : JSON.stringify(msg);
    });
    throw new Error(msgs.join(' ') || 'Unknown error');
};

exports.loadDirModules = function (path, excludeFiles, target) {      // target(filename, name, capName)

    var exclude = {};
    for (var i = 0, il = excludeFiles.length; i < il; ++i) {
        exclude[excludeFiles[i] + '.js'] = true;
    }

    var files = Fs.readdirSync(path);
    for (i = 0, il = files.length; i < il; ++i) {
        var filename = files[i];
        if (/\.js$/.test(filename) &&
            !exclude[filename]) {

            var name = filename.substr(0, filename.lastIndexOf('.'));
            var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();

            if (typeof target !== 'function') {
                target[capName] = require(path + '/' + name);
            }
            else {
                target(path + '/' + name, name, capName);
            }
        }
    }
};

exports.rename = function (obj, from, to) {

    obj[to] = obj[from];
    delete obj[from];
};

exports.Timer = function () {

    this.reset();
};

exports.Timer.prototype.reset = function () {

    this.ts = Date.now();
};

exports.Timer.prototype.elapsed = function () {

    return Date.now() - this.ts;
};

// Load and parse package.json process root or given directory

exports.loadPackage = function (dir) {

    var result = {};
    var filepath = Path.normalize((dir || process.env.PWD || process.cwd()) + '/package.json');
    if (Fs.existsSync(filepath)) {
        try {
            result = JSON.parse(Fs.readFileSync(filepath));
        }
        catch (e) { }
    }

    return result;
};

// Escape string for Regex construction

exports.escapeRegex = function (string) {

    // Escape ^$.*+-?=!:|\/()[]{},
    return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
};

// Return an error as first argument of a callback

exports.toss = function (condition /*, [message], next */) {

    var message = (arguments.length === 3 ? arguments[1] : '');
    var next = (arguments.length === 3 ? arguments[2] : arguments[1]);

    var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));

    if (condition instanceof Error ||
        !condition) {

        return next(err);
    }
};

// Base64url (RFC 4648) encode

exports.base64urlEncode = function (value) {

    return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
};

// Base64url (RFC 4648) decode

exports.base64urlDecode = function (encoded) {

    if (encoded &&
        !encoded.match(/^[\w\-]*$/)) {

        return new Error('Invalid character');
    }

    try {
        return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
    }
    catch (err) {
        return err;
    }
};

// Escape attribute value for use in HTTP header

exports.escapeHeaderAttribute = function (attribute) {

    // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "

    exports.assert(attribute.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/), 'Bad attribute value (' + attribute + ')');

    return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"');                             // Escape quotes and slash
};

exports.escapeHtml = function (string) {

    return Escape.escapeHtml(string);
};

exports.escapeJavaScript = function (string) {

    return Escape.escapeJavaScript(string);
};

/*
var event = {
    timestamp: now.getTime(),
    tags: ['tag'],
    data: { some: 'data' }
};
*/

exports.consoleFunc = console.log;

exports.printEvent = function (event) {

    var pad = function (value) {

        return (value < 10 ? '0' : '') + value;
    };

    var now = new Date(event.timestamp);
    var timestring = (now.getYear() - 100).toString() +
        pad(now.getMonth() + 1) +
        pad(now.getDate()) +
        '/' +
        pad(now.getHours()) +
        pad(now.getMinutes()) +
        pad(now.getSeconds()) +
        '.' +
        now.getMilliseconds();

    var data = event.data;
    if (typeof event.data !== 'string') {
        try {
            data = JSON.stringify(event.data);
        }
        catch (e) {
            data = 'JSON Error: ' + e.message;
        }
    }

    var output = timestring + ', ' + event.tags[0] + ', ' + data;
    exports.consoleFunc(output);
};

exports.nextTick = function (callback) {

    return function () {

        var args = arguments;
        process.nextTick(function () {

            callback.apply(null, args);
        });
    };
};

exports.readStream = function (stream, callback) {

    var result = '';

    stream.on('readable', function () {

        var read = stream.read();
        if (read) {
            result += read.toString();
        }
    });

    stream.once('end', function () {

        callback(result);
    });
};
<|endoftext|>


<commit_before>import Backbone from 'backbone'
import objectPath from './object-path'
import deepCopy from './deep-copy'

const DEFAULTS = Object.freeze({
  pathSeparator: '.',
  pathParser: null,
})

const defaults = Object.assign({}, DEFAULTS)

function updateObjectPath() {
  objectPath.pathSeparator = defaults.pathSeparator

  const { pathParser } = defaults
  if (typeof pathParser === 'function' || pathParser == null) {
    objectPath.pathParser = pathParser
  }

  return objectPath
}

function isObject(value) {
  return value != null && typeof value === 'object'
}

/**
 * @class
 * @see http://backbonejs.org/#Model
 *
 * @example
 * class Person extends DeepModel {...}
 *
 * // or
 * const Person = DeepModel.extend({...})
 */
export default class DeepModel extends Backbone.Model {
  /**
   * this module's version.
   */
  static get VERSION() {
    return '1.2.4'
  }

  /**
   * Update default settings.
   *
   * @param {Object} [settings={}] reset if `null`
   * @param {string} [settings.pathSeparator='/']
   * @param {function(path: string): Array.<string>} [settings.pathParser] ignore if returns `[]`
   * @returns {Object}
   *
   * @example
   * DeepModel.defaults({anySetting: true})
   * DeepModel.defaults(null) // reset!
   *
   * @example
   * DeepModel.defaults({pathSeparator: '/'})
   *
   * const model = new DeepModel()
   * model.set('a', {})
   * model.set('a/b', 1)
   * model.get('a/b') //=> 1
   *
   * @example
   * DeepModel.defaults({
   *   pathParser(path) {
   *     if (path === '*') { return [] } // ignore!
   *     return path.split('_')
   *   }
   * })
   *
   * const model = new DeepModel()
   * model.set('a', {})
   * model.set('a_b', 1)
   * model.get('a_b') //=> 1
   * model.set('*', 2)
   * model.get('*') //=> undefined
   */
  static defaults(settings = {}) {
    return Object.assign(defaults, settings == null ? DEFAULTS : settings)
  }

  /**
   * @see http://backbonejs.org/#Model-get
   * @override
   * @param {string} attribute
   * @returns {*}
   *
   * @example
   * model.get('a.b')
   */
  get(attribute) {
    return updateObjectPath().get(this.attributes, attribute)
  }

  /**
   * @see http://backbonejs.org/#Model-set
   * @override
   * @param {string} attribute
   * @param {*}      value
   * @param {Object} [options]
   * @returns {DeepModel}
   *
   * @example
   * model.set({'a.b': 'value'})
   * model.set('a.b', 'value')
   */
  set(attribute, value, options) {
    if (attribute == null) {
      return this
    }

    const _ = updateObjectPath()

    let attrs
    if (typeof attribute === 'object') {
      attrs = attribute
      options = value // eslint-disable-line no-param-reassign
    } else {
      if (!_.pathParser && !_.hasSeparator(attribute)) {
        return super.set(attribute, value, options)
      }
      attrs = {}
      attrs[attribute] = value
    }

    const newAttrs = Object.keys(attrs).reduce((newObj, path) => {
      const paths = _.parse(path)

      if (paths.length === 0) {
        return newObj
      }
      if (paths.length === 1) {
        newObj[paths[0]] = attrs[path] // eslint-disable-line no-param-reassign
        return newObj
      }

      const rootPath = paths[0]
      let obj = newObj[rootPath]
      if (obj == null) {
        obj = deepCopy(this.attributes[rootPath])
      }
      if (!isObject(obj)) {
        throw new Error(`"${path}" does not exist in ${JSON.stringify(this)}`)
      }
      newObj[rootPath] = obj // eslint-disable-line no-param-reassign

      return _.set(newObj, paths, attrs[path])
    }, {})

    return super.set(newAttrs, options)
  }
}

DeepModel.extend = Backbone.Model.extend
<commit_msg>chore(release): revert to dummy version<commit_after>import Backbone from 'backbone'
import objectPath from './object-path'
import deepCopy from './deep-copy'

const DEFAULTS = Object.freeze({
  pathSeparator: '.',
  pathParser: null,
})

const defaults = Object.assign({}, DEFAULTS)

function updateObjectPath() {
  objectPath.pathSeparator = defaults.pathSeparator

  const { pathParser } = defaults
  if (typeof pathParser === 'function' || pathParser == null) {
    objectPath.pathParser = pathParser
  }

  return objectPath
}

function isObject(value) {
  return value != null && typeof value === 'object'
}

/**
 * @class
 * @see http://backbonejs.org/#Model
 *
 * @example
 * class Person extends DeepModel {...}
 *
 * // or
 * const Person = DeepModel.extend({...})
 */
export default class DeepModel extends Backbone.Model {
  /**
   * this module's version.
   */
  static get VERSION() {
    return '0.0.0'
  }

  /**
   * Update default settings.
   *
   * @param {Object} [settings={}] reset if `null`
   * @param {string} [settings.pathSeparator='/']
   * @param {function(path: string): Array.<string>} [settings.pathParser] ignore if returns `[]`
   * @returns {Object}
   *
   * @example
   * DeepModel.defaults({anySetting: true})
   * DeepModel.defaults(null) // reset!
   *
   * @example
   * DeepModel.defaults({pathSeparator: '/'})
   *
   * const model = new DeepModel()
   * model.set('a', {})
   * model.set('a/b', 1)
   * model.get('a/b') //=> 1
   *
   * @example
   * DeepModel.defaults({
   *   pathParser(path) {
   *     if (path === '*') { return [] } // ignore!
   *     return path.split('_')
   *   }
   * })
   *
   * const model = new DeepModel()
   * model.set('a', {})
   * model.set('a_b', 1)
   * model.get('a_b') //=> 1
   * model.set('*', 2)
   * model.get('*') //=> undefined
   */
  static defaults(settings = {}) {
    return Object.assign(defaults, settings == null ? DEFAULTS : settings)
  }

  /**
   * @see http://backbonejs.org/#Model-get
   * @override
   * @param {string} attribute
   * @returns {*}
   *
   * @example
   * model.get('a.b')
   */
  get(attribute) {
    return updateObjectPath().get(this.attributes, attribute)
  }

  /**
   * @see http://backbonejs.org/#Model-set
   * @override
   * @param {string} attribute
   * @param {*}      value
   * @param {Object} [options]
   * @returns {DeepModel}
   *
   * @example
   * model.set({'a.b': 'value'})
   * model.set('a.b', 'value')
   */
  set(attribute, value, options) {
    if (attribute == null) {
      return this
    }

    const _ = updateObjectPath()

    let attrs
    if (typeof attribute === 'object') {
      attrs = attribute
      options = value // eslint-disable-line no-param-reassign
    } else {
      if (!_.pathParser && !_.hasSeparator(attribute)) {
        return super.set(attribute, value, options)
      }
      attrs = {}
      attrs[attribute] = value
    }

    const newAttrs = Object.keys(attrs).reduce((newObj, path) => {
      const paths = _.parse(path)

      if (paths.length === 0) {
        return newObj
      }
      if (paths.length === 1) {
        newObj[paths[0]] = attrs[path] // eslint-disable-line no-param-reassign
        return newObj
      }

      const rootPath = paths[0]
      let obj = newObj[rootPath]
      if (obj == null) {
        obj = deepCopy(this.attributes[rootPath])
      }
      if (!isObject(obj)) {
        throw new Error(`"${path}" does not exist in ${JSON.stringify(this)}`)
      }
      newObj[rootPath] = obj // eslint-disable-line no-param-reassign

      return _.set(newObj, paths, attrs[path])
    }, {})

    return super.set(newAttrs, options)
  }
}

DeepModel.extend = Backbone.Model.extend
<|endoftext|>


<commit_before>import path from 'path';
import postcss from 'postcss';
import 'babel/polyfill';

const defaultResolutions = [
  '(min--moz-device-pixel-ratio: 1.5)',
  '(-o-min-device-pixel-ratio: 3/2)',
  '(-webkit-min-device-pixel-ratio: 1.5)',
  '(min-device-pixel-ratio: 1.5)',
  '(min-resolution: 144dpi)',
  '(min-resolution: 1.5dppx)'
];

export default postcss.plugin('postcss-at2x', at2x);

function at2x({ identifier = '@2x' } = {}) {
  return function(root) {
    // Create an empty rule so that all the new rules can be appended to this
    // and then append it at the end. Adding them to original `root` means
    // PostCSS then loops over the new rules in the `eachRule`
    // and creates extra loops and sadness.
    const ruleContainer = postcss.root();

    // Create the standard retina media at rule here so that all rules
    // can be appended into one rather than duplicating the params each time
    const retinaMediaAtRule = postcss.atRule({
      name: 'media',
      params: defaultResolutions.join(', ')
    });

    root.eachRule((rule) => {
      const mediaParent = rule.parent;

      // Check for any `background-size` declarations and keep a reference to it
      // These need to be added again to prevent it being overridden by usage of
      // the `background` shorthand
      let backgroundSize;
      rule.eachDecl('background-size', decl => backgroundSize = decl);

      rule.eachDecl(/^background/, (decl) => {
        // Exit if it's a normal background declaration
        if (!backgroundWithHiResURL(decl.value)) {
          return;
        }

        // Strip out `at-2x` from image url
        decl.value = decl.value.replace(/\s+(at-2x)\s*(;|$)/, '$2');

        // Construct a duplicate rule but with the image urls
        // replaced with retina versions
        const retinaRule = postcss.rule({ selector: decl.parent.selector });
        retinaRule.append(postcss.decl({
          prop: decl.prop,
          value: createRetinaUrl(decl.value, identifier)
        }));

        // Add back any `background-size` value
        if (backgroundSize) {
          retinaRule.append(postcss.decl(backgroundSize));
        }

        // If retina image is within a media query then ensure each size gets
        // the retina resolutions. Append these one at the time because each set
        // of atRule params will be different
        //
        // Otherwise just append them to the media rule declared previously
        if (mediaParent.name === 'media') {
          const params = combineMediaQuery(mediaParent.params.split(/,\s*/), defaultResolutions);
          const scopedRetinaMediaAtRule = postcss.atRule({ name: 'media', params });

          scopedRetinaMediaAtRule.append(retinaRule);
          ruleContainer.append(scopedRetinaMediaAtRule);
        } else {
          retinaMediaAtRule.append(retinaRule);
        }
      });
    });

    // There is a chance ruleContainer could be empty, so check for it
    if (retinaMediaAtRule.nodes) {
      ruleContainer.append(retinaMediaAtRule);
    }

    // Add all the new rules to the bottom of the stylesheet
    root.append(ruleContainer);
  };
}

/**
 * Add all the resolutions to each media query to scope them
 */
function combineMediaQuery(queries, resolutions) {
  return queries.reduce((finalQuery, query) => {
    resolutions.forEach(resolution => finalQuery.push(`${query} and ${resolution}`));
    return finalQuery;
  }, []).join(', ');
}

const urlPathRegex = /url\((.*?)\)/gm;

function createRetinaUrl(bgValue, identifier) {

  // Loop over all occurances of `url()` and match the path
  let match;
  while ((match = urlPathRegex.exec(bgValue)) !== null) {
    const [, url] = match;
    const extension = path.extname(url);

    if (extension === '.svg') {
      break;
    }

    // File name without extension
    const filename = path.basename(path.basename(url), extension);
    // Replace with retina filename
    bgValue = bgValue.replace(new RegExp(`(${filename})(${extension})`, 'gm'), `$1${identifier}$2`);
  }

  return bgValue;
}

function backgroundWithHiResURL(value) {
  return value.includes('url(') && value.includes('at-2x');
}
<commit_msg>Rename argument<commit_after>import path from 'path';
import postcss from 'postcss';
import 'babel/polyfill';

const defaultResolutions = [
  '(min--moz-device-pixel-ratio: 1.5)',
  '(-o-min-device-pixel-ratio: 3/2)',
  '(-webkit-min-device-pixel-ratio: 1.5)',
  '(min-device-pixel-ratio: 1.5)',
  '(min-resolution: 144dpi)',
  '(min-resolution: 1.5dppx)'
];

export default postcss.plugin('postcss-at2x', at2x);

function at2x({ identifier = '@2x' } = {}) {
  return function(root) {
    // Create an empty rule so that all the new rules can be appended to this
    // and then append it at the end. Adding them to original `root` means
    // PostCSS then loops over the new rules in the `eachRule`
    // and creates extra loops and sadness.
    const ruleContainer = postcss.root();

    // Create the standard retina media at rule here so that all rules
    // can be appended into one rather than duplicating the params each time
    const retinaMediaAtRule = postcss.atRule({
      name: 'media',
      params: defaultResolutions.join(', ')
    });

    root.eachRule((rule) => {
      const mediaParent = rule.parent;

      // Check for any `background-size` declarations and keep a reference to it
      // These need to be added again to prevent it being overridden by usage of
      // the `background` shorthand
      let backgroundSize;
      rule.eachDecl('background-size', decl => backgroundSize = decl);

      rule.eachDecl(/^background/, (decl) => {
        // Exit if it's a normal background declaration
        if (!backgroundWithHiResURL(decl.value)) {
          return;
        }

        // Strip out `at-2x` from image url
        decl.value = decl.value.replace(/\s+(at-2x)\s*(;|$)/, '$2');

        // Construct a duplicate rule but with the image urls
        // replaced with retina versions
        const retinaRule = postcss.rule({ selector: decl.parent.selector });
        retinaRule.append(postcss.decl({
          prop: decl.prop,
          value: createRetinaUrl(decl.value, identifier)
        }));

        // Add back any `background-size` value
        if (backgroundSize) {
          retinaRule.append(postcss.decl(backgroundSize));
        }

        // If retina image is within a media query then ensure each size gets
        // the retina resolutions. Append these one at the time because each set
        // of atRule params will be different
        //
        // Otherwise just append them to the media rule declared previously
        if (mediaParent.name === 'media') {
          const params = combineMediaQuery(mediaParent.params.split(/,\s*/), defaultResolutions);
          const scopedRetinaMediaAtRule = postcss.atRule({ name: 'media', params });

          scopedRetinaMediaAtRule.append(retinaRule);
          ruleContainer.append(scopedRetinaMediaAtRule);
        } else {
          retinaMediaAtRule.append(retinaRule);
        }
      });
    });

    // There is a chance ruleContainer could be empty, so check for it
    if (retinaMediaAtRule.nodes) {
      ruleContainer.append(retinaMediaAtRule);
    }

    // Add all the new rules to the bottom of the stylesheet
    root.append(ruleContainer);
  };
}

/**
 * Add all the resolutions to each media query to scope them
 */
function combineMediaQuery(queries, resolutions) {
  return queries.reduce((finalQuery, query) => {
    resolutions.forEach(resolution => finalQuery.push(`${query} and ${resolution}`));
    return finalQuery;
  }, []).join(', ');
}

const urlPathRegex = /url\((.*?)\)/gm;

function createRetinaUrl(bgValue, identifier) {

  // Loop over all occurances of `url()` and match the path
  let match;
  while ((match = urlPathRegex.exec(bgValue)) !== null) {
    const [, url] = match;
    const extension = path.extname(url);

    if (extension === '.svg') {
      break;
    }

    // File name without extension
    const filename = path.basename(path.basename(url), extension);
    // Replace with retina filename
    bgValue = bgValue.replace(new RegExp(`(${filename})(${extension})`, 'gm'), `$1${identifier}$2`);
  }

  return bgValue;
}

function backgroundWithHiResURL(bgValue) {
  return bgValue.includes('url(') && bgValue.includes('at-2x');
}
<|endoftext|>


<commit_before>/**

  server

  The backbone of the server module. In development, this runs proxied through
  BrowserSync server.

  @param {Object} options Options passed on to "globals"
  @param {Function} next Called when server successfully initialized

**/

var http = require("http"),
    reorg = require("reorg");

module.exports = reorg(function(options, next) {

  // Globals
  require("./globals")(options);

  var server     = global.shipp.server = global.shipp.framework({ strict: true }),
      middleware = require("./middleware"),
      Utils      = require("./utils");

  // Create http server
  global.shipp.http = http.createServer(server);

  // Remove views functionality (we handle this in our compilers)
  server.disable("view cache");
  server.disable("view engine");
  server.disable("views");

  // Remove powered-by header for security
  server.disable("x-powered-by");

  // Websockets
  require('./websockets')();

  // Middleware
  [
    // User-defined middleware
    middleware("beforeAll"),

    // Common middleware: logging, favicons, cookie parsing, sessions and body parsing
    require("./common")(),

    // User-defined middleware
    middleware("beforeRoutes"),

    // Static and compiled routes
    require("./routes")(),

    // Data-server
    require("./data-api")(),

    // User-defined middleware
    middleware("afterRoutes")

  ].forEach(function(library) {
    Utils.useMiddleware(server, library);
  });

  // Error handling: please see errors middleware for explanation of structure
  require("./errors")(server, middleware("errorHandler"));

  // Find open port and set up graceful shutdown
  require("./lifecycle")(next);

}, "object", ["function", function() {}]);
<commit_msg>index: adds caching middleware<commit_after>/**

  server

  The backbone of the server module. In development, this runs proxied through
  BrowserSync server.

  @param {Object} options Options passed on to "globals"
  @param {Function} next Called when server successfully initialized

**/

var http = require("http"),
    reorg = require("reorg");

module.exports = reorg(function(options, next) {

  // Globals
  require("./globals")(options);

  var server     = global.shipp.server = global.shipp.framework({ strict: true }),
      middleware = require("./middleware"),
      Utils      = require("./utils");

  // Create http server
  global.shipp.http = http.createServer(server);

  // Remove views functionality (we handle this in our compilers)
  server.disable("view cache");
  server.disable("view engine");
  server.disable("views");

  // Remove powered-by header for security
  server.disable("x-powered-by");

  // Websockets
  require('./websockets')();

  // Middleware
  [
    // User-defined middleware
    middleware("beforeAll"),

    // Common middleware: logging, favicons, cookie parsing, sessions and body parsing
    require("./common")(),

    // User-defined middleware
    middleware("beforeRoutes"),

    // Caching
    global.shipp.cache.middleware,

    // Static and compiled routes
    require("./routes")(),

    // Data-server
    require("./data-api")(),

    // User-defined middleware
    middleware("afterRoutes")

  ].forEach(function(library) {
    Utils.useMiddleware(server, library);
  });

  // Error handling: please see errors middleware for explanation of structure
  require("./errors")(server, middleware("errorHandler"));

  // Find open port and set up graceful shutdown
  require("./lifecycle")(next);

}, "object", ["function", function() {}]);
<|endoftext|>


<commit_before>let watcher = null
try {
  watcher = require('../build/Release/watcher.node')
} catch (err) {
  watcher = require('../build/Debug/watcher.node')
}

const ACTIONS = new Map([
  [0, 'created'],
  [1, 'deleted'],
  [2, 'modified'],
  [3, 'renamed']
])

const ENTRIES = new Map([
  [0, 'file'],
  [1, 'directory'],
  [2, 'unknown']
])

// Logging mode constants
const DISABLE = Symbol('disable')
const STDERR = Symbol('stderr')
const STDOUT = Symbol('stdout')

function logOption (baseName, options, normalized) {
  const value = options[baseName]

  if (value === undefined) return

  if (value === DISABLE) {
    normalized[`${baseName}Disable`] = true
    return
  }

  if (value === STDERR) {
    normalized[`${baseName}Stderr`] = true
    return
  }

  if (value === STDOUT) {
    normalized[`${baseName}Stdout`] = true
    return
  }

  if (typeof value === 'string' || value instanceof String) {
    normalized[`${baseName}File`] = value
    return
  }

  throw new Error(`option ${baseName} must be DISABLE, STDERR, STDOUT, or a filename`)
}

class NativeWatcher {
  constructor (channel) {
    this.channel = channel
    this.disposed = false
  }

  unwatch () {
    if (this.disposed) {
      return Promise.resolve()
    }
    this.disposed = true

    return new Promise((resolve, reject) => {
      watcher.unwatch(this.channel, err => (err ? reject(err) : resolve()))
    })
  }
}

module.exports = {
  configure: function (options) {
    if (!options) {
      return Promise.reject(new Error('configure() requires an option object'))
    }

    const normalized = {}

    logOption('mainLog', options, normalized)
    logOption('workerLog', options, normalized)

    return new Promise((resolve, reject) => {
      watcher.configure(normalized, err => (err ? reject(err) : resolve(err)))
    })
  },

  watch: function (rootPath, options, eventCallback) {
    const eventMapper = (err, events) => {
      if (err) {
        if (eventCallback) {
          eventCallback(err)
        } else {
          console.error(`[watcher] error: ${err}`)
        }
        return
      }

      if (!eventCallback) return

      const translated = events.map(event => {
        const n = {
          action: ACTIONS.get(event.action),
          kind: ENTRIES.get(event.kind),
          path: event.path
        }

        if (event.oldPath !== '') n.oldPath = event.oldPath

        return n
      })

      eventCallback(null, translated)
    }

    return new Promise((resolve, reject) => {
      watcher.watch(rootPath, options, (err, channel) => {
        if (err) {
          reject(err)
          return
        }

        resolve(new NativeWatcher(channel))
      }, eventMapper)
    })
  },

  status: function () {
    return watcher.status()
  },

  DISABLE,
  STDERR,
  STDOUT
}
<commit_msg>Normalize polling options in JS<commit_after>let watcher = null
try {
  watcher = require('../build/Release/watcher.node')
} catch (err) {
  watcher = require('../build/Debug/watcher.node')
}

const ACTIONS = new Map([
  [0, 'created'],
  [1, 'deleted'],
  [2, 'modified'],
  [3, 'renamed']
])

const ENTRIES = new Map([
  [0, 'file'],
  [1, 'directory'],
  [2, 'unknown']
])

// Logging mode constants
const DISABLE = Symbol('disable')
const STDERR = Symbol('stderr')
const STDOUT = Symbol('stdout')

function logOption (baseName, options, normalized) {
  const value = options[baseName]

  if (value === undefined) return

  if (value === DISABLE) {
    normalized[`${baseName}Disable`] = true
    return
  }

  if (value === STDERR) {
    normalized[`${baseName}Stderr`] = true
    return
  }

  if (value === STDOUT) {
    normalized[`${baseName}Stdout`] = true
    return
  }

  if (typeof value === 'string' || value instanceof String) {
    normalized[`${baseName}File`] = value
    return
  }

  throw new Error(`option ${baseName} must be DISABLE, STDERR, STDOUT, or a filename`)
}

class NativeWatcher {
  constructor (channel) {
    this.channel = channel
    this.disposed = false
  }

  unwatch () {
    if (this.disposed) {
      return Promise.resolve()
    }
    this.disposed = true

    return new Promise((resolve, reject) => {
      watcher.unwatch(this.channel, err => (err ? reject(err) : resolve()))
    })
  }
}

module.exports = {
  configure: function (options) {
    if (!options) {
      return Promise.reject(new Error('configure() requires an option object'))
    }

    const normalized = {}

    logOption('mainLog', options, normalized)
    logOption('workerLog', options, normalized)
    logOption('pollingLog', options, normalized)

    return new Promise((resolve, reject) => {
      watcher.configure(normalized, err => (err ? reject(err) : resolve(err)))
    })
  },

  watch: function (rootPath, options, eventCallback) {
    const eventMapper = (err, events) => {
      if (err) {
        if (eventCallback) {
          eventCallback(err)
        } else {
          console.error(`[watcher] error: ${err}`)
        }
        return
      }

      if (!eventCallback) return

      const translated = events.map(event => {
        const n = {
          action: ACTIONS.get(event.action),
          kind: ENTRIES.get(event.kind),
          path: event.path
        }

        if (event.oldPath !== '') n.oldPath = event.oldPath

        return n
      })

      eventCallback(null, translated)
    }

    return new Promise((resolve, reject) => {
      watcher.watch(rootPath, options, (err, channel) => {
        if (err) {
          reject(err)
          return
        }

        resolve(new NativeWatcher(channel))
      }, eventMapper)
    })
  },

  status: function () {
    return watcher.status()
  },

  DISABLE,
  STDERR,
  STDOUT
}
<|endoftext|>


<commit_before>
/*
 * Hoax
 * https://github.com/nick-thompson/hoax
 *
 * Copyright (c) 2013 Nick Thompson
 * MIT License.
 */

var fs    = require('fs')
  , path  = require('path')
  , glob  = require('glob')
  , async = require('async')
  , utils = require('./utils')
  , Pouch = require('pouchdb')
  , exec  = require('child_process').exec
  , pyDir = path.resolve(__dirname, '../tag')

/**
 * Read the track metadata.
 *
 * @param {string} track Path to the audio file.
 * @param {function} callback
 */

function readTag (track, callback) {
  var cmd = 'python tag.py "' + track + '"';
  exec(cmd, { cwd: pyDir }, function (err, stdout, stderr) {
    if (err) return utils.error(err.message);
    if (stderr) return utils.error(stderr);
    callback.call(null, null, JSON.parse(stdout));
  });
}

/**
 * Read the track binary as a Base64 string.
 *
 * @param {string} track Path to the audio file.
 * @param {function} callback
 */

function readBinary (track, callback) {
  fs.readFile(track, function (err, buffer) {
    if (err) return utils.error(err.message);
    callback.call(null, null, buffer.toString('base64'));
  });
}

/**
 * Recursively read a directory, returning a list of the files therein.
 *
 * @param {string} fp Filepath of the directory.
 * @param {function} callback
 */

function readDir (fp, callback) {
  glob('**/*.mp3', { cwd: fp }, function (err, files) {
    if (err) return utils.error(err.message);
    callback.call(null, null, files.map(function (file) {
      return path.join(fp, file);
    }));
  });
}

/**
 * Create a new Hoax instance at `uri` with tracks from `directory`.
 *
 * @param {string} uri
 * @param {string} directory
 * @param {function} callback
 */

function createNew (uri, directory, callback) {
  readDir(directory, function (err, tracks) {
    if (err) throw err;
    async.each(tracks, function (track, done) {
      utils.log('Reading ' + track);
      async.parallel([
        readTag.bind(null, track),
        readBinary.bind(null, track)
      ], function (err, results) {
        utils.log('Uploading ' + track);
        var meta = results[0]
          , b64string = results[1]
          , fileDoc;

        // This document will hold the actual music file.
        fileDoc = {
          _id: meta['_id'],
          _attachments: {
            'file.mp3': {
              'content_type': 'audio/mpeg',
              'data': b64string
            }
          }
        };

        // And we'll patch the metadata document with a consistant namespace
        meta['_id'] = 'meta_' + meta['_id'];

        Pouch(uri, function (err, db) {
          if (err) throw err;
          db.bulkDocs({ docs: [meta, fileDoc] }, function (err, res) {
            if (err) throw err;
          });
        });
      });
    }, callback);
  });
}

function updateExisting (uri, directory) {
  console.log(uri, directory);
}

module.exports = {
  'new': createNew,
  'update': updateExisting
};

<commit_msg>Couchapp installation on new command.<commit_after>
/*
 * Hoax
 * https://github.com/nick-thompson/hoax
 *
 * Copyright (c) 2013 Nick Thompson
 * MIT License.
 */

var fs        = require('fs')
  , path      = require('path')
  , glob      = require('glob')
  , async     = require('async')
  , utils     = require('./utils')
  , Pouch     = require('pouchdb')
  , couchapp  = require('couchapp')
  , exec      = require('child_process').exec
  , pyDir     = path.resolve(__dirname, '../tag')

/**
 * Read the track metadata.
 *
 * @param {string} track Path to the audio file.
 * @param {function} callback
 */

function readTag (track, callback) {
  var cmd = 'python tag.py "' + track + '"';
  exec(cmd, { cwd: pyDir }, function (err, stdout, stderr) {
    if (err) return utils.error(err.message);
    if (stderr) return utils.error(stderr);
    callback.call(null, null, JSON.parse(stdout));
  });
}

/**
 * Read the track binary as a Base64 string.
 *
 * @param {string} track Path to the audio file.
 * @param {function} callback
 */

function readBinary (track, callback) {
  fs.readFile(track, function (err, buffer) {
    if (err) return utils.error(err.message);
    callback.call(null, null, buffer.toString('base64'));
  });
}

/**
 * Recursively read a directory, returning a list of the files therein.
 *
 * @param {string} fp Filepath of the directory.
 * @param {function} callback
 */

function readDir (fp, callback) {
  glob('**/*.mp3', { cwd: fp }, function (err, files) {
    if (err) return utils.error(err.message);
    callback.call(null, null, files.map(function (file) {
      return path.join(fp, file);
    }));
  });
}

/**
 * Uploads the client side CouchApp to the database from ../client/
 *
 * @param {string} uri
 * @param {function} callback
 */

function uploadCouchApp (uri, callback) {
  var ddoc = {
    _id: '_design/hoax',
    views: {},
    lists: {},
    shows: {}
  };

  couchapp.loadAttachments(ddoc, path.resolve(__dirname, '../client'));
  couchapp.createApp(ddoc, uri, function (app) {
    app.push(callback);
  });
}

/**
 * Create a new Hoax instance at `uri` with tracks from `directory`.
 *
 * @param {string} uri
 * @param {string} directory
 * @param {function} callback
 */

function createNew (uri, directory, callback) {
  Pouch(uri, function (err, db) {
    if (err) throw err;
    utils.log('Installing CouchApp...');
    uploadCouchApp(uri, function () {
      readDir(directory, function (err, tracks) {
        if (err) throw err;
        async.each(tracks, function (track, done) {
          utils.log('Reading ' + track);
          async.parallel([
            readTag.bind(null, track),
            readBinary.bind(null, track)
          ], function (err, results) {
            utils.log('Uploading ' + track);
            var meta = results[0]
              , b64string = results[1]
              , fileDoc;

            // This document will hold the actual music file.
            fileDoc = {
              _id: meta['_id'],
              _attachments: {
                'file.mp3': {
                  'content_type': 'audio/mpeg',
                  'data': b64string
                }
              }
            };

            // And we'll patch the metadata document with a consistant namespace
            meta['_id'] = 'meta_' + meta['_id'];

            // Go!
            db.bulkDocs({ docs: [meta, fileDoc] }, function (err, res) {
              if (err) throw err;
            });
          });
        }, callback);
      });
    });
  });
}

function updateExisting (uri, directory) {
  console.log(uri, directory);
}

module.exports = {
  'new': createNew,
  'update': updateExisting
};

<|endoftext|>


<commit_before>'use strict';

var http = require('http');
var Request = require('request');
var Q = require('q');
var zlib = require('zlib');
var busywait = require('busywait').async;
var _ = require('underscore');

var debug = false;

module.exports = Codeine;

function Codeine(server,port,api_key) {
  this.server = server;
  this.api_key = api_key;
  this.port = port;
  this.request = Request.defaults({'headers': { 'api_token' : this.api_key} });
}

function getCodeinePath(self) {
  return 'http://' + self.server + ':' + self.port + '/api-with-token/';
}

Codeine.prototype.setDebug = function(val) {
  debug = val;
};

Codeine.prototype.getProjects = function() {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'projects';
  log('getProjects() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var projects = JSON.parse(body);
      deferred.resolve(projects);
    }
    else {
      log('getProjects() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjects() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.createNewProject = function(projectName, selectedProject) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'projects';
  log('createNewProject() - uri is ' + uri);
  this.request(createNewProjectCommand(uri,this.api_key,projectName,selectedProject), function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      deferred.resolve(body);
    }
    else {
      log('createNewProject() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: createNewProject() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.runCommand = function(projectName, commandObject){
  var deferred = Q.defer();
  var runCommandOptions = createCodeineRunCommand(this.server,projectName,this.api_key, this.port);
  log('runCommand() - command object ', runCommandOptions);
  var post_data = JSON.stringify(commandObject);
  log('runCommand() - post data is ' + post_data);
  var commandReq = http.request(runCommandOptions, function(res) {
    res.setEncoding('utf8');

    if (res.statusCode === 200) {
      log('runCommand() - Command ran successfully');
    }
    else {
      console.error('codeine:: runCommand() - Status Code =  ' + res.statusCode);
      deferred.reject();
    }
    res.on('data', function (chunk) {
      log('Response: ', chunk);
      deferred.resolve(chunk);
    });
  });
  commandReq.write(post_data);
  commandReq.on('error', function(e) {
    console.error('codeine:: runCommand() - Error from server', e);
    deferred.reject(e);
  });
  commandReq.end();
  return deferred.promise;
};

Codeine.prototype.runCommandSync = function (projectName, commandObject, sleep, times) {
  var scope = this;
  log('runCommandSync() - Running command', commandObject.command_info.name);
  return this.runCommand(projectName, commandObject)
      .then(function (commandId) {
        log('runCommandSync() - Waiting for command', commandId, 'to finish');
        function check(iteration) {
          log('runCommandSync() - waiting for command', commandId, 'to finish.' +
              ' Iteration:', iteration);
          return scope.getCommandStatusJson(projectName, commandId, false)
              .then(function (res) {
                  if (res.finished && (res.fail_list.length + res.success_list.length + (res.skip_list ? res.skip_list.length : 0)) === res.nodes_list.length) {
                      return _.map(res.fail_list, function (node) {
                          return node.name;
                      });
                  } else {
                      return Q.reject('not finished yet');
                  }
              });
        }
        return busywait(check, {sleepTime: sleep,maxChecks: times,
            failMsg: 'Command is not complete after timeout'})
            .then(function (result) {
              var failedNodes = result.result;
              if (failedNodes.length > 0) {
                return Q.reject("Failed running command on " + failedNodes);
              }
              log('runCommandSync() - Command', commandId, 'finished successfully');
            });
      });
};

Codeine.prototype.getProjectNodes = function(projectName, filter) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-nodes?project='+ projectName;
  log('getProjectNodes() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      zlib.gunzip(body, function(err, decoded) {
        if (err) {
          console.error('codeine:: getProjectNodes() - Error during gzip', err);
          deferred.reject(err);
        }
        else {
          var projectNodes = JSON.parse(decoded);
          if (filter) {
            projectNodes = _.filter(projectNodes, function(node) { return filter(node);});
          }
          deferred.resolve(projectNodes);
        }
      });
    }
    else {
      log('getProjectNodes() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectNodes() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.getProjectConfiguration = function(projectName) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-configuration?project='+ projectName;
  log('getProjectConfiguration() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var config = JSON.parse(body);
      deferred.resolve(config);
    }
    else {
      log('getProjectConfiguration() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectConfiguration() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.getProjectStatus = function(projectName) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-status2?project='+ projectName;
  log('getProjectStatus() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var config = JSON.parse(body);
      deferred.resolve(config);
    }
    else {
      log('getProjectStatus() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectStatus() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.saveProjectConfiguration = function(projectName, conf) {
  var deferred = Q.defer();
  var saveConfCommandOptions = createSaveConfCommand(this.server, projectName, this.api_key, this.port);
  var post_data = JSON.stringify(conf);
  log('saveProjectConfiguration() - post data is ', post_data);
  var commandReq = http.request(saveConfCommandOptions, function(res) {
    res.setEncoding('utf8');
    if (res.statusCode === 200) {
      log('saveProjectConfiguration() - Configuration was saved successfully');
    }
    else {
      console.error('coeine:: saveProjectConfiguration() - Status Code =  ' + res.statusCode);
      deferred.reject();
    }
    res.on('data', function (chunk) {
      log('Response: ', chunk);
      deferred.resolve(chunk);
    });
  });
  commandReq.write(post_data);
  commandReq.on('error', function(e) {
    console.error('codeine:: saveProjectConfiguration() - Error from server', e);
    deferred.reject(e);
  });
  commandReq.end();
  return deferred.promise;
};

Codeine.prototype.getCommandStatus = function(projectName, commandId, includeOutput) {
  var uri = getCodeinePath(this) + 'command-status?command=' + commandId + '&project='+ projectName;
  if (includeOutput !== undefined && includeOutput === false) {
    uri += '&output=false';
  }
  log('getCommandStatus() - uri is ' + uri);
  return this.request({ url : uri, encoding : null }).pipe(zlib.createGunzip());
};

Codeine.prototype.getCommandStatusJson = function(projectName, commandId, includeOutput) {
  var deferred = Q.defer();
  var stream = this.getCommandStatus(projectName,commandId,includeOutput);
  var chunks = [];
  stream.on("data", function (chunk) {
    chunks.push(chunk);
  });
  stream.on("end", function () {
    deferred.resolve(JSON.parse(Buffer.concat(chunks).toString()));
  });
  stream.on("error", function (err) {
    deferred.reject(err);
  });
  return deferred.promise;
};

Codeine.prototype.getCommandOutput = function(projectName, commandId) {
  var uri = getCodeinePath(this) + 'command-output?command-id=' + commandId + '&project='+ projectName;
  log('getCommandOutput() - uri is ' + uri);
  return this.request({ url : uri, encoding : null });
};

function createNewProjectCommand(url,api_token,projectName,selectedProject) {
  var requestData = {
    'project_name': projectName,
    'type': 'New'
  };
  if (selectedProject) {
    requestData.type = 'Copy';
    requestData.selected_project = selectedProject;
  }
  return {
    url: url,
    encoding: null,
    headers  : {
      'api_token' : api_token
    },
    method: 'POST',
    body: JSON.stringify(requestData)
  };
}

function createSaveConfCommand(server,project,api_token,port) {
  return {
    hostname: server,
    headers  : {'api_token' : api_token} ,
    port: port,
    path: '/api-with-token/project-configuration?project=' + project,
    method: 'PUT'
  };
}

function createCodeineRunCommand(server,project,api_token,port) {
  return {
    hostname: server,
    headers  : {'api_token' : api_token} ,
    port: port,
    path: '/api-with-token/command-nodes?project=' + project,
    method: 'POST'
  };
}

function log() {
  if (debug) {
    console.log.apply(undefined,arguments);
  }
}
<commit_msg>codeine_node_utils-7 add getProjectCommandsConfiguration (#8)<commit_after>'use strict';

var http = require('http');
var Request = require('request');
var Q = require('q');
var zlib = require('zlib');
var busywait = require('busywait').async;
var _ = require('underscore');

var debug = false;

module.exports = Codeine;

function Codeine(server,port,api_key) {
  this.server = server;
  this.api_key = api_key;
  this.port = port;
  this.request = Request.defaults({'headers': { 'api_token' : this.api_key} });
}

function getCodeinePath(self) {
  return 'http://' + self.server + ':' + self.port + '/api-with-token/';
}

Codeine.prototype.setDebug = function(val) {
  debug = val;
};

Codeine.prototype.getProjects = function() {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'projects';
  log('getProjects() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var projects = JSON.parse(body);
      deferred.resolve(projects);
    }
    else {
      log('getProjects() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjects() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.createNewProject = function(projectName, selectedProject) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'projects';
  log('createNewProject() - uri is ' + uri);
  this.request(createNewProjectCommand(uri,this.api_key,projectName,selectedProject), function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      deferred.resolve(body);
    }
    else {
      log('createNewProject() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: createNewProject() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.runCommand = function(projectName, commandObject){
  var deferred = Q.defer();
  var runCommandOptions = createCodeineRunCommand(this.server,projectName,this.api_key, this.port);
  log('runCommand() - command object ', runCommandOptions);
  var post_data = JSON.stringify(commandObject);
  log('runCommand() - post data is ' + post_data);
  var commandReq = http.request(runCommandOptions, function(res) {
    res.setEncoding('utf8');

    if (res.statusCode === 200) {
      log('runCommand() - Command ran successfully');
    }
    else {
      console.error('codeine:: runCommand() - Status Code =  ' + res.statusCode);
      deferred.reject();
    }
    res.on('data', function (chunk) {
      log('Response: ', chunk);
      deferred.resolve(chunk);
    });
  });
  commandReq.write(post_data);
  commandReq.on('error', function(e) {
    console.error('codeine:: runCommand() - Error from server', e);
    deferred.reject(e);
  });
  commandReq.end();
  return deferred.promise;
};

Codeine.prototype.runCommandSync = function (projectName, commandObject, sleep, times) {
  var scope = this;
  log('runCommandSync() - Running command', commandObject.command_info.name);
  return this.runCommand(projectName, commandObject)
      .then(function (commandId) {
        log('runCommandSync() - Waiting for command', commandId, 'to finish');
        function check(iteration) {
          log('runCommandSync() - waiting for command', commandId, 'to finish.' +
              ' Iteration:', iteration);
          return scope.getCommandStatusJson(projectName, commandId, false)
              .then(function (res) {
                  if (res.finished && (res.fail_list.length + res.success_list.length + (res.skip_list ? res.skip_list.length : 0)) === res.nodes_list.length) {
                      return _.map(res.fail_list, function (node) {
                          return node.name;
                      });
                  } else {
                      return Q.reject('not finished yet');
                  }
              });
        }
        return busywait(check, {sleepTime: sleep,maxChecks: times,
            failMsg: 'Command is not complete after timeout'})
            .then(function (result) {
              var failedNodes = result.result;
              if (failedNodes.length > 0) {
                return Q.reject("Failed running command on " + failedNodes);
              }
              log('runCommandSync() - Command', commandId, 'finished successfully');
            });
      });
};

Codeine.prototype.getProjectNodes = function(projectName, filter) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-nodes?project='+ projectName;
  log('getProjectNodes() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      zlib.gunzip(body, function(err, decoded) {
        if (err) {
          console.error('codeine:: getProjectNodes() - Error during gzip', err);
          deferred.reject(err);
        }
        else {
          var projectNodes = JSON.parse(decoded);
          if (filter) {
            projectNodes = _.filter(projectNodes, function(node) { return filter(node);});
          }
          deferred.resolve(projectNodes);
        }
      });
    }
    else {
      log('getProjectNodes() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectNodes() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.getProjectConfiguration = function(projectName) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-configuration?project='+ projectName;
  log('getProjectConfiguration() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var config = JSON.parse(body);
      deferred.resolve(config);
    }
    else {
      log('getProjectConfiguration() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectConfiguration() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.getProjectCommandsConfiguration = function(projectName) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-commands-configuration?project='+ projectName;
  log('getProjectCommandsConfiguration() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var config = JSON.parse(body);
      deferred.resolve(config);
    }
    else {
      log('getProjectCommandsConfiguration() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectCommandsConfiguration() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.getProjectStatus = function(projectName) {
  var deferred = Q.defer();
  var uri = getCodeinePath(this) + 'project-status2?project='+ projectName;
  log('getProjectStatus() - uri is ' + uri);
  this.request({ url : uri, encoding : null }, function (error, response, body) {
    if (!error && response && response.statusCode === 200) {
      var config = JSON.parse(body);
      deferred.resolve(config);
    }
    else {
      log('getProjectStatus() - Error is', error);
      if (response && response.statusCode) {
        console.error('codeine:: getProjectStatus() - Status Code =  ' + response.statusCode);
      }
      deferred.reject(error);
    }
  });
  return deferred.promise;
};

Codeine.prototype.saveProjectConfiguration = function(projectName, conf) {
  var deferred = Q.defer();
  var saveConfCommandOptions = createSaveConfCommand(this.server, projectName, this.api_key, this.port);
  var post_data = JSON.stringify(conf);
  log('saveProjectConfiguration() - post data is ', post_data);
  var commandReq = http.request(saveConfCommandOptions, function(res) {
    res.setEncoding('utf8');
    if (res.statusCode === 200) {
      log('saveProjectConfiguration() - Configuration was saved successfully');
    }
    else {
      console.error('coeine:: saveProjectConfiguration() - Status Code =  ' + res.statusCode);
      deferred.reject();
    }
    res.on('data', function (chunk) {
      log('Response: ', chunk);
      deferred.resolve(chunk);
    });
  });
  commandReq.write(post_data);
  commandReq.on('error', function(e) {
    console.error('codeine:: saveProjectConfiguration() - Error from server', e);
    deferred.reject(e);
  });
  commandReq.end();
  return deferred.promise;
};

Codeine.prototype.getCommandStatus = function(projectName, commandId, includeOutput) {
  var uri = getCodeinePath(this) + 'command-status?command=' + commandId + '&project='+ projectName;
  if (includeOutput !== undefined && includeOutput === false) {
    uri += '&output=false';
  }
  log('getCommandStatus() - uri is ' + uri);
  return this.request({ url : uri, encoding : null }).pipe(zlib.createGunzip());
};

Codeine.prototype.getCommandStatusJson = function(projectName, commandId, includeOutput) {
  var deferred = Q.defer();
  var stream = this.getCommandStatus(projectName,commandId,includeOutput);
  var chunks = [];
  stream.on("data", function (chunk) {
    chunks.push(chunk);
  });
  stream.on("end", function () {
    deferred.resolve(JSON.parse(Buffer.concat(chunks).toString()));
  });
  stream.on("error", function (err) {
    deferred.reject(err);
  });
  return deferred.promise;
};

Codeine.prototype.getCommandOutput = function(projectName, commandId) {
  var uri = getCodeinePath(this) + 'command-output?command-id=' + commandId + '&project='+ projectName;
  log('getCommandOutput() - uri is ' + uri);
  return this.request({ url : uri, encoding : null });
};

function createNewProjectCommand(url,api_token,projectName,selectedProject) {
  var requestData = {
    'project_name': projectName,
    'type': 'New'
  };
  if (selectedProject) {
    requestData.type = 'Copy';
    requestData.selected_project = selectedProject;
  }
  return {
    url: url,
    encoding: null,
    headers  : {
      'api_token' : api_token
    },
    method: 'POST',
    body: JSON.stringify(requestData)
  };
}

function createSaveConfCommand(server,project,api_token,port) {
  return {
    hostname: server,
    headers  : {'api_token' : api_token} ,
    port: port,
    path: '/api-with-token/project-configuration?project=' + project,
    method: 'PUT'
  };
}

function createCodeineRunCommand(server,project,api_token,port) {
  return {
    hostname: server,
    headers  : {'api_token' : api_token} ,
    port: port,
    path: '/api-with-token/command-nodes?project=' + project,
    method: 'POST'
  };
}

function log() {
  if (debug) {
    console.log.apply(undefined,arguments);
  }
}
<|endoftext|>


<commit_before>

//model must expose
//  .apply(doc, op) -> doc (where doc can be null)
//  .fromJSON(json) -> doc
//  .transformCursor(cursor, op, isOwnOp)
//
//  the doc must expose
//  .toJSON

// usage (client side)
// var sharejs = require('share').client;
// var slate_type = require('ot-slate0')(model);
// sharejs.registerType(slate_type);

// usage (server side)
// livedb.ot.registerType(slate_type);

//Operations

// number => retain
// {d:....} => remove
// {i:....} => insert

// .... can be string or object
var RETAIN = 'retain';
var REMOVE = 'remove';
var INSERT = 'insert';

function optype(op) {
	if (typeof op === 'number') return RETAIN;
	if (op.i !== undefined) return INSERT;
	return REMOVE;
}

module.exports = function(model) {
	function create(data) {
		return data === undefined ? null : data;
	}

	function apply(snapshot, op) {
		return model.apply(snapshot, op);
	}

	function _slice(op, s, e) {
		if (typeof op === 'number') {
			//retain
			return (e === undefined ? op : e) - s;
		} else if (op.i !== undefined) {
			//insert
			if (typeof op.i === 'string')
				return {i:op.i.slice(s,e)};
			return op;
		} else {
			//delete
			if (typeof op.d === 'string')
				return {d:op.d.slice(s,e)};
			return op;
		}
	}

	function _type(op) {
		if (typeof op === 'number') return 'retain';
		if (typeof op.i === 'string') return 'insert';
		if (typeof op.d === 'string') return 'remove';
		return 'object';
	}

	function _push(ops, op) {
		if (ops.length > 0) {
			var nt = _type(op);
			var ot = _type(ops[ops.length - 1]);
			if (nt === ot && nt !== 'object') {
				var oop = ops.pop();
				switch(nt) {
					case 'retain':
						op = op + oop;
						break;
					case 'remove':
						op = {d:(oop.d + op.d)};
						break;
					case 'insert':
						op = {i:(oop.i + op.i)};
						break;
				}
			}
		}
		return ops.push(op);
	}

	function _n(op) {
		if (typeof op === 'number') return op;
		var str_or_obj = (op.i !== undefined) ? op.i : op.d;
		return (typeof str_or_obj === 'string') ? str_or_obj.length : 1;
	}

	function _makeTake(ops) {
		var offset = 0;
		var ia = 0;

		function take(n, indivisableField) {
			if (ia === ops.length)
				return n === -1 ? null : n;

			var part;
			var c = ops[ia];
			if (n === -1 || _n(c) - offset <= n ||
			   ((c.i !== undefined) && indivisableField === 'i') ||
			   ((c.d !== undefined) && indivisableField === 'd')) {
				part = _slice(c, offset);
				++ia;
				offset = 0;
				return part;
			} else {
				part = _slice(c, offset, offset + n);
				offset += n;
				return part;
			}
		}

		function peek() {
			return ops[ia];
		}

		return {
			take: take,
			peek: peek,
		};
	}

	function transform(op1, op2, side) {
		var left = side === 'left';
		var newOps = [];

		var chunk;
		var length;
		var opo;

		var tp = _makeTake(op1);
		var take = tp.take;
		var peek = tp.peek;

		for (var i = 0; i < op2.length; i++) {
			opo = op2[i];
			if (typeof opo === 'number') {
				length = opo;
				while (length > 0) {
					chunk = take(length, 'i'); // don't split insert
					_push(newOps, chunk); //append(chunk);
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.d !== undefined) {
						length -= (typeof chunk.d === 'string') ? chunk.d.length : 1;
					}
				}
			} else if (opo.i !== undefined) {
				if (left && (peek()).i !== undefined) {
					_push(newOps, take(-1)); //left insert goes first;
				}
				_push(newOps, (typeof opo.i === 'string') ? opo.i.length : 1); //skip the inserted text/obj
			} else if (opo.d !== undefined) {
				length = (typeof opo.d === 'string') ? opo.d.length : 1;
				while (length > 0) {
					chunk = take(length, 'i'); // don't split insert
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.i !== undefined) {
						_push(newOps, chunk);
					} else if (chunk.d !== undefined) {
						length -= (typeof chunk.d === 'string') ? chunk.d.length : 1;
					}
				}
			}
		}

		while ((chunk = take(-1)))
			_push(newOps, chunk);

		return newOps;
	}

	function compose(op1, op2) {
		//return ops
		var newOps = [];

		var chunk;
		var length;
		var opo;

		var tp = _makeTake(op1);
		var take = tp.take;
		var peek = tp.peek;

		for (var i = 0; i < op2.length; i++) {
			opo = op2[i];
			if (typeof opo === 'number') {
				length = opo;
				while (length > 0) {
					chunk = take(length, 'd'); // don't split delete
					_push(newOps, chunk); //append(chunk);
					//length -= targetLength
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.i !== undefined) {
						length -= (typeof chunk.i === 'string') ? chunk.i.length : 1;
					}
				}
			} else if (opo.i !== undefined) {
				_push(newOps, opo)
			} else if (opo.d !== undefined) {
				length = (typeof opo.d === 'string') ? opo.d.length : 1;
				var s = 0;
				while (length > 0) {
					chunk = take(length, 'd'); // don't split insert
					if (typeof chunk === 'number') {
						//append part of the delete...
						_push(newOps, _slice(opo, s, s + chunk));
						length -= chunk;
						s += chunk;
					} else if (chunk.i !== undefined) {
						var n = (typeof chunk.i === 'string') ? chunk.i.length : 1;
						length -= n;
						s += n;
					} else if (chunk.d !== undefined) {
						_push(newOps, chunk);
					}
				}
			}
		}

		while ((chunk = take(-1)))
			_push(newOps, chunk);

		return newOps;
	}

	function invert(ops) {
		return ops.map(_invert);
	}

	function _invert(op) {
		//return op^(-1) TODO
		if (typeof op === 'number') return op;
		if (op.i !== undefined) return {d:op.i};
		return {i:op.d}; //assuming delete
	}

	function serialize(snapshot)
	{
		return snapshot === null ? null : snapshot.toJSON();
	}

	function deserialize(data)
	{
		if (data === 'null') return null;
		return model.fromJSON(data);
	}

	function transformCursor(cursor, op, isOwnOp)
	{
		return model.transformCursor(cursor, op, isOwnOp);
	}

	return {
		name: 'slate0',
		uri: 'http://clay3.com/types/slatev0',
		create: create,
		apply: apply,
		transform: transform,
		compose: compose,
		invert: invert,
		serialize: serialize,
		deserialize: deserialize,
		transformCursor: transformCursor,
		optype: optype,
		optypes: {
			RETAIN: RETAIN,
			REMOVE: REMOVE,
			INSERT: INSERT
		}
	};
};<commit_msg>change create to accept JSON or string of JSON<commit_after>

//model must expose
//  .apply(doc, op) -> doc (where doc can be null)
//  .fromJSON(json) -> doc
//  .transformCursor(cursor, op, isOwnOp)
//
//  the doc must expose
//  .toJSON

// usage (client side)
// var sharejs = require('share').client;
// var slate_type = require('ot-slate0')(model);
// sharejs.registerType(slate_type);

// usage (server side)
// livedb.ot.registerType(slate_type);

//Operations

// number => retain
// {d:....} => remove
// {i:....} => insert

// .... can be string or object
var RETAIN = 'retain';
var REMOVE = 'remove';
var INSERT = 'insert';

function optype(op) {
	if (typeof op === 'number') return RETAIN;
	if (op.i !== undefined) return INSERT;
	return REMOVE;
}

module.exports = function(model) {
	function create(data) {
		if (typeof data === 'string') data = JSON.parse(data);
		return data === undefined ? null : deserialize(data); //just in case we are given JSON
	}

	function apply(snapshot, op) {
		return model.apply(snapshot, op);
	}

	function _slice(op, s, e) {
		if (typeof op === 'number') {
			//retain
			return (e === undefined ? op : e) - s;
		} else if (op.i !== undefined) {
			//insert
			if (typeof op.i === 'string')
				return {i:op.i.slice(s,e)};
			return op;
		} else {
			//delete
			if (typeof op.d === 'string')
				return {d:op.d.slice(s,e)};
			return op;
		}
	}

	function _type(op) {
		if (typeof op === 'number') return 'retain';
		if (typeof op.i === 'string') return 'insert';
		if (typeof op.d === 'string') return 'remove';
		return 'object';
	}

	function _push(ops, op) {
		if (ops.length > 0) {
			var nt = _type(op);
			var ot = _type(ops[ops.length - 1]);
			if (nt === ot && nt !== 'object') {
				var oop = ops.pop();
				switch(nt) {
					case 'retain':
						op = op + oop;
						break;
					case 'remove':
						op = {d:(oop.d + op.d)};
						break;
					case 'insert':
						op = {i:(oop.i + op.i)};
						break;
				}
			}
		}
		return ops.push(op);
	}

	function _n(op) {
		if (typeof op === 'number') return op;
		var str_or_obj = (op.i !== undefined) ? op.i : op.d;
		return (typeof str_or_obj === 'string') ? str_or_obj.length : 1;
	}

	function _makeTake(ops) {
		var offset = 0;
		var ia = 0;

		function take(n, indivisableField) {
			if (ia === ops.length)
				return n === -1 ? null : n;

			var part;
			var c = ops[ia];
			if (n === -1 || _n(c) - offset <= n ||
			   ((c.i !== undefined) && indivisableField === 'i') ||
			   ((c.d !== undefined) && indivisableField === 'd')) {
				part = _slice(c, offset);
				++ia;
				offset = 0;
				return part;
			} else {
				part = _slice(c, offset, offset + n);
				offset += n;
				return part;
			}
		}

		function peek() {
			return ops[ia];
		}

		return {
			take: take,
			peek: peek,
		};
	}

	function transform(op1, op2, side) {
		var left = side === 'left';
		var newOps = [];

		var chunk;
		var length;
		var opo;

		var tp = _makeTake(op1);
		var take = tp.take;
		var peek = tp.peek;

		for (var i = 0; i < op2.length; i++) {
			opo = op2[i];
			if (typeof opo === 'number') {
				length = opo;
				while (length > 0) {
					chunk = take(length, 'i'); // don't split insert
					_push(newOps, chunk); //append(chunk);
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.d !== undefined) {
						length -= (typeof chunk.d === 'string') ? chunk.d.length : 1;
					}
				}
			} else if (opo.i !== undefined) {
				if (left && (peek()).i !== undefined) {
					_push(newOps, take(-1)); //left insert goes first;
				}
				_push(newOps, (typeof opo.i === 'string') ? opo.i.length : 1); //skip the inserted text/obj
			} else if (opo.d !== undefined) {
				length = (typeof opo.d === 'string') ? opo.d.length : 1;
				while (length > 0) {
					chunk = take(length, 'i'); // don't split insert
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.i !== undefined) {
						_push(newOps, chunk);
					} else if (chunk.d !== undefined) {
						length -= (typeof chunk.d === 'string') ? chunk.d.length : 1;
					}
				}
			}
		}

		while ((chunk = take(-1)))
			_push(newOps, chunk);

		return newOps;
	}

	function compose(op1, op2) {
		//return ops
		var newOps = [];

		var chunk;
		var length;
		var opo;

		var tp = _makeTake(op1);
		var take = tp.take;
		var peek = tp.peek;

		for (var i = 0; i < op2.length; i++) {
			opo = op2[i];
			if (typeof opo === 'number') {
				length = opo;
				while (length > 0) {
					chunk = take(length, 'd'); // don't split delete
					_push(newOps, chunk); //append(chunk);
					//length -= targetLength
					if (typeof chunk === 'number') {
						length -= chunk;
					} else if (chunk.i !== undefined) {
						length -= (typeof chunk.i === 'string') ? chunk.i.length : 1;
					}
				}
			} else if (opo.i !== undefined) {
				_push(newOps, opo)
			} else if (opo.d !== undefined) {
				length = (typeof opo.d === 'string') ? opo.d.length : 1;
				var s = 0;
				while (length > 0) {
					chunk = take(length, 'd'); // don't split insert
					if (typeof chunk === 'number') {
						//append part of the delete...
						_push(newOps, _slice(opo, s, s + chunk));
						length -= chunk;
						s += chunk;
					} else if (chunk.i !== undefined) {
						var n = (typeof chunk.i === 'string') ? chunk.i.length : 1;
						length -= n;
						s += n;
					} else if (chunk.d !== undefined) {
						_push(newOps, chunk);
					}
				}
			}
		}

		while ((chunk = take(-1)))
			_push(newOps, chunk);

		return newOps;
	}

	function invert(ops) {
		return ops.map(_invert);
	}

	function _invert(op) {
		//return op^(-1) TODO
		if (typeof op === 'number') return op;
		if (op.i !== undefined) return {d:op.i};
		return {i:op.d}; //assuming delete
	}

	function serialize(snapshot)
	{
		return snapshot === null ? null : snapshot.toJSON();
	}

	function deserialize(data)
	{
		if (data === 'null') return null;
		return model.fromJSON(data);
	}

	function transformCursor(cursor, op, isOwnOp)
	{
		return model.transformCursor(cursor, op, isOwnOp);
	}

	return {
		name: 'slate0',
		uri: 'http://clay3.com/types/slatev0',
		create: create,
		apply: apply,
		transform: transform,
		compose: compose,
		invert: invert,
		serialize: serialize,
		deserialize: deserialize,
		transformCursor: transformCursor,
		optype: optype,
		optypes: {
			RETAIN: RETAIN,
			REMOVE: REMOVE,
			INSERT: INSERT
		}
	};
};<|endoftext|>