<commit_before>/*global namespace*/
(function () {
    var shim = namespace.shim;
    var bind = shim.bind;
    var forEach = shim.forEach;
    var filter = shim.filter;
    var map = shim.map;
    var trim = shim.trim;
    var reduce = shim.reduce;
    var getKeys = shim.getKeys;

    var utils = namespace.utils;
    var truncateStack = utils.truncateStack;
    var extend = utils.extend;
    var levenshteinDistance = utils.levenshteinDistance;
    var isArray = utils.isArray;

    function Assertion(expect, subject, testDescription, flags, args) {
        this.expect = expect;
        this.obj = subject; // deprecated
        this.equal = bind(expect.equal, expect); // deprecated
        this.eql = this.equal; // deprecated
        this.inspect = bind(expect.inspect, expect); // deprecated
        this.subject = subject;
        this.testDescription = testDescription;
        this.flags = flags;
        this.args = args;
        this.errorMode = 'default';
    }

    Assertion.prototype.standardErrorMessage = function () {
        var expect = this.expect;
        var argsString = map(this.args, function (arg) {
            return expect.inspect(arg);
        }).join(', ');

        if (argsString.length > 0) {
            argsString = ' ' + argsString;
        }

        return 'expected ' +
            expect.inspect(this.subject) +
            ' ' + this.testDescription +
            argsString;
    };

    Assertion.prototype.throwStandardError = function () {
        var err = new Error(this.standardErrorMessage());
        err._isUnexpected = true;
        throw err;
    };

    Assertion.prototype.assert = function (condition) {
        var not = !!this.flags.not;
        condition = !!condition;
        if (condition === not) {
            this.throwStandardError();
        }
    };

    function Unexpected(assertions, types) {
        this.assertions = assertions || {};
        this.types = types || [];
    }

    Unexpected.prototype.equal = function (actual, expected) {
        return namespace.equal(actual, expected, this.types);
    };

    Unexpected.prototype.inspect = function (obj) {
        return namespace.inspect(obj, false, 2, this.types);
    };

    Unexpected.prototype.format = function (message, args) {
        args = map(args, function (arg) {
            return this.inspect(arg);
        }, this);
        message = message.replace(/\{(\d+)\}/g, function (match, n) {
            return args[n] || match;
        });
        return message;
    };

    Unexpected.prototype.fail = function (message) {
        message = message || "explicit failure";
        var args = Array.prototype.slice.call(arguments, 1);
        throw new Error(this.format(message, args));
    };

    Unexpected.prototype.findAssertionSimilarTo = function (text) {
        var editDistrances = [];
        forEach(getKeys(this.assertions), function (assertion) {
            var distance = levenshteinDistance(text, assertion);
            editDistrances.push({
                assertion: assertion,
                distance: distance
            });
        });
        editDistrances.sort(function (x, y) {
            return x.distance - y.distance;
        });
        return map(editDistrances.slice(0, 5), function (editDistrance) {
            return editDistrance.assertion;
        });
    };

    Unexpected.prototype.addAssertion = function () {
        var assertions = this.assertions;
        var patterns = Array.prototype.slice.call(arguments, 0, -1);
        var handler = Array.prototype.slice.call(arguments, -1)[0];
        forEach(patterns, function (pattern) {
            ensureValidPattern(pattern);
            forEach(expandPattern(pattern), function (expandedPattern) {
                assertions[expandedPattern.text] = {
                    handler: handler,
                    flags: expandedPattern.flags
                };
            });
        });

        return this.expect; // for chaining
    };

    Unexpected.prototype.addType = function (obj) {
        this.types.unshift(obj);

        return this.expect;
    };

    Unexpected.prototype.installPlugin = function (plugin) {
        if (typeof plugin !== 'function') {
            throw new Error('Expected first argument given to installPlugin to be a function');
        }

        plugin(this.expect);

        return this.expect; // for chaining
    };

    Unexpected.prototype.sanitize = function (obj, stack) {
        stack = stack || [];

        var i;
        for (i = 0 ; i < stack.length ; i += 1) {
            if (stack[i] === obj) {
                return obj;
            }
        }

        var sanitized,
            matchingCustomType = utils.findFirst(this.types || [], function (type) {
                return type.identify(obj);
            });
        if (matchingCustomType) {
            stack.push(obj);
            sanitized = this.sanitize(matchingCustomType.toJSON(obj), stack);
            stack.pop();
            return sanitized;
        }
        if (isArray(obj)) {
            stack.push(obj);
            sanitized = map(obj, function (item) {
                return this.sanitize(item, stack);
            }, this);
            stack.pop();
        } else if (typeof obj === 'object' && obj) {
            stack.push(obj);
            sanitized = {};
            forEach(getKeys(obj).sort(), function (key) {
                sanitized[key] = this.sanitize(obj[key], stack);
            }, this);
            stack.pop();
        } else {
            sanitized = obj;
        }
        return sanitized;
    };

    function handleNestedExpects(e, assertion) {
        switch (assertion.errorMode) {
        case 'nested':
            e.message = assertion.standardErrorMessage() + '\n    ' + e.message.replace(/\n/g, '\n    ');
            break;
        case 'default':
            e.message = assertion.standardErrorMessage();
            break;
        case 'bubble':
            break;
        default:
            throw new Error("Unknown error mode: '" + assertion.errorMode + "'");
        }
    }

    function installExpectMethods(unexpected, expectFunction) {
        var expect = bind(expectFunction, unexpected);
        expect.equal = bind(unexpected.equal, unexpected);
        expect.sanitize = bind(unexpected.sanitize, unexpected);
        expect.inspect = bind(unexpected.inspect, unexpected);
        expect.fail = bind(unexpected.fail, unexpected);
        expect.addAssertion = bind(unexpected.addAssertion, unexpected);
        expect.addType = bind(unexpected.addType, unexpected);
        expect.clone = bind(unexpected.clone, unexpected);
        expect.toString = bind(unexpected.toString, unexpected);
        expect.assertions = unexpected.assertions;
        expect.installPlugin = bind(unexpected.installPlugin, unexpected);
        return expect;
    }

    function makeExpectFunction(unexpected) {
        var expect = installExpectMethods(unexpected, unexpected.expect);
        unexpected.expect = expect;
        return expect;
    }

    Unexpected.prototype.expect = function expect(subject, testDescriptionString) {
        var that = this;
        if (arguments.length < 2) {
            throw new Error('The expect functions requires at least two parameters.');
        }
        if (typeof testDescriptionString !== 'string') {
            throw new Error('The expect functions requires second parameter to be a string.');
        }
        var assertionRule = this.assertions[testDescriptionString];
        if (assertionRule) {
            var flags = extend({}, assertionRule.flags);
            var nestingLevel = 0;
            var wrappedExpect = function wrappedExpect(subject, testDescriptionString) {
                testDescriptionString = trim(testDescriptionString.replace(/\[(!?)([^\]]+)\] ?/g, function (match, negate, flag) {
                    negate = !!negate;
                    return flags[flag] !== negate ? flag + ' ' : '';
                }));

                var args = Array.prototype.slice.call(arguments, 2);
                nestingLevel += 1;
                try {
                    that.expect.apply(that, [subject, testDescriptionString].concat(args));
                    nestingLevel -= 1;
                } catch (e) {
                    nestingLevel -= 1;
                    if (e._isUnexpected) {
                        truncateStack(e, wrappedExpect);
                    }
                    if (nestingLevel === 0) {
                        handleNestedExpects(e, assertion);
                    }
                    throw e;
                }
            };

            // Not sure this is the right way to go about this:
            wrappedExpect.equal = this.equal;
            wrappedExpect.types = this.types;
            wrappedExpect.sanitize = this.sanitize;
            wrappedExpect.inspect = this.inspect;

            var args = Array.prototype.slice.call(arguments, 2);
            args.unshift(wrappedExpect, subject);
            var assertion = new Assertion(wrappedExpect, subject, testDescriptionString, flags, args.slice(2));
            var handler = assertionRule.handler;
            try {
                handler.apply(assertion, args);
            } catch (e) {
                if (e._isUnexpected) {
                    truncateStack(e, this.expect);
                }
                throw e;
            }
        } else {
            var similarAssertions = this.findAssertionSimilarTo(testDescriptionString);
            var message =
                'Unknown assertion "' + testDescriptionString + '", ' +
                'did you mean: "' + similarAssertions[0] + '"';
            var err = new Error(message);
            truncateStack(err, this.expect);
            throw err;
        }
    };

    Unexpected.prototype.toString = function () {
        return getKeys(this.assertions).sort().join('\n');
    };

    Unexpected.prototype.clone = function () {
        var unexpected = new Unexpected(extend({}, this.assertions), [].concat(this.types));
        return makeExpectFunction(unexpected);
    };

    Unexpected.create = function () {
        var unexpected = new Unexpected();
        return makeExpectFunction(unexpected);
    };

    var expandPattern = (function () {
        function isFlag(token) {
            return token.slice(0, 1) === '[' && token.slice(-1) === ']';
        }
        function isAlternation(token) {
            return token.slice(0, 1) === '(' && token.slice(-1) === ')';
        }
        function removeEmptyStrings(texts) {
            return filter(texts, function (text) {
                return text !== '';
            });
        }
        function createPermutations(tokens, index) {
            if (index === tokens.length) {
                return [{ text: '', flags: {}}];
            }

            var token = tokens[index];
            var tail = createPermutations(tokens, index + 1);
            if (isFlag(token)) {
                var flag = token.slice(1, -1);
                return map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = true;
                    return {
                        text: flag + ' ' + pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }).concat(map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = false;
                    return {
                        text: pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }));
            } else if (isAlternation(token)) {
                var alternations = token.split(/\(|\)|\|/);
                alternations = removeEmptyStrings(alternations);
                return reduce(alternations, function (result, alternation) {
                    return result.concat(map(tail, function (pattern) {
                        return {
                            text: alternation + pattern.text,
                            flags: pattern.flags
                        };
                    }));
                }, []);
            } else {
                return map(tail, function (pattern) {
                    return {
                        text: token + pattern.text,
                        flags: pattern.flags
                    };
                });
            }
        }
        return function (pattern) {
            pattern = pattern.replace(/(\[[^\]]+\]) ?/g, '$1');
            var splitRegex = /\[[^\]]+\]|\([^\)]+\)/g;
            var tokens = [];
            var m;
            var lastIndex = 0;
            while ((m = splitRegex.exec(pattern))) {
                tokens.push(pattern.slice(lastIndex, m.index));
                tokens.push(pattern.slice(m.index, splitRegex.lastIndex));
                lastIndex = splitRegex.lastIndex;
            }
            tokens.push(pattern.slice(lastIndex));

            tokens = removeEmptyStrings(tokens);
            var permutations = createPermutations(tokens, 0);
            forEach(permutations, function (permutation) {
                permutation.text = trim(permutation.text);
                if (permutation.text === '') {
                    // This can only happen if the pattern only contains flags
                    throw new Error("Assertion patterns must not only contain flags");
                }
            });
            return permutations;
        };
    }());

    function ensureValidUseOfParenthesesOrBrackets(pattern) {
        var counts = {
            '[': 0,
            ']': 0,
            '(': 0,
            ')': 0
        };
        for (var i = 0; i < pattern.length; i += 1) {
            var c = pattern.charAt(i);
            if (c in counts) {
                counts[c] += 1;
            }
            if (c === ']' && counts['['] >= counts[']']) {
                if (counts['['] === counts[']'] + 1) {
                    throw new Error("Assertion patterns must not contain flags with brackets: '" + pattern + "'");
                }

                if (counts['('] !== counts[')']) {
                    throw new Error("Assertion patterns must not contain flags with parentheses: '" + pattern + "'");
                }

                if (pattern.charAt(i - 1) === '[') {
                    throw new Error("Assertion patterns must not contain empty flags: '" + pattern + "'");
                }
            } else if (c === ')' && counts['('] >= counts[')']) {
                if (counts['('] === counts[')'] + 1) {
                    throw new Error("Assertion patterns must not contain alternations with parentheses: '" + pattern + "'");
                }

                if (counts['['] !== counts[']']) {
                    throw new Error("Assertion patterns must not contain alternations with brackets: '" + pattern + "'");
                }
            }

            if ((c === ')' || c === '|') && counts['('] >= counts[')']) {
                if (pattern.charAt(i - 1) === '(' || pattern.charAt(i - 1) === '|') {
                    throw new Error("Assertion patterns must not contain empty alternations: '" + pattern + "'");
                }
            }
        }

        if (counts['['] !== counts[']']) {
            throw new Error("Assertion patterns must not contain unbalanced brackets: '" + pattern + "'");
        }

        if (counts['('] !== counts[')']) {
            throw new Error("Assertion patterns must not contain unbalanced parentheses: '" + pattern + "'");
        }
    }

    function ensureValidPattern(pattern) {
        if (typeof pattern !== 'string' || pattern === '') {
            throw new Error("Assertion patterns must be a non empty string");
        }
        if (pattern.match(/^\s|\s$/)) {
            throw new Error("Assertion patterns can't start or end with whitespace");
        }

        ensureValidUseOfParenthesesOrBrackets(pattern);
    }

    namespace.expect = Unexpected.create();
}());
<commit_msg>sanitize: Moved stack.push/pop to the outer level.<commit_after>/*global namespace*/
(function () {
    var shim = namespace.shim;
    var bind = shim.bind;
    var forEach = shim.forEach;
    var filter = shim.filter;
    var map = shim.map;
    var trim = shim.trim;
    var reduce = shim.reduce;
    var getKeys = shim.getKeys;

    var utils = namespace.utils;
    var truncateStack = utils.truncateStack;
    var extend = utils.extend;
    var levenshteinDistance = utils.levenshteinDistance;
    var isArray = utils.isArray;

    function Assertion(expect, subject, testDescription, flags, args) {
        this.expect = expect;
        this.obj = subject; // deprecated
        this.equal = bind(expect.equal, expect); // deprecated
        this.eql = this.equal; // deprecated
        this.inspect = bind(expect.inspect, expect); // deprecated
        this.subject = subject;
        this.testDescription = testDescription;
        this.flags = flags;
        this.args = args;
        this.errorMode = 'default';
    }

    Assertion.prototype.standardErrorMessage = function () {
        var expect = this.expect;
        var argsString = map(this.args, function (arg) {
            return expect.inspect(arg);
        }).join(', ');

        if (argsString.length > 0) {
            argsString = ' ' + argsString;
        }

        return 'expected ' +
            expect.inspect(this.subject) +
            ' ' + this.testDescription +
            argsString;
    };

    Assertion.prototype.throwStandardError = function () {
        var err = new Error(this.standardErrorMessage());
        err._isUnexpected = true;
        throw err;
    };

    Assertion.prototype.assert = function (condition) {
        var not = !!this.flags.not;
        condition = !!condition;
        if (condition === not) {
            this.throwStandardError();
        }
    };

    function Unexpected(assertions, types) {
        this.assertions = assertions || {};
        this.types = types || [];
    }

    Unexpected.prototype.equal = function (actual, expected) {
        return namespace.equal(actual, expected, this.types);
    };

    Unexpected.prototype.inspect = function (obj) {
        return namespace.inspect(obj, false, 2, this.types);
    };

    Unexpected.prototype.format = function (message, args) {
        args = map(args, function (arg) {
            return this.inspect(arg);
        }, this);
        message = message.replace(/\{(\d+)\}/g, function (match, n) {
            return args[n] || match;
        });
        return message;
    };

    Unexpected.prototype.fail = function (message) {
        message = message || "explicit failure";
        var args = Array.prototype.slice.call(arguments, 1);
        throw new Error(this.format(message, args));
    };

    Unexpected.prototype.findAssertionSimilarTo = function (text) {
        var editDistrances = [];
        forEach(getKeys(this.assertions), function (assertion) {
            var distance = levenshteinDistance(text, assertion);
            editDistrances.push({
                assertion: assertion,
                distance: distance
            });
        });
        editDistrances.sort(function (x, y) {
            return x.distance - y.distance;
        });
        return map(editDistrances.slice(0, 5), function (editDistrance) {
            return editDistrance.assertion;
        });
    };

    Unexpected.prototype.addAssertion = function () {
        var assertions = this.assertions;
        var patterns = Array.prototype.slice.call(arguments, 0, -1);
        var handler = Array.prototype.slice.call(arguments, -1)[0];
        forEach(patterns, function (pattern) {
            ensureValidPattern(pattern);
            forEach(expandPattern(pattern), function (expandedPattern) {
                assertions[expandedPattern.text] = {
                    handler: handler,
                    flags: expandedPattern.flags
                };
            });
        });

        return this.expect; // for chaining
    };

    Unexpected.prototype.addType = function (obj) {
        this.types.unshift(obj);

        return this.expect;
    };

    Unexpected.prototype.installPlugin = function (plugin) {
        if (typeof plugin !== 'function') {
            throw new Error('Expected first argument given to installPlugin to be a function');
        }

        plugin(this.expect);

        return this.expect; // for chaining
    };

    Unexpected.prototype.sanitize = function (obj, stack) {
        stack = stack || [];

        var i;
        for (i = 0 ; i < stack.length ; i += 1) {
            if (stack[i] === obj) {
                return obj;
            }
        }

        stack.push(obj);

        var sanitized,
            matchingCustomType = utils.findFirst(this.types || [], function (type) {
                return type.identify(obj);
            });
        if (matchingCustomType) {
            sanitized = this.sanitize(matchingCustomType.toJSON(obj), stack);
        } else if (isArray(obj)) {
            sanitized = map(obj, function (item) {
                return this.sanitize(item, stack);
            }, this);
        } else if (typeof obj === 'object' && obj) {
            sanitized = {};
            forEach(getKeys(obj).sort(), function (key) {
                sanitized[key] = this.sanitize(obj[key], stack);
            }, this);
        } else {
            sanitized = obj;
        }
        stack.pop();
        return sanitized;
    };

    function handleNestedExpects(e, assertion) {
        switch (assertion.errorMode) {
        case 'nested':
            e.message = assertion.standardErrorMessage() + '\n    ' + e.message.replace(/\n/g, '\n    ');
            break;
        case 'default':
            e.message = assertion.standardErrorMessage();
            break;
        case 'bubble':
            break;
        default:
            throw new Error("Unknown error mode: '" + assertion.errorMode + "'");
        }
    }

    function installExpectMethods(unexpected, expectFunction) {
        var expect = bind(expectFunction, unexpected);
        expect.equal = bind(unexpected.equal, unexpected);
        expect.sanitize = bind(unexpected.sanitize, unexpected);
        expect.inspect = bind(unexpected.inspect, unexpected);
        expect.fail = bind(unexpected.fail, unexpected);
        expect.addAssertion = bind(unexpected.addAssertion, unexpected);
        expect.addType = bind(unexpected.addType, unexpected);
        expect.clone = bind(unexpected.clone, unexpected);
        expect.toString = bind(unexpected.toString, unexpected);
        expect.assertions = unexpected.assertions;
        expect.installPlugin = bind(unexpected.installPlugin, unexpected);
        return expect;
    }

    function makeExpectFunction(unexpected) {
        var expect = installExpectMethods(unexpected, unexpected.expect);
        unexpected.expect = expect;
        return expect;
    }

    Unexpected.prototype.expect = function expect(subject, testDescriptionString) {
        var that = this;
        if (arguments.length < 2) {
            throw new Error('The expect functions requires at least two parameters.');
        }
        if (typeof testDescriptionString !== 'string') {
            throw new Error('The expect functions requires second parameter to be a string.');
        }
        var assertionRule = this.assertions[testDescriptionString];
        if (assertionRule) {
            var flags = extend({}, assertionRule.flags);
            var nestingLevel = 0;
            var wrappedExpect = function wrappedExpect(subject, testDescriptionString) {
                testDescriptionString = trim(testDescriptionString.replace(/\[(!?)([^\]]+)\] ?/g, function (match, negate, flag) {
                    negate = !!negate;
                    return flags[flag] !== negate ? flag + ' ' : '';
                }));

                var args = Array.prototype.slice.call(arguments, 2);
                nestingLevel += 1;
                try {
                    that.expect.apply(that, [subject, testDescriptionString].concat(args));
                    nestingLevel -= 1;
                } catch (e) {
                    nestingLevel -= 1;
                    if (e._isUnexpected) {
                        truncateStack(e, wrappedExpect);
                    }
                    if (nestingLevel === 0) {
                        handleNestedExpects(e, assertion);
                    }
                    throw e;
                }
            };

            // Not sure this is the right way to go about this:
            wrappedExpect.equal = this.equal;
            wrappedExpect.types = this.types;
            wrappedExpect.sanitize = this.sanitize;
            wrappedExpect.inspect = this.inspect;

            var args = Array.prototype.slice.call(arguments, 2);
            args.unshift(wrappedExpect, subject);
            var assertion = new Assertion(wrappedExpect, subject, testDescriptionString, flags, args.slice(2));
            var handler = assertionRule.handler;
            try {
                handler.apply(assertion, args);
            } catch (e) {
                if (e._isUnexpected) {
                    truncateStack(e, this.expect);
                }
                throw e;
            }
        } else {
            var similarAssertions = this.findAssertionSimilarTo(testDescriptionString);
            var message =
                'Unknown assertion "' + testDescriptionString + '", ' +
                'did you mean: "' + similarAssertions[0] + '"';
            var err = new Error(message);
            truncateStack(err, this.expect);
            throw err;
        }
    };

    Unexpected.prototype.toString = function () {
        return getKeys(this.assertions).sort().join('\n');
    };

    Unexpected.prototype.clone = function () {
        var unexpected = new Unexpected(extend({}, this.assertions), [].concat(this.types));
        return makeExpectFunction(unexpected);
    };

    Unexpected.create = function () {
        var unexpected = new Unexpected();
        return makeExpectFunction(unexpected);
    };

    var expandPattern = (function () {
        function isFlag(token) {
            return token.slice(0, 1) === '[' && token.slice(-1) === ']';
        }
        function isAlternation(token) {
            return token.slice(0, 1) === '(' && token.slice(-1) === ')';
        }
        function removeEmptyStrings(texts) {
            return filter(texts, function (text) {
                return text !== '';
            });
        }
        function createPermutations(tokens, index) {
            if (index === tokens.length) {
                return [{ text: '', flags: {}}];
            }

            var token = tokens[index];
            var tail = createPermutations(tokens, index + 1);
            if (isFlag(token)) {
                var flag = token.slice(1, -1);
                return map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = true;
                    return {
                        text: flag + ' ' + pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }).concat(map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = false;
                    return {
                        text: pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }));
            } else if (isAlternation(token)) {
                var alternations = token.split(/\(|\)|\|/);
                alternations = removeEmptyStrings(alternations);
                return reduce(alternations, function (result, alternation) {
                    return result.concat(map(tail, function (pattern) {
                        return {
                            text: alternation + pattern.text,
                            flags: pattern.flags
                        };
                    }));
                }, []);
            } else {
                return map(tail, function (pattern) {
                    return {
                        text: token + pattern.text,
                        flags: pattern.flags
                    };
                });
            }
        }
        return function (pattern) {
            pattern = pattern.replace(/(\[[^\]]+\]) ?/g, '$1');
            var splitRegex = /\[[^\]]+\]|\([^\)]+\)/g;
            var tokens = [];
            var m;
            var lastIndex = 0;
            while ((m = splitRegex.exec(pattern))) {
                tokens.push(pattern.slice(lastIndex, m.index));
                tokens.push(pattern.slice(m.index, splitRegex.lastIndex));
                lastIndex = splitRegex.lastIndex;
            }
            tokens.push(pattern.slice(lastIndex));

            tokens = removeEmptyStrings(tokens);
            var permutations = createPermutations(tokens, 0);
            forEach(permutations, function (permutation) {
                permutation.text = trim(permutation.text);
                if (permutation.text === '') {
                    // This can only happen if the pattern only contains flags
                    throw new Error("Assertion patterns must not only contain flags");
                }
            });
            return permutations;
        };
    }());

    function ensureValidUseOfParenthesesOrBrackets(pattern) {
        var counts = {
            '[': 0,
            ']': 0,
            '(': 0,
            ')': 0
        };
        for (var i = 0; i < pattern.length; i += 1) {
            var c = pattern.charAt(i);
            if (c in counts) {
                counts[c] += 1;
            }
            if (c === ']' && counts['['] >= counts[']']) {
                if (counts['['] === counts[']'] + 1) {
                    throw new Error("Assertion patterns must not contain flags with brackets: '" + pattern + "'");
                }

                if (counts['('] !== counts[')']) {
                    throw new Error("Assertion patterns must not contain flags with parentheses: '" + pattern + "'");
                }

                if (pattern.charAt(i - 1) === '[') {
                    throw new Error("Assertion patterns must not contain empty flags: '" + pattern + "'");
                }
            } else if (c === ')' && counts['('] >= counts[')']) {
                if (counts['('] === counts[')'] + 1) {
                    throw new Error("Assertion patterns must not contain alternations with parentheses: '" + pattern + "'");
                }

                if (counts['['] !== counts[']']) {
                    throw new Error("Assertion patterns must not contain alternations with brackets: '" + pattern + "'");
                }
            }

            if ((c === ')' || c === '|') && counts['('] >= counts[')']) {
                if (pattern.charAt(i - 1) === '(' || pattern.charAt(i - 1) === '|') {
                    throw new Error("Assertion patterns must not contain empty alternations: '" + pattern + "'");
                }
            }
        }

        if (counts['['] !== counts[']']) {
            throw new Error("Assertion patterns must not contain unbalanced brackets: '" + pattern + "'");
        }

        if (counts['('] !== counts[')']) {
            throw new Error("Assertion patterns must not contain unbalanced parentheses: '" + pattern + "'");
        }
    }

    function ensureValidPattern(pattern) {
        if (typeof pattern !== 'string' || pattern === '') {
            throw new Error("Assertion patterns must be a non empty string");
        }
        if (pattern.match(/^\s|\s$/)) {
            throw new Error("Assertion patterns can't start or end with whitespace");
        }

        ensureValidUseOfParenthesesOrBrackets(pattern);
    }

    namespace.expect = Unexpected.create();
}());
<|endoftext|>


<commit_before>
exports = module.exports = lifecycle
exports.cmd = cmd

var log = require("./log.js")
  , exec = require("./exec.js")
  , npm = require("../../npm.js")
  , path = require("path")
  , readJson = require("./read-json.js")
  , fs = require("graceful-fs")
  , chain = require("slide").chain
  , constants = require("constants")
  , output = require("./output.js")

function lifecycle (pkg, stage, wd, unsafe, cb) {
  if (typeof cb !== "function") cb = unsafe, unsafe = false
  if (typeof cb !== "function") cb = wd, wd = null

  while (pkg && pkg._data) pkg = pkg._data
  if (!pkg) return cb(new Error("Invalid package data"))

  log(pkg._id, stage)
  if (!pkg.scripts) pkg.scripts = {}

  validWd(wd || path.resolve(npm.dir, pkg.name), function (er, wd) {
    if (er) return cb(er)

    unsafe = unsafe || npm.config.get("unsafe-perm")

    if ((wd.indexOf(npm.dir) !== 0 || path.basename(wd) !== pkg.name)
        && !unsafe && pkg.scripts[stage]) {
      log.warn(pkg._id+" "+pkg.scripts[stage], "skipping, cannot run in "+wd)
      return cb()
    }

    // set the env variables, then run scripts as a child process.
    var env = makeEnv(pkg)
    env.npm_lifecycle_event = stage

    // "nobody" typically doesn't have permission to write to /tmp
    // even if it's never used, sh freaks out.
    if (!npm.config.get("unsafe-perm")) env.TMPDIR = wd

    lifecycle_(pkg, stage, wd, env, unsafe, cb)
  })
}

function checkForLink (pkg, cb) {
  var f = path.join(npm.dir, pkg.name)
  fs.lstat(f, function (er, s) {
    cb(null, !(er || !s.isSymbolicLink()))
  })
}

function lifecycle_ (pkg, stage, wd, env, unsafe, cb) {
  var PATH = []
    , p = wd.split("node_modules")
    , acc = path.resolve(p.shift())
  p.forEach(function (pp) {
    PATH.unshift(path.join(acc, "node_modules", ".bin"))
    acc = path.join(acc, "node_modules", pp)
  })
  PATH.unshift(path.join(acc, "node_modules", ".bin"))
  if (env.PATH) PATH.push(env.PATH)
  env.PATH = PATH.join(process.platform === "win32" ? ";" : ":")

  var packageLifecycle = pkg.scripts && pkg.scripts.hasOwnProperty(stage)

  if (packageLifecycle) {
    // define this here so it's available to all scripts.
    env.npm_lifecycle_script = pkg.scripts[stage]
  }

  if (npm.config.get("force")) cb = (function (cb_) { return function (er) {
    if (er) log(er, "forced, continuing")
    cb_()
  }})(cb)

  chain
    ( [ packageLifecycle && [runPackageLifecycle, pkg, env, wd, unsafe]
      , [runHookLifecycle, pkg, env, wd, unsafe] ]
    , cb )
}

function validWd (d, cb) {
  fs.stat(d, function (er, st) {
    if (er || !st.isDirectory()) {
      var p = path.dirname(d)
      if (p === d) {
        return cb(new Error("Could not find suitable wd"))
      }
      return validWd(p, cb)
    }
    return cb(null, d)
  })
}

function runPackageLifecycle (pkg, env, wd, unsafe, cb) {
  // run package lifecycle scripts in the package root, or the nearest parent.
  var stage = env.npm_lifecycle_event
    , user = unsafe ? null : npm.config.get("user")
    , group = unsafe ? null : npm.config.get("group")
    , cmd = env.npm_lifecycle_script
    , sh = "sh"
    , shFlag = "-c"

  if (process.platform === "win32") {
    sh = "cmd"
    shFlag = "/C"
  }

  log.verbose(unsafe, "unsafe-perm in lifecycle")

  output.write("\n> "+pkg._id+" " + stage+" "+wd+"\n> "+cmd+"\n", function (er) {
    if (er) return cb(er)

    exec( sh, [shFlag, cmd], env, true, wd
        , user, group
        , function (er, code, stdout, stderr) {
      if (er && !npm.ROLLBACK) {
        log("Failed to exec "+stage+" script", pkg._id)
        er.message = pkg._id + " "
                   + stage + ": `" + env.npm_lifecycle_script+"`\n"
                   + er.message
        if (er.errno !== constants.EPERM) {
          er.errno = npm.ELIFECYCLE
        }
        er.pkgid = pkg._id
        er.stage = stage
        er.script = env.npm_lifecycle_script
        er.pkgname = pkg.name
        return cb(er)
      } else if (er) {
        log.error(er, pkg._id+"."+stage)
        log.error("failed, but continuing anyway", pkg._id+"."+stage)
        return cb()
      }
      cb(er)
    })
  })
}

function runHookLifecycle (pkg, env, wd, unsafe, cb) {
  // check for a hook script, run if present.
  var stage = env.npm_lifecycle_event
    , hook = path.join(npm.dir, ".hooks", stage)
    , user = unsafe ? null : npm.config.get("user")
    , group = unsafe ? null : npm.config.get("group")
    , cmd = hook

  fs.stat(hook, function (er) {
    if (er) return cb()

    exec( "sh", ["-c", cmd], env, true, wd
        , user, group
        , function (er) {
      if (er) {
        er.message += "\nFailed to exec "+stage+" hook script"
        log(er, pkg._id)
      }
      if (npm.ROLLBACK) return cb()
      cb(er)
    })
  })
}

function makeEnv (data, prefix, env) {
  prefix = prefix || "npm_package_"
  if (!env) {
    env = {}
    for (var i in process.env) if (!i.match(/^npm_/)) {
      env[i] = process.env[i]
    }

    // npat asks for tap output
    if (npm.config.get("npat")) env.TAP = 1

    // express and others respect the NODE_ENV value.
    if (npm.config.get("production")) env.NODE_ENV = "production"

  } else if (!data.hasOwnProperty("_lifecycleEnv")) {
    Object.defineProperty(data, "_lifecycleEnv",
      { value : env
      , enumerable : false
      })
  }

  for (var i in data) if (i.charAt(0) !== "_") {
    var envKey = (prefix+i).replace(/[^a-zA-Z0-9_]/g, '_')
    if (data[i] && typeof(data[i]) === "object") {
      try {
        // quick and dirty detection for cyclical structures
        JSON.stringify(data[i])
        makeEnv(data[i], envKey+"_", env)
      } catch (ex) {
        // usually these are package objects.
        // just get the path and basic details.
        var d = data[i]
        makeEnv( { name: d.name, version: d.version, path:d.path }
               , envKey+"_", env)
      }
    } else {
      env[envKey] = String(data[i])
    }
  }

  if (prefix !== "npm_package_") return env

  prefix = "npm_config_"
  var pkgConfig = {}
    , ini = require("./ini.js")
    , keys = ini.keys
    , pkgVerConfig = {}
    , namePref = data.name + ":"
    , verPref = data.name + "@" + data.version + ":"

  keys.forEach(function (i) {
    if (i.charAt(0) === "_" && i.indexOf("_"+namePref) !== 0) {
      return
    }
    var value = String(ini.get(i))
    i = i.replace(/^_+/, "")
    if (i.indexOf(namePref) === 0) {
      var k = i.substr(namePref.length).replace(/[^a-zA-Z0-9_]/g, "_")
      pkgConfig[ k ] = value
    } else if (i.indexOf(verPref) === 0) {
      var k = i.substr(verPref.length).replace(/[^a-zA-Z0-9_]/g, "_")
      pkgVerConfig[ k ] = value
    }
    var envKey = (prefix+i).replace(/[^a-zA-Z0-9_]/g, "_")
    env[envKey] = value
  })

  prefix = "npm_package_config_"
  ;[pkgConfig, pkgVerConfig].forEach(function (conf) {
    for (var i in conf) {
      var envKey = (prefix+i)
      env[envKey] = conf[i]
    }
  })

  return env
}

function cmd (stage) {
  function CMD (args, cb) {
    if (args.length) {
      chain(args.map(function (p) {
        return [npm.commands, "run-script", [p, stage]]
      }), cb)
    } else npm.commands["run-script"]([stage], cb)
 }
  CMD.usage = "npm "+stage+" <name>"
  var installedShallow = require("./completion/installed-shallow.js")
  CMD.completion = function (opts, cb) {
    installedShallow(opts, function (d) {
      return d.scripts && d.scripts[stage]
    }, cb)
  }
  return CMD
}
<commit_msg>cmd /c flag not case sensitive<commit_after>
exports = module.exports = lifecycle
exports.cmd = cmd

var log = require("./log.js")
  , exec = require("./exec.js")
  , npm = require("../../npm.js")
  , path = require("path")
  , readJson = require("./read-json.js")
  , fs = require("graceful-fs")
  , chain = require("slide").chain
  , constants = require("constants")
  , output = require("./output.js")

function lifecycle (pkg, stage, wd, unsafe, cb) {
  if (typeof cb !== "function") cb = unsafe, unsafe = false
  if (typeof cb !== "function") cb = wd, wd = null

  while (pkg && pkg._data) pkg = pkg._data
  if (!pkg) return cb(new Error("Invalid package data"))

  log(pkg._id, stage)
  if (!pkg.scripts) pkg.scripts = {}

  validWd(wd || path.resolve(npm.dir, pkg.name), function (er, wd) {
    if (er) return cb(er)

    unsafe = unsafe || npm.config.get("unsafe-perm")

    if ((wd.indexOf(npm.dir) !== 0 || path.basename(wd) !== pkg.name)
        && !unsafe && pkg.scripts[stage]) {
      log.warn(pkg._id+" "+pkg.scripts[stage], "skipping, cannot run in "+wd)
      return cb()
    }

    // set the env variables, then run scripts as a child process.
    var env = makeEnv(pkg)
    env.npm_lifecycle_event = stage

    // "nobody" typically doesn't have permission to write to /tmp
    // even if it's never used, sh freaks out.
    if (!npm.config.get("unsafe-perm")) env.TMPDIR = wd

    lifecycle_(pkg, stage, wd, env, unsafe, cb)
  })
}

function checkForLink (pkg, cb) {
  var f = path.join(npm.dir, pkg.name)
  fs.lstat(f, function (er, s) {
    cb(null, !(er || !s.isSymbolicLink()))
  })
}

function lifecycle_ (pkg, stage, wd, env, unsafe, cb) {
  var PATH = []
    , p = wd.split("node_modules")
    , acc = path.resolve(p.shift())
  p.forEach(function (pp) {
    PATH.unshift(path.join(acc, "node_modules", ".bin"))
    acc = path.join(acc, "node_modules", pp)
  })
  PATH.unshift(path.join(acc, "node_modules", ".bin"))
  if (env.PATH) PATH.push(env.PATH)
  env.PATH = PATH.join(process.platform === "win32" ? ";" : ":")

  var packageLifecycle = pkg.scripts && pkg.scripts.hasOwnProperty(stage)

  if (packageLifecycle) {
    // define this here so it's available to all scripts.
    env.npm_lifecycle_script = pkg.scripts[stage]
  }

  if (npm.config.get("force")) cb = (function (cb_) { return function (er) {
    if (er) log(er, "forced, continuing")
    cb_()
  }})(cb)

  chain
    ( [ packageLifecycle && [runPackageLifecycle, pkg, env, wd, unsafe]
      , [runHookLifecycle, pkg, env, wd, unsafe] ]
    , cb )
}

function validWd (d, cb) {
  fs.stat(d, function (er, st) {
    if (er || !st.isDirectory()) {
      var p = path.dirname(d)
      if (p === d) {
        return cb(new Error("Could not find suitable wd"))
      }
      return validWd(p, cb)
    }
    return cb(null, d)
  })
}

function runPackageLifecycle (pkg, env, wd, unsafe, cb) {
  // run package lifecycle scripts in the package root, or the nearest parent.
  var stage = env.npm_lifecycle_event
    , user = unsafe ? null : npm.config.get("user")
    , group = unsafe ? null : npm.config.get("group")
    , cmd = env.npm_lifecycle_script
    , sh = "sh"
    , shFlag = "-c"

  if (process.platform === "win32") {
    sh = "cmd"
    shFlag = "/c"
  }

  log.verbose(unsafe, "unsafe-perm in lifecycle")

  output.write("\n> "+pkg._id+" " + stage+" "+wd+"\n> "+cmd+"\n", function (er) {
    if (er) return cb(er)

    exec( sh, [shFlag, cmd], env, true, wd
        , user, group
        , function (er, code, stdout, stderr) {
      if (er && !npm.ROLLBACK) {
        log("Failed to exec "+stage+" script", pkg._id)
        er.message = pkg._id + " "
                   + stage + ": `" + env.npm_lifecycle_script+"`\n"
                   + er.message
        if (er.errno !== constants.EPERM) {
          er.errno = npm.ELIFECYCLE
        }
        er.pkgid = pkg._id
        er.stage = stage
        er.script = env.npm_lifecycle_script
        er.pkgname = pkg.name
        return cb(er)
      } else if (er) {
        log.error(er, pkg._id+"."+stage)
        log.error("failed, but continuing anyway", pkg._id+"."+stage)
        return cb()
      }
      cb(er)
    })
  })
}

function runHookLifecycle (pkg, env, wd, unsafe, cb) {
  // check for a hook script, run if present.
  var stage = env.npm_lifecycle_event
    , hook = path.join(npm.dir, ".hooks", stage)
    , user = unsafe ? null : npm.config.get("user")
    , group = unsafe ? null : npm.config.get("group")
    , cmd = hook

  fs.stat(hook, function (er) {
    if (er) return cb()

    exec( "sh", ["-c", cmd], env, true, wd
        , user, group
        , function (er) {
      if (er) {
        er.message += "\nFailed to exec "+stage+" hook script"
        log(er, pkg._id)
      }
      if (npm.ROLLBACK) return cb()
      cb(er)
    })
  })
}

function makeEnv (data, prefix, env) {
  prefix = prefix || "npm_package_"
  if (!env) {
    env = {}
    for (var i in process.env) if (!i.match(/^npm_/)) {
      env[i] = process.env[i]
    }

    // npat asks for tap output
    if (npm.config.get("npat")) env.TAP = 1

    // express and others respect the NODE_ENV value.
    if (npm.config.get("production")) env.NODE_ENV = "production"

  } else if (!data.hasOwnProperty("_lifecycleEnv")) {
    Object.defineProperty(data, "_lifecycleEnv",
      { value : env
      , enumerable : false
      })
  }

  for (var i in data) if (i.charAt(0) !== "_") {
    var envKey = (prefix+i).replace(/[^a-zA-Z0-9_]/g, '_')
    if (data[i] && typeof(data[i]) === "object") {
      try {
        // quick and dirty detection for cyclical structures
        JSON.stringify(data[i])
        makeEnv(data[i], envKey+"_", env)
      } catch (ex) {
        // usually these are package objects.
        // just get the path and basic details.
        var d = data[i]
        makeEnv( { name: d.name, version: d.version, path:d.path }
               , envKey+"_", env)
      }
    } else {
      env[envKey] = String(data[i])
    }
  }

  if (prefix !== "npm_package_") return env

  prefix = "npm_config_"
  var pkgConfig = {}
    , ini = require("./ini.js")
    , keys = ini.keys
    , pkgVerConfig = {}
    , namePref = data.name + ":"
    , verPref = data.name + "@" + data.version + ":"

  keys.forEach(function (i) {
    if (i.charAt(0) === "_" && i.indexOf("_"+namePref) !== 0) {
      return
    }
    var value = String(ini.get(i))
    i = i.replace(/^_+/, "")
    if (i.indexOf(namePref) === 0) {
      var k = i.substr(namePref.length).replace(/[^a-zA-Z0-9_]/g, "_")
      pkgConfig[ k ] = value
    } else if (i.indexOf(verPref) === 0) {
      var k = i.substr(verPref.length).replace(/[^a-zA-Z0-9_]/g, "_")
      pkgVerConfig[ k ] = value
    }
    var envKey = (prefix+i).replace(/[^a-zA-Z0-9_]/g, "_")
    env[envKey] = value
  })

  prefix = "npm_package_config_"
  ;[pkgConfig, pkgVerConfig].forEach(function (conf) {
    for (var i in conf) {
      var envKey = (prefix+i)
      env[envKey] = conf[i]
    }
  })

  return env
}

function cmd (stage) {
  function CMD (args, cb) {
    if (args.length) {
      chain(args.map(function (p) {
        return [npm.commands, "run-script", [p, stage]]
      }), cb)
    } else npm.commands["run-script"]([stage], cb)
 }
  CMD.usage = "npm "+stage+" <name>"
  var installedShallow = require("./completion/installed-shallow.js")
  CMD.completion = function (opts, cb) {
    installedShallow(opts, function (d) {
      return d.scripts && d.scripts[stage]
    }, cb)
  }
  return CMD
}
<|endoftext|>


<commit_before>
module.exports = readJson
readJson.processJson = processJson
readJson.unParsePeople = unParsePeople
readJson.parsePeople = parsePeople

var fs = require("./graceful-fs")
  , semver = require("semver")
  , path = require("path")
  , log = require("./log")
  , npm = require("../../npm")
  , cache = {}
  , timers = {}
  , loadPackageDefaults = require("./load-package-defaults")

function readJson (jsonFile, opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (cache.hasOwnProperty(jsonFile)) {
    log.verbose(jsonFile, "from cache")
    return cb(null, cache[jsonFile])
  }
  opts.file = jsonFile
  if (!opts.tag) {
    var parsedPath = jsonFile.indexOf(npm.dir) === 0 && jsonFile.match(
      /\/([^\/]+)\/([^\/]+)\/package\/package\.json$/)
    if (parsedPath && semver.valid(parsedPath[2])) {
      // this is a package.json in some installed package.
      // infer the opts.tag so that linked packages behave right.
      opts.tag = parsedPath[2]
    }
  }

  fs.readFile( path.join(path.dirname(jsonFile), "wscript")
             , function (er, data) {
    if (er) opts.wscript = false
    else opts.wscript = data.toString().match(/(^|\n)def build\b/)
                      && data.toString().match(/(^|\n)def configure\b/)
    fs.readFile(jsonFile, processJson(opts, function (er, data) {
      if (er) return cb(er)
      var doLoad = !(jsonFile.indexOf(npm.cache) === 0 &&
                     path.basename(path.dirname(jsonFile)) !== "package")
      if (!doLoad) return cb(er, data)
      loadPackageDefaults(data, path.dirname(jsonFile), cb)
    }))
  })
}
function processJson (opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (typeof cb !== "function") {
    var thing = cb, cb = null
    return P(null, thing)
  } else return P

  function P (er, thing) {
    if (er) {
      if (cb) return cb(er, thing)
      throw er
    }
    if (typeof thing === "object" && !Buffer.isBuffer(thing)) {
      return processObject(opts, cb)(er, thing)
    } else {
      return processJsonString(opts, cb)(er, thing)
    }
  }
}
function processJsonString (opts, cb) { return function (er, jsonString) {
  jsonString += ""
  if (er) return cb(er, jsonString)
  var json
  try {
    json = JSON.parse(jsonString)
  } catch (ex2) { try {
    json = process.binding("evals").Script.runInNewContext(
      "(\n"+jsonString+"\n)")
  } catch (ex) {
    var e = new Error(
      "Failed to parse json\n"+ex.message+"\n"+ex2.message+"\n"+jsonString)
    if (cb) return cb(e)
    throw e
  }}
  return processObject(opts, cb)(er, json)
}}
function processObject (opts, cb) { return function (er, json) {
  if (json.overlay) {
    ;["node", "npm"].forEach(function (k) {
      if (!json.overlay[k]) return undefined
      for (var i in json.overlay[k]) json[i] = json.overlay[k][i]
    })
  }

  // slashes would be a security risk.
  // anything else will just fail harmlessly.
  if (!json.name) {
    var e = new Error("No 'name' field found in package.json")
    if (cb) return cb(e)
    throw e
  }
  json.name = json.name.trim()
  if (json.name.charAt(0) === "." || json.name.match(/[\/@\s\+%:]/)) {
    var msg = "Invalid name: "
            + JSON.stringify(json.name)
            + " may not start with '.' or contain %/@+: or whitespace"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name.toLowerCase() === "node_modules") {
    var msg = "Invalid package name: node_modules"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name.toLowerCase() === "favicon.ico") {
    var msg = "Sorry, favicon.ico is a picture, not a package."
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }

  if (json.repostories) {
    var msg = "'repositories' (plural) No longer supported.\n"
            + "Please pick one, and put it in the 'repository' field."
      , e = new Error(msg)
    // uncomment once this is no longer an issue.
    // if (cb) return cb(e)
    // throw e
    log.error(msg, "incorrect json")
    json.repostory = json.repositories[0]
    delete json.repositories
  }

  if (json.repository) {
    if (typeof json.repository === "string") {
      json.repository = { type : "git"
                        , url : json.repository }
    }
    var repo = json.repository.url
    repo = repo.replace(/^(https?|git):\/\/[^\@]+\@github.com/
                       ,'$1://github.com')
    if (json.repository.type === "git"
        && ( repo.match(/^https?:\/\/github.com/)
          || repo.match(/github.com\/[^\/]+\/[^\/]+\/?$/)
             && !repo.match(/\.git$/)
        )) {
      var msg = "Please use the 'git://github.com/user/project.git'\n"
              + "format for github repository URLs."
        , e = new Error(msg)
      // later: uncomment this
      // if (cb) return cb(e)
      // throw e
      log.error(msg, "incorrect json "+json._id)
      repo = repo.replace(/^https?:\/\/github.com/, 'git://github.com')
      if (!repo.match(/\.git$/)) {
        repo = repo
               .replace(/^(https?|git):\/\/github.com\/([^\/]+)\/([^\/]+)\/?$/
                       ,'git://github.com/$2/$3.git')
      }
    }
    if (repo.match(/github\.com\/[^\/]+\/[^\/]+\/?$/)
        && repo.match(/\.git\.git$/)) {
      log.win(repo, "Are you sure this is right?")
    }
    json.repository.url = repo
  }

  var tag = opts.tag
  if (tag) json.version = tag//+"-"+json.version

  if (json.modules) {
    if (typeof json.modules !== "object") {
      var e = new Error("Invalid modules object")
      if (cb) return cb(e)
      throw e
    }
    Object.keys(json.modules).forEach(function (mod) {
      if (typeof json.modules[mod] !== "string") {
        var e = new Error("Invalid module "+mod+", not a string: "
                         +JSON.stringify(json.modules[mod]))
        if (cb) return cb(e)
        throw e
      }
    })
  }

  if (opts.wscript) {
    var scripts = json.scripts = json.scripts || {}
    if (!scripts.install && !scripts.preinstall) {
      // don't fail if it was unexpected, just try.
      scripts.preinstall = "node-waf clean || true; node-waf configure build"
    }
  }

  if (!(semver.valid(json.version))) {
    var e = new Error("Invalid version: "+json.version+"\n"
                     +"Must be X.Y.Z, with an optional trailing tag.\n"
                     +"See the section on 'version' in `npm help json`")
    if (cb) return cb(e)
    throw e
  }
  json.version = semver.clean(json.version)

  if (json.bin && typeof json.bin === "string") {
    var b = {}
    b[ path.basename( json.bin ) ] = json.bin
    json.bin = b
  }

  if (json["dev-dependencies"] && !json.devDependencies) {
    json.devDependencies = json["dev-dependencies"]
    delete json["dev-dependencies"]
  }
  ;["dependencies", "devDependencies"].forEach(function (d) {
    if (!json[d]) return
    json[d] = depObjectify(json[d])
  })

  json._id = json.name+"@"+json.version
  json = testEngine(json)
  json = parsePeople(unParsePeople(json))
  if ( json.bugs ) json.bugs = parsePerson(unParsePerson(json.bugs))
  json._npmVersion = npm.version
  json._nodeVersion = process.version
  if (opts.file) {
    log.verbose(opts.file, "caching")
    cache[opts.file] = json
    // arbitrary
    var keys = Object.keys(cache)
      , l = keys.length
    if (l > 10000) for (var i = 0; i < l - 5000; i ++) {
      delete cache[keys[i]]
    }
  }
  if (cb) cb(null,json)
  return json
}}
function depObjectify (deps) {
  if (!Array.isArray(deps)) return deps
  var o = {}
  deps.forEach(function (d) {
    d = d.trim().split(/(:?[@\s><=])/)
    o[d.shift()] = d.join("").trim().replace(/^@/, "")
  })
  return o
}
function testEngine (json) {
  // if engines is empty, then assume that node is allowed.
  log.silly(json, "testEngine")
  if ( !json.engines
      || Array.isArray(json.engines)
        && !json.engines.length
      || typeof json.engines === "object"
        && !Object.keys(json.engines).length
      ) {
    json.engines = { "node" : "*" }
  }
  if (typeof json.engines === "string") {
    if (semver.validRange(json.engines) !== null) {
      json.engines = { "node" : json.engines }
    } else json.engines = [ json.engines ]
  }

  var nodeVer = npm.config.get("node-version")
    , ok = false
  if (nodeVer) nodeVer = nodeVer.replace(/\+$/, '')
  if (Array.isArray(json.engines)) {
    // Packages/1.0 commonjs style, with an array.
    // hack it to just hang a "node" member with the version range,
    // then do the npm-style check below.
    for (var i = 0, l = json.engines.length; i < l; i ++) {
      var e = json.engines[i].trim()
      if (e.substr(0, 4) === "node") {
        json.engines.node = e.substr(4)
      } else if (e.substr(0, 3) === "npm") {
        json.engines.npm = e.substr(3)
      }
    }
  }
  if (json.engines.node === "") json.engines.node = "*"
  if (json.engines.node && null === semver.validRange(json.engines.node)) {
    log.warn( json.engines.node
            , "Invalid range in engines.node.  Please see `npm help json`" )
  }

  if (nodeVer) {
    json._engineSupported = semver.satisfies( nodeVer
                                            , json.engines.node || "null" )
  }
  if (json.engines.hasOwnProperty("npm") && json._engineSupported) {
    json._engineSupported = semver.satisfies(npm.version, json.engines.npm)
  }
  return json
}

function unParsePeople (json) { return parsePeople(json, true) }
function parsePeople (json, un) {
  var fn = un ? unParsePerson : parsePerson
  if (json.author) json.author = fn(json.author)
  ;["maintainers", "contributors"].forEach(function (set) {
    if (Array.isArray(json[set])) json[set] = json[set].map(fn)
  })
  return json
}
function unParsePerson (person) {
  if (typeof person === "string") return person
  var name = person.name || ""
    , u = person.url || person.web
    , url = u ? (" ("+u+")") : ""
    , e = person.email || person.mail
    , email = e ? (" <"+e+">") : ""
  return name+email+url
}
function parsePerson (person) {
  if (typeof person !== "string") return person
  var name = person.match(/^([^\(<]+)/)
    , url = person.match(/\(([^\)]+)\)/)
    , email = person.match(/<([^>]+)>/)
    , obj = {}
  if (name && name[0].trim()) obj.name = name[0].trim()
  if (email) obj.email = email[1]
  if (url) obj.url = url[1]
  return obj
}
<commit_msg>Report this better<commit_after>
module.exports = readJson
readJson.processJson = processJson
readJson.unParsePeople = unParsePeople
readJson.parsePeople = parsePeople

var fs = require("./graceful-fs")
  , semver = require("semver")
  , path = require("path")
  , log = require("./log")
  , npm = require("../../npm")
  , cache = {}
  , timers = {}
  , loadPackageDefaults = require("./load-package-defaults")

function readJson (jsonFile, opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (cache.hasOwnProperty(jsonFile)) {
    log.verbose(jsonFile, "from cache")
    return cb(null, cache[jsonFile])
  }
  opts.file = jsonFile
  if (!opts.tag) {
    var parsedPath = jsonFile.indexOf(npm.dir) === 0 && jsonFile.match(
      /\/([^\/]+)\/([^\/]+)\/package\/package\.json$/)
    if (parsedPath && semver.valid(parsedPath[2])) {
      // this is a package.json in some installed package.
      // infer the opts.tag so that linked packages behave right.
      opts.tag = parsedPath[2]
    }
  }

  fs.readFile( path.join(path.dirname(jsonFile), "wscript")
             , function (er, data) {
    if (er) opts.wscript = false
    else opts.wscript = data.toString().match(/(^|\n)def build\b/)
                      && data.toString().match(/(^|\n)def configure\b/)
    fs.readFile(jsonFile, processJson(opts, function (er, data) {
      if (er) return cb(er)
      var doLoad = !(jsonFile.indexOf(npm.cache) === 0 &&
                     path.basename(path.dirname(jsonFile)) !== "package")
      if (!doLoad) return cb(er, data)
      loadPackageDefaults(data, path.dirname(jsonFile), cb)
    }))
  })
}
function processJson (opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (typeof cb !== "function") {
    var thing = cb, cb = null
    return P(null, thing)
  } else return P

  function P (er, thing) {
    if (er) {
      if (cb) return cb(er, thing)
      throw er
    }
    if (typeof thing === "object" && !Buffer.isBuffer(thing)) {
      return processObject(opts, cb)(er, thing)
    } else {
      return processJsonString(opts, cb)(er, thing)
    }
  }
}
function processJsonString (opts, cb) { return function (er, jsonString) {
  jsonString += ""
  if (er) return cb(er, jsonString)
  var json
  try {
    json = JSON.parse(jsonString)
  } catch (ex2) { try {
    json = process.binding("evals").Script.runInNewContext(
      "(\n"+jsonString+"\n)")
  } catch (ex) {
    var e = new Error(
      "Failed to parse json\n"+ex.message+"\n"+ex2.message+"\n"+jsonString)
    if (cb) return cb(e)
    throw e
  }}
  return processObject(opts, cb)(er, json)
}}
function processObject (opts, cb) { return function (er, json) {
  if (json.overlay) {
    ;["node", "npm"].forEach(function (k) {
      if (!json.overlay[k]) return undefined
      for (var i in json.overlay[k]) json[i] = json.overlay[k][i]
    })
  }

  // slashes would be a security risk.
  // anything else will just fail harmlessly.
  if (!json.name) {
    var e = new Error("No 'name' field found in package.json")
    if (cb) return cb(e)
    throw e
  }
  json.name = json.name.trim()
  if (json.name.charAt(0) === "." || json.name.match(/[\/@\s\+%:]/)) {
    var msg = "Invalid name: "
            + JSON.stringify(json.name)
            + " may not start with '.' or contain %/@+: or whitespace"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name.toLowerCase() === "node_modules") {
    var msg = "Invalid package name: node_modules"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name.toLowerCase() === "favicon.ico") {
    var msg = "Sorry, favicon.ico is a picture, not a package."
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }

  if (json.repostories) {
    var msg = "'repositories' (plural) No longer supported.\n"
            + "Please pick one, and put it in the 'repository' field."
      , e = new Error(msg)
    // uncomment once this is no longer an issue.
    // if (cb) return cb(e)
    // throw e
    log.error(msg, "incorrect json")
    json.repostory = json.repositories[0]
    delete json.repositories
  }

  if (json.repository) {
    if (typeof json.repository === "string") {
      json.repository = { type : "git"
                        , url : json.repository }
    }
    var repo = json.repository.url
    repo = repo.replace(/^(https?|git):\/\/[^\@]+\@github.com/
                       ,'$1://github.com')
    if (json.repository.type === "git"
        && ( repo.match(/^https?:\/\/github.com/)
          || repo.match(/github.com\/[^\/]+\/[^\/]+\/?$/)
             && !repo.match(/\.git$/)
        )) {
      var msg = "Please use the 'git://github.com/user/project.git'\n"
              + "format for github repository URLs."
        , e = new Error(msg)
      // later: uncomment this
      // if (cb) return cb(e)
      // throw e
      log.error(msg, "incorrect json "
                   +(json._id || (json.name+"@"+json.version)))
      repo = repo.replace(/^https?:\/\/github.com/, 'git://github.com')
      if (!repo.match(/\.git$/)) {
        repo = repo.replace(/\/?$/, '.git')
      }
    }
    if (repo.match(/github\.com\/[^\/]+\/[^\/]+\/?$/)
        && repo.match(/\.git\.git$/)) {
      log.win(repo, "Are you sure this is right?")
    }
    json.repository.url = repo
  }

  var tag = opts.tag
  if (tag) json.version = tag//+"-"+json.version

  if (json.modules) {
    if (typeof json.modules !== "object") {
      var e = new Error("Invalid modules object")
      if (cb) return cb(e)
      throw e
    }
    Object.keys(json.modules).forEach(function (mod) {
      if (typeof json.modules[mod] !== "string") {
        var e = new Error("Invalid module "+mod+", not a string: "
                         +JSON.stringify(json.modules[mod]))
        if (cb) return cb(e)
        throw e
      }
    })
  }

  if (opts.wscript) {
    var scripts = json.scripts = json.scripts || {}
    if (!scripts.install && !scripts.preinstall) {
      // don't fail if it was unexpected, just try.
      scripts.preinstall = "node-waf clean || true; node-waf configure build"
    }
  }

  if (!(semver.valid(json.version))) {
    var e = new Error("Invalid version: "+json.version+"\n"
                     +"Must be X.Y.Z, with an optional trailing tag.\n"
                     +"See the section on 'version' in `npm help json`")
    if (cb) return cb(e)
    throw e
  }
  json.version = semver.clean(json.version)

  if (json.bin && typeof json.bin === "string") {
    var b = {}
    b[ path.basename( json.bin ) ] = json.bin
    json.bin = b
  }

  if (json["dev-dependencies"] && !json.devDependencies) {
    json.devDependencies = json["dev-dependencies"]
    delete json["dev-dependencies"]
  }
  ;["dependencies", "devDependencies"].forEach(function (d) {
    if (!json[d]) return
    json[d] = depObjectify(json[d])
  })

  json._id = json.name+"@"+json.version
  json = testEngine(json)
  json = parsePeople(unParsePeople(json))
  if ( json.bugs ) json.bugs = parsePerson(unParsePerson(json.bugs))
  json._npmVersion = npm.version
  json._nodeVersion = process.version
  if (opts.file) {
    log.verbose(opts.file, "caching")
    cache[opts.file] = json
    // arbitrary
    var keys = Object.keys(cache)
      , l = keys.length
    if (l > 10000) for (var i = 0; i < l - 5000; i ++) {
      delete cache[keys[i]]
    }
  }
  if (cb) cb(null,json)
  return json
}}
function depObjectify (deps) {
  if (!Array.isArray(deps)) return deps
  var o = {}
  deps.forEach(function (d) {
    d = d.trim().split(/(:?[@\s><=])/)
    o[d.shift()] = d.join("").trim().replace(/^@/, "")
  })
  return o
}
function testEngine (json) {
  // if engines is empty, then assume that node is allowed.
  log.silly(json, "testEngine")
  if ( !json.engines
      || Array.isArray(json.engines)
        && !json.engines.length
      || typeof json.engines === "object"
        && !Object.keys(json.engines).length
      ) {
    json.engines = { "node" : "*" }
  }
  if (typeof json.engines === "string") {
    if (semver.validRange(json.engines) !== null) {
      json.engines = { "node" : json.engines }
    } else json.engines = [ json.engines ]
  }

  var nodeVer = npm.config.get("node-version")
    , ok = false
  if (nodeVer) nodeVer = nodeVer.replace(/\+$/, '')
  if (Array.isArray(json.engines)) {
    // Packages/1.0 commonjs style, with an array.
    // hack it to just hang a "node" member with the version range,
    // then do the npm-style check below.
    for (var i = 0, l = json.engines.length; i < l; i ++) {
      var e = json.engines[i].trim()
      if (e.substr(0, 4) === "node") {
        json.engines.node = e.substr(4)
      } else if (e.substr(0, 3) === "npm") {
        json.engines.npm = e.substr(3)
      }
    }
  }
  if (json.engines.node === "") json.engines.node = "*"
  if (json.engines.node && null === semver.validRange(json.engines.node)) {
    log.warn( json.engines.node
            , "Invalid range in engines.node.  Please see `npm help json`" )
  }

  if (nodeVer) {
    json._engineSupported = semver.satisfies( nodeVer
                                            , json.engines.node || "null" )
  }
  if (json.engines.hasOwnProperty("npm") && json._engineSupported) {
    json._engineSupported = semver.satisfies(npm.version, json.engines.npm)
  }
  return json
}

function unParsePeople (json) { return parsePeople(json, true) }
function parsePeople (json, un) {
  var fn = un ? unParsePerson : parsePerson
  if (json.author) json.author = fn(json.author)
  ;["maintainers", "contributors"].forEach(function (set) {
    if (Array.isArray(json[set])) json[set] = json[set].map(fn)
  })
  return json
}
function unParsePerson (person) {
  if (typeof person === "string") return person
  var name = person.name || ""
    , u = person.url || person.web
    , url = u ? (" ("+u+")") : ""
    , e = person.email || person.mail
    , email = e ? (" <"+e+">") : ""
  return name+email+url
}
function parsePerson (person) {
  if (typeof person !== "string") return person
  var name = person.match(/^([^\(<]+)/)
    , url = person.match(/\(([^\)]+)\)/)
    , email = person.match(/<([^>]+)>/)
    , obj = {}
  if (name && name[0].trim()) obj.name = name[0].trim()
  if (email) obj.email = email[1]
  if (url) obj.url = url[1]
  return obj
}
<|endoftext|>


<commit_before>// Utilies and other common gook shared between the WebWorker master and
// its constituent Workers.

var events = require('events');
var msgpack = require('msgpack');
var path = require('path');
var sys = require('sys');
var urllib = require('url');

// Symbolic names for our messages types
exports.MSGTYPE_NOOP = 0;
exports.MSGTYPE_HANDSHAKE = 1;
exports.MSGTYPE_ERROR = 2;
exports.MSGTYPE_CLOSE = 3;
exports.MSGTYPE_USER = 100;

// Some debugging functions
var debugLevel = ('NODE_DEBUG' in process.env) ?
    parseInt(process.env.NODE_DEBUG) : 0;
exports.debug = (debugLevel > 0) ?
    function(l, x) { if (l >= debugLevel) { sys.debug(x); } } :
    function() {};

// Is the given message well-formed?
exports.isValidMessage = function(msg) {
    return (Array.isArray(msg) && msg.length == 2);
}

// A simple messaging stream.
//
// This class is constructed around an existing stream net.Stream. This class
// emits 'msg' events when a message is received. Each emitted 'msg' event
// may come with a second 'fd' parameter if the message was sent with  file
// descriptor. A sent file descriptor is guaranteed to be received with the
// message with which it was sent.
//
// Sending messages is done with the send() method.
var MsgStream = function(s) {
    var self = this;

    events.EventEmitter.call(self);

    // Sequence numbers for outgoing and incoming FDs
    var fds_seqno_sent = 0;
    var fds_seqno_recvd = 0;

    // Collections of messages waiting for FDs and vice-versa. These
    // are keyed by FD seqno.
    var msg_waiting_for_fd = {};
    var fd_waiting_for_msg = {};

    // Our msgpack.Stream instance which we're interfacing with, as it will
    // manage framing for us
    var mpStream = new msgpack.Stream(s);

    // Send the given JavaSript object. If 'fd' is provided, it is sent as a
    // file descriptor along with the message.
    self.send = function(v, fd) {
        mpStream.send(
            [(fd != undefined) ? ++fds_seqno_sent : 0, v],
            undefined,
            fd
        );
    };

    mpStream.addListener('msg', function(msg_arr) {
        var fd = undefined;

        var fd_seq = msg_arr[0];
        var msg = msg_arr[1];

        // If our message has an associated file descriptor that we
        // have not yet received, queue it for later delivery.
        if (fd_seq) {
            if (!(fd = fd_waiting_for_msg[fd_seq])) {
                msg_waiting_for_fd[fd_seq] = msg;
                return;
            }

            delete fd_waiting_for_msg[fd_seq];
        }

        // We're complete; emit
        self.emit('msg', msg, fd);
    });

    s.addListener('fd', function(fd) {
        // Look for a message that's waiting for our arrival. If we don't
        // have one, enqueu the received FD for later delivery.
        var msg = msg_waiting_for_fd[++fds_seqno_recvd];
        if (!msg) {
            fd_waiting_for_msg[fds_seqno_recvd] = fd;
            return;
        }

        // There was a message waiting for us; emit
        delete msg_waiting_for_fd[fds_seqno_recvd];
        self.emit('msg', msg, fd);
    });
};

sys.inherits(MsgStream, events.EventEmitter);
exports.MsgStream = MsgStream;

// Implement the WorkerLocation interface described in
// http://www.whatwg.org/specs/web-workers/current-work/#dom-workerlocation-href
//
// XXX: None of these properties are readonly as required by the spec.
var WorkerLocation = function(url) {
    var u = urllib.parse(url);

    var portForProto = function(proto) {
        switch (proto) {
        case 'http':
            return 80;

        case 'https':
            return 443;

        case 'file':
            return undefined;

        default:
            sys.debug(
                'Unknown protocol \'' + proto + '\'; returning undefined'
            );
            return undefined;
        };
    };

    this.href = u.href;
    this.protocol = u.protocol.substring(0, u.protocol.length - 1);
    this.host = u.host;
    this.hostname = u.hostname;
    this.port = (u.port) ? u.port : portForProto(this.protocol);
    this.pathname = (u.pathname) ? path.normalize(u.pathname) : '/';
    this.search = (u.search) ? u.search : '';
    this.hash = (u.hash) ? u.hash : '';
};

exports.WorkerLocation = WorkerLocation;
<commit_msg>First cut of error parsing functions.<commit_after>// Utilies and other common gook shared between the WebWorker master and
// its constituent Workers.

var events = require('events');
var msgpack = require('msgpack');
var path = require('path');
var sys = require('sys');
var urllib = require('url');

// Symbolic names for our messages types
exports.MSGTYPE_NOOP = 0;
exports.MSGTYPE_HANDSHAKE = 1;
exports.MSGTYPE_ERROR = 2;
exports.MSGTYPE_CLOSE = 3;
exports.MSGTYPE_USER = 100;

// Some debugging functions
var debugLevel = ('NODE_DEBUG' in process.env) ?
    parseInt(process.env.NODE_DEBUG) : 0;
exports.debug = (debugLevel > 0) ?
    function(l, x) { if (l <= debugLevel) { sys.debug(x); } } :
    function() {};

// Is the given message well-formed?
exports.isValidMessage = function(msg) {
    return (Array.isArray(msg) && msg.length == 2);
}

// A simple messaging stream.
//
// This class is constructed around an existing stream net.Stream. This class
// emits 'msg' events when a message is received. Each emitted 'msg' event
// may come with a second 'fd' parameter if the message was sent with  file
// descriptor. A sent file descriptor is guaranteed to be received with the
// message with which it was sent.
//
// Sending messages is done with the send() method.
var MsgStream = function(s) {
    var self = this;

    events.EventEmitter.call(self);

    // Sequence numbers for outgoing and incoming FDs
    var fds_seqno_sent = 0;
    var fds_seqno_recvd = 0;

    // Collections of messages waiting for FDs and vice-versa. These
    // are keyed by FD seqno.
    var msg_waiting_for_fd = {};
    var fd_waiting_for_msg = {};

    // Our msgpack.Stream instance which we're interfacing with, as it will
    // manage framing for us
    var mpStream = new msgpack.Stream(s);

    // Send the given JavaSript object. If 'fd' is provided, it is sent as a
    // file descriptor along with the message.
    self.send = function(v, fd) {
        mpStream.send(
            [(fd != undefined) ? ++fds_seqno_sent : 0, v],
            undefined,
            fd
        );
    };

    mpStream.addListener('msg', function(msg_arr) {
        var fd = undefined;

        var fd_seq = msg_arr[0];
        var msg = msg_arr[1];

        // If our message has an associated file descriptor that we
        // have not yet received, queue it for later delivery.
        if (fd_seq) {
            if (!(fd = fd_waiting_for_msg[fd_seq])) {
                msg_waiting_for_fd[fd_seq] = msg;
                return;
            }

            delete fd_waiting_for_msg[fd_seq];
        }

        // We're complete; emit
        self.emit('msg', msg, fd);
    });

    s.addListener('fd', function(fd) {
        // Look for a message that's waiting for our arrival. If we don't
        // have one, enqueu the received FD for later delivery.
        var msg = msg_waiting_for_fd[++fds_seqno_recvd];
        if (!msg) {
            fd_waiting_for_msg[fds_seqno_recvd] = fd;
            return;
        }

        // There was a message waiting for us; emit
        delete msg_waiting_for_fd[fds_seqno_recvd];
        self.emit('msg', msg, fd);
    });
};

sys.inherits(MsgStream, events.EventEmitter);
exports.MsgStream = MsgStream;

// Implement the WorkerLocation interface described in
// http://www.whatwg.org/specs/web-workers/current-work/#dom-workerlocation-href
//
// XXX: None of these properties are readonly as required by the spec.
var WorkerLocation = function(url) {
    var u = urllib.parse(url);

    var portForProto = function(proto) {
        switch (proto) {
        case 'http':
            return 80;

        case 'https':
            return 443;

        case 'file':
            return undefined;

        default:
            sys.debug(
                'Unknown protocol \'' + proto + '\'; returning undefined'
            );
            return undefined;
        };
    };

    this.href = u.href;
    this.protocol = u.protocol.substring(0, u.protocol.length - 1);
    this.host = u.host;
    this.hostname = u.hostname;
    this.port = (u.port) ? u.port : portForProto(this.protocol);
    this.pathname = (u.pathname) ? path.normalize(u.pathname) : '/';
    this.search = (u.search) ? u.search : '';
    this.hash = (u.hash) ? u.hash : '';
};

exports.WorkerLocation = WorkerLocation;

// Get the error message for a given exception
exports.getErrorMessage = function(e) {
    try {
        return e.message || e.stack.split('\n')[0].trim();
    } catch (e) {
        return 'WebWorkers: failed to get error message';
    }
};

// Get the filename for a given exception
exports.getErrorFilename = function(e) {
    try {
        return e.stack.split('\n')[1].trim().substr(3).split(':')[0];
    } catch (e) {
        return 'WebWorkers: failed to get error filename';
    }
};

// Get the line number for a given exception
exports.getErrorLine = function(e) {
    try {
        return parseInt(e.stack.split('\n')[1].trim().split(':')[1]);
    } catch (e) {
        return -1;
    }
};
<|endoftext|>


<commit_before>var HID = require('node-hid'),
  util = require('util'),
  events = require('events'),
  chalk = require('chalk'),
  config = require('../lib/config'),
  buttons;

function XboxController(opts){
  this.HIDController = null;
  this.HIDProduct = (opts && opts.product) || 'controller';
  this.HIDConfig = (opts && opts.config) || {};

  this.getController();
}

util.inherits(XboxController, events.EventEmitter);

XboxController.prototype.getController = function () {
  HID.devices().forEach(function(d){
    var product = (typeof d === 'object' && d.product) || '';

    if(product.toLowerCase().indexOf(this.HIDProduct.toLowerCase()) !== -1){

      this.HIDController = new HID.HID(d.path);
      console.log(chalk.green('Notice:'), 'Xbox controller connected');
    }
  }.bind(this));

  if(!this.HIDController){
    console.log(chalk.red('Error:'), 'Xbox controller not found');
  }else{
    this.interpretControllerData();
  }
}

XboxController.prototype.interpretControllerData = function () {
  this.HIDController.on('data', function (data) {
    this.controlButton = data[this.HIDConfig.controlBtnsBlock] || data[10];
    this.directionalButton = data[this.HIDConfig.directionalBtnsBlock] || data[11];

    this._fireButtonEvents(this.directionalButton, this.controlButton);
  }.bind(this));
}

XboxController.prototype._fireButtonEvents = function(directionalButton, controlButton) {
  if(directionalButton){
    this.emit(getButton(directionalButton, 'DIRECTIONAL'));
  }

  if(controlButton){
    this.emit(getButton(controlButton));
  }
}

XboxController.prototype.configure = function () {
  if(this.HIDController){
    config.start(this);
  }
}

XboxController.prototype.CreateController = function (HIDInfo) {
  if(!this.HIDController){
   if(!HIDInfo || !HIDInfo.product){
     console.log(chalk.yellow('Warn:'), '"HIDInfo.product" not found. Assuming pattern "controller"');
   }

   if(!HIDInfo || !HIDInfo.config){
     console.log(chalk.yellow('Warn:'), '"HIDInfo.config" not found. Assuming patterns "{controlBtnsBlock : 10, directionalBtnsBlock: 11}"');
   }

   return new XboxController(HIDInfo);
 }else{
   console.log(chalk.yellow("Warn:"), "Xbox controller is already connected");
 }
}

XboxController.prototype.listHIDDevices = function () {
  console.log(HID.devices());
}

function getButton(data, typeButton) {
  var buttonRange;

  if(!buttons){
    try{
      buttons = require('../config/buttons.json');
    }catch(err){
      buttons = require('../lib/buttons.json')
    }
  }

  if(typeButton == 'DIRECTIONAL'){
    buttonRange = buttons.directionalButtons;
  }else {
    buttonRange = buttons.controlButtons;
  }

  for(btn in buttonRange){
    if(data ==  buttonRange[btn]){
      return btn;
    }
  }
}

module.exports = new XboxController();
<commit_msg>Emiting event [button]:none per button<commit_after>var HID = require('node-hid'),
  util = require('util'),
  events = require('events'),
  chalk = require('chalk'),
  config = require('../lib/config'),
  buttons;

function XboxController(opts){
  this.HIDController = null;
  this.HIDProduct = (opts && opts.product) || 'controller';
  this.HIDConfig = (opts && opts.config) || {};

  this.getController();
}

util.inherits(XboxController, events.EventEmitter);

XboxController.prototype.getController = function () {
  HID.devices().forEach(function(d){
    var product = (typeof d === 'object' && d.product) || '';

    if(product.toLowerCase().indexOf(this.HIDProduct.toLowerCase()) !== -1){

      this.HIDController = new HID.HID(d.path);
      console.log(chalk.green('Notice:'), 'Xbox controller connected');
    }
  }.bind(this));

  if(!this.HIDController){
    console.log(chalk.red('Error:'), 'Xbox controller not found');
  }else{
    this.interpretControllerData();
  }
}

XboxController.prototype.interpretControllerData = function () {
  this.HIDController.on('data', function (data) {
    this.controlButton = data[this.HIDConfig.controlBtnsBlock] || data[10];
    this.directionalButton = data[this.HIDConfig.directionalBtnsBlock] || data[11];

    this._fireButtonEvents(this.directionalButton, this.controlButton);
  }.bind(this));
}

XboxController.prototype._fireButtonEvents = function(directionalButton, controlButton) {
  if(directionalButton){
    this.getButton(directionalButton, 'DIRECTIONAL');
  }

  if(controlButton){
    this.getButton(controlButton);
  }
}

XboxController.prototype.configure = function () {
  if(this.HIDController){
    config.start(this);
  }
}

XboxController.prototype.CreateController = function (HIDInfo) {
  if(!this.HIDController){
    if(!HIDInfo || !HIDInfo.product){
      console.log(chalk.yellow('Warn:'), '"HIDInfo.product" not found. Assuming pattern "controller"');
    }

    if(!HIDInfo || !HIDInfo.config){
      console.log(chalk.yellow('Warn:'), '"HIDInfo.config" not found. Assuming patterns "{controlBtnsBlock : 10, directionalBtnsBlock: 11}"');
    }

    return new XboxController(HIDInfo);
  }else{
    console.log(chalk.yellow("Warn:"), "Xbox controller is already connected");
  }
}

XboxController.prototype.listHIDDevices = function () {
  console.log(HID.devices());
}

XboxController.prototype.getButton = function(data, typeButton) {
  var buttonRange;

  if(!buttons){
    try{
      buttons = require('../config/buttons.json');
    }catch(err){
      buttons = require('../lib/buttons.json')
    }
  }

  if(typeButton == 'DIRECTIONAL'){
    buttonRange = buttons.directionalButtons;
  }else {
    buttonRange = buttons.controlButtons;
  }

  for(btn in buttonRange){
    if(data ==  buttonRange[btn]){
      this.emit(btn);
    }else{
      this.emit(btn + ':none');
    }
  }
}

module.exports = new XboxController();
<|endoftext|>


<commit_before>//Load modules
var System = require('systemjs');
var ASQ = require('asynquence');

function report (msg) {
	console.log(msg)
};
report(ASQ);

function repErr (err) {
	console.error(err)
};

var app = require('express')();
var http = require('http').Server(app)};
var io = require('socket.io')(http)};
var emic = require('./emic2.js')};
ASQ()
/*.then(function () {app = require('express')();
report(app)})
.then(report(app))
.then(function () {http = require('http').Server(app)})
.then(function () {io = require('socket.io')(http)})
.then(function () {emic = require('./emic2.js')})
.then(function () {report("Modules loaded successfully")})
//.or(repErr("Module load error"))
.then(report(emic))*/
.then(emic.init())
.then(app.get('/', function(req, res){
    //var html = fs.readFileSync("index3.html", "utf8");
    //res.send(html);
    res.sendFile(__dirname + '/main.html');
}))
.then(report('connection achieved'))
.gate(
	io.on('connection', function(socket){
		report('a user connected');
		socket.on('disconnect', function() {
			report('a user disconnected');
		});
		socket.on('user message', function(msg){
			report('sendmessage');
			EMIC.speak(msg);
			report('usermessage: ' + msg);
			io.emit('user message', msg);
		});
	}),
	http.listen(3001, function(){
    	report('listening on *:3001');
	})
)
<commit_msg>update<commit_after>//Load modules
var System = require('systemjs');
var ASQ = require('asynquence');

function report (msg) {
	console.log(msg)
};
report(ASQ);

function repErr (err) {
	console.error(err)
};

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var emic = require('./emic2.js');
ASQ()
/*.then(function () {app = require('express')();
report(app)})
.then(report(app))
.then(function () {http = require('http').Server(app)})
.then(function () {io = require('socket.io')(http)})
.then(function () {emic = require('./emic2.js')})
.then(function () {report("Modules loaded successfully")})
//.or(repErr("Module load error"))
.then(report(emic))*/
.then(emic.init())
.then(app.get('/', function(req, res){
    //var html = fs.readFileSync("index3.html", "utf8");
    //res.send(html);
    res.sendFile(__dirname + '/main.html');
}))
.then(report('connection achieved'))
.gate(
	io.on('connection', function(socket){
		report('a user connected');
		socket.on('disconnect', function() {
			report('a user disconnected');
		});
		socket.on('user message', function(msg){
			report('sendmessage');
			EMIC.speak(msg);
			report('usermessage: ' + msg);
			io.emit('user message', msg);
		});
	}),
	http.listen(3001, function(){
    	report('listening on *:3001');
	})
)
<|endoftext|>