<commit_before>exports.categories = {
    'Authentication': {
        bell: {
            url: 'https://github.com/hapijs/bell',
            description: 'Third-party login plugin for hapi with built in Facebook, GitHub, Google, Twitter, Yahoo, Foursquare, and Windows Live support'
        },
        'hapi-auth-anonymous': {
            url: 'https://github.com/codedoctor/hapi-auth-anonymous',
            description: 'Authentication strategy to support anonymous mobile users.'
        },
        'hapi-auth-basic': {
            url: 'https://github.com/hapijs/hapi-auth-basic',
            description: 'An HTTP Basic authentication scheme'
        },
        'hapi-auth-bearer-token': {
            url: 'https://github.com/johnbrett/hapi-auth-bearer-token',
            description: 'A bearer token based authentication scheme'
        },
        'hapi-auth-cookie': {
            url: 'https://github.com/hapijs/hapi-auth-cookie',
            description: 'A cookie-based session authentication scheme'
        },
        'hapi-auth-extra': {
            url: 'https://github.com/asafdav/hapi-auth-extra',
            description: 'Additional auth toolbox for HapiJS including ACL support'
        },
        'hapi-auth-hawk': {
            url :'https://github.com/hapijs/hapi-auth-hawk',
            description: 'Hawk authentication plugin'
        },
        'hapi-auth-jwt': {
          url :'https://github.com/ryanfitz/hapi-auth-jwt',
          description: 'JSON Web Token (JWT) authentication plugin'
        },
        'hapi-auth-signature': {
          url :'https://github.com/58bits/hapi-auth-signature',
          description: 'Signature authentication plugin - a wrapper for the Joyent http-signature scheme'
        },
        'hapi-session-mongo': {
            url: 'https://github.com/Mkoopajr/hapi-session-mongo',
            description: 'MongoDB session store and authentication plugin'
        }
    },
    'Documentation': {
        'hapi-swagger': {
            url: 'https://github.com/glennjones/hapi-swagger',
            description: 'A swagger documentation UI generator plugin for hapi'
        },
        'hapi-swagger-models': {
            url: 'https://github.com/codeandfury/node-hapi-swagger-models',
            description: 'Generate Backbone models from a swagger API'
        },
        lout: {
            url: 'https://github.com/hapijs/lout',
            description: 'A browsable documentation generator'
        }
    },
    "Localization/Internationalization": {
        'hapi-l10n-gettext': {
            url: 'https://github.com/maxnachlinger/hapi-l10n-gettext',
            description: 'A localization plug-in for HapiJS'
        },
        hapil18n: {
            url: 'https://github.com/gpierret/hapi18n',
            description: 'i18n for Hapi'
        }
    },
    'Logging/Metrics': {
        blipp: {
            url: 'https://github.com/danielb2/blipp',
            description: 'Displays the routes table at startup'
        },
        good: {
            url: 'https://github.com/hapijs/good',
            description: 'A logging plugin that supports output to console, file and udp/http endpoints'
        },
        'good-reporters': {
            url: 'https://github.com/hapijs/good/tree/master#list-of-reporters',
            description: 'List of available good reporter plugins'
        },
        'hapi-statsd': {
            url: 'https://github.com/mac-/hapi-statsd',
            description: 'Sends request round trip metrics to statsd'
        }
    },
    'Security': {
        blankie: {
            url: 'https://github.com/nlf/blankie',
            description: 'A plugin that makes Content-Security-Policy headers easy'
        },
        crumb: {
            url: 'https://github.com/hapijs/crumb',
            description: 'CSRF crumb generation and validation for hapi'
        }
    },
    'Session': {
        yar: {
            url: 'https://github.com/hapijs/yar',
            description: 'A hapi session plugin and cookie jar'
        }
    },
    'Templating': {
        'hapi-dust': {
            url: 'https://github.com/mikefrey/hapi-dust',
            description: 'Compatibility wrapper for dust.js'
        },
        'hapi-json-view': {
            url: 'https://github.com/gergoerdosi/hapi-json-view',
            description: 'JSON view engine for hapi.'
        },
        'hapi-react-views': {
            url: 'https://github.com/jedireza/hapi-react-views',
            description: 'A hapi view engine for React components.'
        },
        'hapi-react': {
            url: 'https://github.com/landau/hapi-react',
            description: 'A port of express-react-views.'
        }
    },
    'Utility': {
        bassmaster: {
            url: 'https://github.com/hapijs/bassmaster',
            description: 'The batch endpoint makes it easy to combine multiple requests into a single one'
        },
        halacious: {
            url: 'https://github.com/bleupen/halacious',
            description: 'A HAL processor for hapi servers'
        },
        'hapi-assets': {
            url: 'https://github.com/poeticninja/hapi-assets',
            description: 'Load assets in views based on node environment.'
        },
        'hapi-cache-buster': {
            url: 'https://github.com/poeticninja/hapi-cache-buster',
            description: 'Browser asset cache buster.'
        },
        'hapi-cloudinary-connector': {
            url: 'https://github.com/gergoerdosi/hapi-cloudinary-connector',
            description: 'Cloudinary connector plugin for hapi.'
        },
        'hapi-level-db': {
            url: 'https://github.com/maxnachlinger/hapi-level-db',
            description: 'HapiJS / LevelDB integration'
        },
        'hapi-magic-filter': {
            url: 'https://github.com/ruiquelhas/hapi-magic-filter',
            description: 'Hapi.js plugin to validate multipart/form-data file contents'
        },
        'hapi-mailer': {
            url: 'https://github.com/gergoerdosi/hapi-mailer',
            description: 'Mailer plugin for hapi.'
        },
        'hapi-mongoose-db-connector' : {
            url: 'https://github.com/codedoctor/hapi-mongoose-db-connector',
            description: 'hapi plugin that connects to mongodb for mongoose apps'
        },
        'hapi-named-routes': {
            url: 'https://github.com/poeticninja/hapi-named-routes',
            description: 'Add named routes to your view templates.'
        },
        'hapi-node-postgres' : {
            url: 'https://github.com/jedireza/hapi-node-postgres',
            description: 'Wrap requests with a pg connection. Uses connection pooling via `node-postgres`.'
        },
        'hapi-route-directory': {
            url: 'https://github.com/clarkie/hapi-route-directory',
            description: 'A lightweight json route directory'
        },
        'hapi-routes-status' : {
          url: 'https://github.com/codedoctor/hapi-routes-status',
          description: 'Exposes a status route for your node.js/hapi projects.'
        },
        'hapi-sequelize': {
            url: 'https://github.com/codeandfury/node-hapi-sequelize',
            description: 'HAPI Plugin for Sequelize'
        },
        'hapi-sequelized' : {
            url: 'https://github.com/danecando/hapi-sequelized',
            description: 'A plugin for using sequelize with hapi'
        },
        poop: {
            url: 'https://github.com/hapijs/poop',
            description: 'Plugin for taking a process dump and cleaning up after an uncaught exception'
        },
        reptile: {
            url: 'https://github.com/hapijs/reptile',
            description: 'A plugin for creating a REPL'
        },
        ridicule: {
            url: 'https://github.com/walmartlabs/ridicule',
            description: 'A plugin for mocking requests'
        },
        scooter: {
            url: 'https://github.com/hapijs/scooter',
            description: 'User-agent information plugin'
        },
        toothache: {
            url: 'https://github.com/smaxwellstewart/toothache',
            description: 'A plugin designed to make it very simple to create RESTful CRUD endpoints for a Hapi server using MongoDB'
        },
        tv: {
            url: 'https://github.com/hapijs/tv',
            description: 'Interactive debug console plugin for hapi servers'
        }
    },
    Boilerplate: {
        'hapi-dash': {
            url: 'https://github.com/smaxwellstewart/hapi-dash',
            description: 'A boilerplate hapi web and API server example, with frontend dashboard'
        },
        'hapi-ninja': {
            url: 'https://github.com/poeticninja/hapi-ninja',
            description: 'Boilerplate Hapi server example. Node.js, Hapi, and Swig.'
        },
        frame: {
            url: 'https://github.com/jedireza/frame',
            description: 'Includes a user system. 100% test coverage. Bring your own front-end.'
        },
        rutha: {
            url: 'https://github.com/molekilla/rutha',
            description: 'frontend stack for Hapi (server, api) and Angular (client)'
        }
    },
    'The extended hapi universe': {
        boom: {
            url: 'https://github.com/hapijs/boom',
            description: 'HTTP-friendly error objects'
        },
        confidence: {
            url: 'https://github.com/hapijs/confidence',
            description: 'A configuration document format, an API, and a foundation for A/B testing'
        },
        faketoe: {
            url: 'https://github.com/hapijs/faketoe',
            description: 'An XML to JSON converter'
        },
        hoek: {
            url: 'https://github.com/hapijs/hoek',
            description: 'General purpose node utilities'
        },
        joi: {
            url: 'https://github.com/hapijs/joi',
            description: 'Object schema description language and validator for JavaScript objects'
        },
        kilt: {
            url: 'https://github.com/hapijs/kilt',
            description: 'Combine multiple event emitters into a single emitter'
        },
        lab: {
            url: 'https://github.com/hapijs/lab',
            description: 'A simple testing utility with code coverage analysis'
        },
        makemehapi: {
            url: 'https://github.com/hapijs/makemehapi',
            description: 'Self guided workshops to teach you about hapi'
        },
        qs: {
            url: 'https://github.com/hapijs/qs',
            description: 'A querystring parses with support for arrays and objects'
        },
        shot: {
            url: 'https://github.com/hapijs/shot',
            description: 'Injects a fake HTTP request/response into your node server logic'
        },
        topo: {
            url: 'https://github.com/hapijs/topo',
            description: 'Topological sorting with grouping support'
        },
        wreck: {
            url: 'https://github.com/hapijs/wreck',
            description: 'HTTP Client utilities'
        }
    }
};
<commit_msg>Fix link to list of good reporters<commit_after>exports.categories = {
    'Authentication': {
        bell: {
            url: 'https://github.com/hapijs/bell',
            description: 'Third-party login plugin for hapi with built in Facebook, GitHub, Google, Twitter, Yahoo, Foursquare, and Windows Live support'
        },
        'hapi-auth-anonymous': {
            url: 'https://github.com/codedoctor/hapi-auth-anonymous',
            description: 'Authentication strategy to support anonymous mobile users.'
        },
        'hapi-auth-basic': {
            url: 'https://github.com/hapijs/hapi-auth-basic',
            description: 'An HTTP Basic authentication scheme'
        },
        'hapi-auth-bearer-token': {
            url: 'https://github.com/johnbrett/hapi-auth-bearer-token',
            description: 'A bearer token based authentication scheme'
        },
        'hapi-auth-cookie': {
            url: 'https://github.com/hapijs/hapi-auth-cookie',
            description: 'A cookie-based session authentication scheme'
        },
        'hapi-auth-extra': {
            url: 'https://github.com/asafdav/hapi-auth-extra',
            description: 'Additional auth toolbox for HapiJS including ACL support'
        },
        'hapi-auth-hawk': {
            url :'https://github.com/hapijs/hapi-auth-hawk',
            description: 'Hawk authentication plugin'
        },
        'hapi-auth-jwt': {
          url :'https://github.com/ryanfitz/hapi-auth-jwt',
          description: 'JSON Web Token (JWT) authentication plugin'
        },
        'hapi-auth-signature': {
          url :'https://github.com/58bits/hapi-auth-signature',
          description: 'Signature authentication plugin - a wrapper for the Joyent http-signature scheme'
        },
        'hapi-session-mongo': {
            url: 'https://github.com/Mkoopajr/hapi-session-mongo',
            description: 'MongoDB session store and authentication plugin'
        }
    },
    'Documentation': {
        'hapi-swagger': {
            url: 'https://github.com/glennjones/hapi-swagger',
            description: 'A swagger documentation UI generator plugin for hapi'
        },
        'hapi-swagger-models': {
            url: 'https://github.com/codeandfury/node-hapi-swagger-models',
            description: 'Generate Backbone models from a swagger API'
        },
        lout: {
            url: 'https://github.com/hapijs/lout',
            description: 'A browsable documentation generator'
        }
    },
    "Localization/Internationalization": {
        'hapi-l10n-gettext': {
            url: 'https://github.com/maxnachlinger/hapi-l10n-gettext',
            description: 'A localization plug-in for HapiJS'
        },
        hapil18n: {
            url: 'https://github.com/gpierret/hapi18n',
            description: 'i18n for Hapi'
        }
    },
    'Logging/Metrics': {
        blipp: {
            url: 'https://github.com/danielb2/blipp',
            description: 'Displays the routes table at startup'
        },
        good: {
            url: 'https://github.com/hapijs/good',
            description: 'A logging plugin that supports output to console, file and udp/http endpoints'
        },
        'good-reporters': {
            url: 'https://github.com/hapijs/good/tree/master#reporters',
            description: 'List of available good reporter plugins'
        },
        'hapi-statsd': {
            url: 'https://github.com/mac-/hapi-statsd',
            description: 'Sends request round trip metrics to statsd'
        }
    },
    'Security': {
        blankie: {
            url: 'https://github.com/nlf/blankie',
            description: 'A plugin that makes Content-Security-Policy headers easy'
        },
        crumb: {
            url: 'https://github.com/hapijs/crumb',
            description: 'CSRF crumb generation and validation for hapi'
        }
    },
    'Session': {
        yar: {
            url: 'https://github.com/hapijs/yar',
            description: 'A hapi session plugin and cookie jar'
        }
    },
    'Templating': {
        'hapi-dust': {
            url: 'https://github.com/mikefrey/hapi-dust',
            description: 'Compatibility wrapper for dust.js'
        },
        'hapi-json-view': {
            url: 'https://github.com/gergoerdosi/hapi-json-view',
            description: 'JSON view engine for hapi.'
        },
        'hapi-react-views': {
            url: 'https://github.com/jedireza/hapi-react-views',
            description: 'A hapi view engine for React components.'
        },
        'hapi-react': {
            url: 'https://github.com/landau/hapi-react',
            description: 'A port of express-react-views.'
        }
    },
    'Utility': {
        bassmaster: {
            url: 'https://github.com/hapijs/bassmaster',
            description: 'The batch endpoint makes it easy to combine multiple requests into a single one'
        },
        halacious: {
            url: 'https://github.com/bleupen/halacious',
            description: 'A HAL processor for hapi servers'
        },
        'hapi-assets': {
            url: 'https://github.com/poeticninja/hapi-assets',
            description: 'Load assets in views based on node environment.'
        },
        'hapi-cache-buster': {
            url: 'https://github.com/poeticninja/hapi-cache-buster',
            description: 'Browser asset cache buster.'
        },
        'hapi-cloudinary-connector': {
            url: 'https://github.com/gergoerdosi/hapi-cloudinary-connector',
            description: 'Cloudinary connector plugin for hapi.'
        },
        'hapi-level-db': {
            url: 'https://github.com/maxnachlinger/hapi-level-db',
            description: 'HapiJS / LevelDB integration'
        },
        'hapi-magic-filter': {
            url: 'https://github.com/ruiquelhas/hapi-magic-filter',
            description: 'Hapi.js plugin to validate multipart/form-data file contents'
        },
        'hapi-mailer': {
            url: 'https://github.com/gergoerdosi/hapi-mailer',
            description: 'Mailer plugin for hapi.'
        },
        'hapi-mongoose-db-connector' : {
            url: 'https://github.com/codedoctor/hapi-mongoose-db-connector',
            description: 'hapi plugin that connects to mongodb for mongoose apps'
        },
        'hapi-named-routes': {
            url: 'https://github.com/poeticninja/hapi-named-routes',
            description: 'Add named routes to your view templates.'
        },
        'hapi-node-postgres' : {
            url: 'https://github.com/jedireza/hapi-node-postgres',
            description: 'Wrap requests with a pg connection. Uses connection pooling via `node-postgres`.'
        },
        'hapi-route-directory': {
            url: 'https://github.com/clarkie/hapi-route-directory',
            description: 'A lightweight json route directory'
        },
        'hapi-routes-status' : {
          url: 'https://github.com/codedoctor/hapi-routes-status',
          description: 'Exposes a status route for your node.js/hapi projects.'
        },
        'hapi-sequelize': {
            url: 'https://github.com/codeandfury/node-hapi-sequelize',
            description: 'HAPI Plugin for Sequelize'
        },
        'hapi-sequelized' : {
            url: 'https://github.com/danecando/hapi-sequelized',
            description: 'A plugin for using sequelize with hapi'
        },
        poop: {
            url: 'https://github.com/hapijs/poop',
            description: 'Plugin for taking a process dump and cleaning up after an uncaught exception'
        },
        reptile: {
            url: 'https://github.com/hapijs/reptile',
            description: 'A plugin for creating a REPL'
        },
        ridicule: {
            url: 'https://github.com/walmartlabs/ridicule',
            description: 'A plugin for mocking requests'
        },
        scooter: {
            url: 'https://github.com/hapijs/scooter',
            description: 'User-agent information plugin'
        },
        toothache: {
            url: 'https://github.com/smaxwellstewart/toothache',
            description: 'A plugin designed to make it very simple to create RESTful CRUD endpoints for a Hapi server using MongoDB'
        },
        tv: {
            url: 'https://github.com/hapijs/tv',
            description: 'Interactive debug console plugin for hapi servers'
        }
    },
    Boilerplate: {
        'hapi-dash': {
            url: 'https://github.com/smaxwellstewart/hapi-dash',
            description: 'A boilerplate hapi web and API server example, with frontend dashboard'
        },
        'hapi-ninja': {
            url: 'https://github.com/poeticninja/hapi-ninja',
            description: 'Boilerplate Hapi server example. Node.js, Hapi, and Swig.'
        },
        frame: {
            url: 'https://github.com/jedireza/frame',
            description: 'Includes a user system. 100% test coverage. Bring your own front-end.'
        },
        rutha: {
            url: 'https://github.com/molekilla/rutha',
            description: 'frontend stack for Hapi (server, api) and Angular (client)'
        }
    },
    'The extended hapi universe': {
        boom: {
            url: 'https://github.com/hapijs/boom',
            description: 'HTTP-friendly error objects'
        },
        confidence: {
            url: 'https://github.com/hapijs/confidence',
            description: 'A configuration document format, an API, and a foundation for A/B testing'
        },
        faketoe: {
            url: 'https://github.com/hapijs/faketoe',
            description: 'An XML to JSON converter'
        },
        hoek: {
            url: 'https://github.com/hapijs/hoek',
            description: 'General purpose node utilities'
        },
        joi: {
            url: 'https://github.com/hapijs/joi',
            description: 'Object schema description language and validator for JavaScript objects'
        },
        kilt: {
            url: 'https://github.com/hapijs/kilt',
            description: 'Combine multiple event emitters into a single emitter'
        },
        lab: {
            url: 'https://github.com/hapijs/lab',
            description: 'A simple testing utility with code coverage analysis'
        },
        makemehapi: {
            url: 'https://github.com/hapijs/makemehapi',
            description: 'Self guided workshops to teach you about hapi'
        },
        qs: {
            url: 'https://github.com/hapijs/qs',
            description: 'A querystring parses with support for arrays and objects'
        },
        shot: {
            url: 'https://github.com/hapijs/shot',
            description: 'Injects a fake HTTP request/response into your node server logic'
        },
        topo: {
            url: 'https://github.com/hapijs/topo',
            description: 'Topological sorting with grouping support'
        },
        wreck: {
            url: 'https://github.com/hapijs/wreck',
            description: 'HTTP Client utilities'
        }
    }
};
<|endoftext|>


<commit_before>module.exports = function Printer(){
    var PRINTER = {};
    PRINTER.colors = require('colors');

    PRINTER.STAGED = "STAGED";
    PRINTER.NOT_STAGED = "NOT_STAGED";
    PRINTER.UNTRACKED = "UNTRACKED";
    PRINTER.margin = "                 ";
    PRINTER.smallMargin = "          ";
    PRINTER.maxLineLength = 80;

    PRINTER.colors.setTheme({
      silly: 'rainbow',
      input: 'grey',
      verbose: 'cyan',
      prompt: 'grey',
      good: 'green',
      staged: 'green',
      data: 'grey',
      help: 'cyan',
      important: 'yellow',
      debug: 'blue',
      important: 'blue',
      change: 'red',
      RED: 'red',
      error: 'red',
      name: 'red',
      logo: 'green',
      title: 'green',
      arg: 'white'
    });

    PRINTER.printPushResult = function(result){
        if(result.indexOf("Everything up-to-date") != -1) {
            var emoji = PRINTER.findEmoji("+1");
            console.log(":)  ".good, emoji, emoji, emoji);
        } else {
            PRINTER.print("adads"+result);
        }
    };

    PRINTER.findEmoji = function(alias) {
        var fs = require("fs");
        var emojis = JSON.parse(fs.readFileSync(__dirname + "/emoji.json").toString());
        for(var i =0; i<emojis.length; i++){
            for(var j =0; j<emojis[i].aliases.length; j++){
                if(emojis[i].aliases[j] === alias){
                    return emojis[i].emoji;
                }
            }
        }
    };

    PRINTER.statusStringIsClean = function(strings, str) {
        return strings.length >= 2 &&(strings[0].indexOf("On branch") != -1 && (strings[1].indexOf("nothing to commit") != -1 || (strings.length>=3 && strings[2].indexOf("nothing to commit") != -1)));
    };

    PRINTER.E = function(str) {
        console.log(str.error);
    };

    PRINTER.I = function(str) {
        console.log(str.important);
    };

    PRINTER.logo = function(path) {
        var fs = require('fs');
        var logo = fs.readFileSync(path).toString();
        PRINTER.printLinesWithPrefix("\t\t", logo, 'logo');
    };

    PRINTER.description = function(issueID, fields) {
        fields = JSON.parse(fields);
        var issuetype = fields.issuetype ? fields.issuetype.name || "" : "typeless";
        var status = fields.status ? fields.status.name || "" : "without any status";
        var assignee = fields.assignee ? fields.assignee.displayName || "" : "no one";
        var summary = fields.summary || "";
        PRINTER._description(issueID, summary, fields.description || "",
            status, issuetype, assignee);
    };

    PRINTER._description = function(key, summary, description, status, issuetype, assignee) {
        description = PRINTER.truncateLines(description);
        console.log(("\t|  " + key + ": " + summary).title);
        PRINTER.hr("\t|");
        console.log("\t| ", "A", ("'"+issuetype+"'").verbose, "issue that is", ("'"+status+"'").verbose, "assigned to", ("'"+assignee+"'").verbose + ".");
        PRINTER.hr("\t|");
        PRINTER.printLinesWithPrefix("\t| ", description);
    };

    PRINTER.comments = function(data) {
        var self = PRINTER;
        console.log("\t### COMMENTS ###".title);
        data = JSON.parse(data);
        if(data.comments){
            var comments = data.comments;
            for(var i=0; i<comments.length; i++) {
                var c = comments[i];
                var author =c.author.displayName;
                console.log("\t#".verbose);
                console.log("\t#".verbose, "author: ", author.name, "\t created: ", c.created.verbose, "\tupdated: "+c.updated.verbose);
                var body = self.truncateLines(c.body);
                self.printLinesWithPrefix("\t#   ", body);
            }
        }else {
            console.log("No comments");
        }
    };

    PRINTER.truncateLines = function(str) {
        var max = PRINTER.maxLineLength;
        var truncated = "";
        var strings = str.split("\n");
        for(var i =0; i<strings.length; i++) {
            var s = strings[i];
            if(s.length > max) {
                var words = s.split(" ");
                var line = "\n";

                for(var j = 0; j<words.length; j++) {
                   line += " "+words[j];
                   var next = line + (j<words.length-1 ? " " + words[j+1] : "");
                   if(next.length >= max){
                        truncated += line;
                        line = "\n";
                   }
                }
                truncated += line === "\n" ? "" : line;
            } else {
                truncated += "\n" + s;
            }
        }
        return truncated;
    };

    PRINTER.printLinesWithPrefix = function(margin, str, style) {
        var strings = str.split("\n");
        for(var i =0; i<strings.length; i++) {
            console.log((margin + strings[i])[style || 'verbose']);
        }
    };

    PRINTER.print = function(str) {
        var strings = str.split("\n");
        if(PRINTER.statusStringIsClean(strings, str)){
            console.log((" ~ "+strings[0]+ " CLEAN ~").good);
        } else {
            for(var i =0; i<strings.length; i++) {
                PRINTER.pf(strings[i], i);
            }
        }
    };

    PRINTER.printCmd = function(c) {
        var ARG = c.arg;
        while(ARG.length < 15) {
            ARG = ARG + " ";
        }
        ARG = ARG + " > ";

        console.log("\t" + ARG.arg + c.name.help);
    };

    PRINTER.logOneLiners = function(data, max) {
        var lines = data.split('\n');
        var max = max || 5;
        var stop = lines.length > max ? max : lines.length;
        for(var i=0; i<stop; i++) {
            var words = lines[i].split(" ");
            var hash = words[0];
            if(hash.length > 0){
                var message = "";
                for(var j=1; j<words.length; j++) {
                    message += " " + words[j];
                }
                message = message.trim();
                console.log("|" + hash.verbose + "| - \"" + message + "\"");
            } else {
                stop++;
                stop = stop > lines.length ? lines.length : stop;
            }
        }
        if(stop < lines.length-1) {
            console.log("...");
        }
    };

    PRINTER.printBranch = function(currentBranch) {
        process.stdout.write(PRINTER.smallMargin);
        console.log("On branch:".verbose, currentBranch);
    };

    PRINTER.pf = function(str, lineNumber){
        if(str.length==0)
            return;

        var margin = str.indexOf("On branch") != -1 ? PRINTER.smallMargin : PRINTER.margin;
        if(!PRINTER.hide(str)) {
            process.stdout.write(margin);
        }

        PRINTER.notStaged(str);
        PRINTER.untracked(str);
        PRINTER.isStaged(str);
        if(!PRINTER.hide(str)){
            if(PRINTER.isGood(str, lineNumber)) {
                console.log(str.good);
            } else if(PRINTER.isVerbose(str, lineNumber)) {
                console.log(str.verbose);
            } else if(PRINTER.isChange(str, lineNumber)) {
                console.log(str.change);
            } else if(PRINTER.isImportant(str, lineNumber)) {
                  console.log(str.important);
            } else if(PRINTER.isALineItem(str, lineNumber) || PRINTER.state == PRINTER.UNTRACKED) {
                if(PRINTER.state == PRINTER.STAGED)
                    console.log(str.staged.staged);
                else if(PRINTER.state == PRINTER.NOT_STAGED)
                    console.log(str.change);
                else if(PRINTER.state == PRINTER.UNTRACKED)
                    console.log(str.change);
                else
                    console.log(str);

            } else {
                console.log(str);
            }
        }
    };

    PRINTER.isGood = function(str, lineNumber) {
        return str.indexOf("Your branch is up-to-date") != -1 || str.indexOf("nothing to commit, working directory clean") != -1;
    };

    PRINTER.isALineItem = function(str, lineNumber) {
        return str.indexOf("modified:") != -1 || str.indexOf("new file:") != -1 || str.indexOf("deleted") != -1;
    };

    PRINTER.isVerbose = function(str, lineNumber) {
        return str.indexOf("On branch") != -1;
    };

    PRINTER.isImportant = function(str, lineNumber) {
        return PRINTER.notStaged(str) || PRINTER.untracked(str) || PRINTER.isStaged(str);
    };

    PRINTER.isStaged = function(str) {
        var b = str.indexOf("Changes to be committed:") != -1;
        if(b)
            PRINTER.state = PRINTER.STAGED;
        return b;
    };

    PRINTER.notStaged = function(str) {
        var b = str.indexOf("Changes not staged for commit:") != -1 || str.indexOf("Unstaged changes after reset:") != -1;
        if(b)
            PRINTER.state = PRINTER.NOT_STAGED;
        return b;
    };

    PRINTER.untracked = function(str){
        var b = str.indexOf("Untracked files:") != -1;
        if(b)
            PRINTER.state = PRINTER.UNTRACKED;
        return b;
    };

    PRINTER.isChange = function(str, lineNumber) {
        return false;
    };

    PRINTER.hide = function(str, lineNumber) {
        return str.indexOf("(use \"git ") != -1;
    };

    PRINTER.hr = function(prefix) {
        prefix = prefix || "";
        console.log(prefix + "----------------------------------------------------------------------------------");
    };

    return PRINTER;
}

<commit_msg>[develop] quick commit.<commit_after>module.exports = function Printer(){
    var PRINTER = {};
    PRINTER.colors = require('colors');

    PRINTER.STAGED = "STAGED";
    PRINTER.NOT_STAGED = "NOT_STAGED";
    PRINTER.UNTRACKED = "UNTRACKED";
    PRINTER.margin = "                 ";
    PRINTER.smallMargin = "          ";
    PRINTER.maxLineLength = 80;

    PRINTER.colors.setTheme({
      silly: 'rainbow',
      input: 'grey',
      verbose: 'cyan',
      prompt: 'grey',
      good: 'green',
      staged: 'green',
      data: 'grey',
      help: 'cyan',
      important: 'yellow',
      debug: 'blue',
      important: 'blue',
      change: 'red',
      RED: 'red',
      error: 'red',
      name: 'red',
      logo: 'green',
      title: 'green',
      arg: 'white'
    });

    PRINTER.printPushResult = function(result){
        if(result.indexOf("Everything up-to-date") != -1) {
            var emoji = PRINTER.findEmoji("+1");
            console.log(":)  ".good, emoji, emoji, emoji);
        } else {
            PRINTER.print(result);
        }
    };

    PRINTER.findEmoji = function(alias) {
        var fs = require("fs");
        var emojis = JSON.parse(fs.readFileSync(__dirname + "/emoji.json").toString());
        for(var i =0; i<emojis.length; i++){
            for(var j =0; j<emojis[i].aliases.length; j++){
                if(emojis[i].aliases[j] === alias){
                    return emojis[i].emoji;
                }
            }
        }
    };

    PRINTER.statusStringIsClean = function(strings, str) {
        return strings.length >= 2 &&(strings[0].indexOf("On branch") != -1 && (strings[1].indexOf("nothing to commit") != -1 || (strings.length>=3 && strings[2].indexOf("nothing to commit") != -1)));
    };

    PRINTER.E = function(str) {
        console.log(str.error);
    };

    PRINTER.I = function(str) {
        console.log(str.important);
    };

    PRINTER.logo = function(path) {
        var fs = require('fs');
        var logo = fs.readFileSync(path).toString();
        PRINTER.printLinesWithPrefix("\t\t", logo, 'logo');
    };

    PRINTER.description = function(issueID, fields) {
        fields = JSON.parse(fields);
        var issuetype = fields.issuetype ? fields.issuetype.name || "" : "typeless";
        var status = fields.status ? fields.status.name || "" : "without any status";
        var assignee = fields.assignee ? fields.assignee.displayName || "" : "no one";
        var summary = fields.summary || "";
        PRINTER._description(issueID, summary, fields.description || "",
            status, issuetype, assignee);
    };

    PRINTER._description = function(key, summary, description, status, issuetype, assignee) {
        description = PRINTER.truncateLines(description);
        console.log(("\t|  " + key + ": " + summary).title);
        PRINTER.hr("\t|");
        console.log("\t| ", "A", ("'"+issuetype+"'").verbose, "issue that is", ("'"+status+"'").verbose, "assigned to", ("'"+assignee+"'").verbose + ".");
        PRINTER.hr("\t|");
        PRINTER.printLinesWithPrefix("\t| ", description);
    };

    PRINTER.comments = function(data) {
        var self = PRINTER;
        console.log("\t### COMMENTS ###".title);
        data = JSON.parse(data);
        if(data.comments){
            var comments = data.comments;
            for(var i=0; i<comments.length; i++) {
                var c = comments[i];
                var author =c.author.displayName;
                console.log("\t#".verbose);
                console.log("\t#".verbose, "author: ", author.name, "\t created: ", c.created.verbose, "\tupdated: "+c.updated.verbose);
                var body = self.truncateLines(c.body);
                self.printLinesWithPrefix("\t#   ", body);
            }
        }else {
            console.log("No comments");
        }
    };

    PRINTER.truncateLines = function(str) {
        var max = PRINTER.maxLineLength;
        var truncated = "";
        var strings = str.split("\n");
        for(var i =0; i<strings.length; i++) {
            var s = strings[i];
            if(s.length > max) {
                var words = s.split(" ");
                var line = "\n";

                for(var j = 0; j<words.length; j++) {
                   line += " "+words[j];
                   var next = line + (j<words.length-1 ? " " + words[j+1] : "");
                   if(next.length >= max){
                        truncated += line;
                        line = "\n";
                   }
                }
                truncated += line === "\n" ? "" : line;
            } else {
                truncated += "\n" + s;
            }
        }
        return truncated;
    };

    PRINTER.printLinesWithPrefix = function(margin, str, style) {
        var strings = str.split("\n");
        for(var i =0; i<strings.length; i++) {
            console.log((margin + strings[i])[style || 'verbose']);
        }
    };

    PRINTER.print = function(str) {
        var strings = str.split("\n");
        if(PRINTER.statusStringIsClean(strings, str)){
            console.log((" ~ "+strings[0]+ " CLEAN ~").good);
        } else {
            for(var i =0; i<strings.length; i++) {
                PRINTER.pf(strings[i], i);
            }
        }
    };

    PRINTER.printCmd = function(c) {
        var ARG = c.arg;
        while(ARG.length < 15) {
            ARG = ARG + " ";
        }
        ARG = ARG + " > ";

        console.log("\t" + ARG.arg + c.name.help);
    };

    PRINTER.logOneLiners = function(data, max) {
        var lines = data.split('\n');
        var max = max || 5;
        var stop = lines.length > max ? max : lines.length;
        for(var i=0; i<stop; i++) {
            var words = lines[i].split(" ");
            var hash = words[0];
            if(hash.length > 0){
                var message = "";
                for(var j=1; j<words.length; j++) {
                    message += " " + words[j];
                }
                message = message.trim();
                console.log("|" + hash.verbose + "| - \"" + message + "\"");
            } else {
                stop++;
                stop = stop > lines.length ? lines.length : stop;
            }
        }
        if(stop < lines.length-1) {
            console.log("...");
        }
    };

    PRINTER.printBranch = function(currentBranch) {
        process.stdout.write(PRINTER.smallMargin);
        console.log("On branch:".verbose, currentBranch);
    };

    PRINTER.pf = function(str, lineNumber){
        if(str.length==0)
            return;

        var margin = str.indexOf("On branch") != -1 ? PRINTER.smallMargin : PRINTER.margin;
        if(!PRINTER.hide(str)) {
            process.stdout.write(margin);
        }

        PRINTER.notStaged(str);
        PRINTER.untracked(str);
        PRINTER.isStaged(str);
        if(!PRINTER.hide(str)){
            if(PRINTER.isGood(str, lineNumber)) {
                console.log(str.good);
            } else if(PRINTER.isVerbose(str, lineNumber)) {
                console.log(str.verbose);
            } else if(PRINTER.isChange(str, lineNumber)) {
                console.log(str.change);
            } else if(PRINTER.isImportant(str, lineNumber)) {
                  console.log(str.important);
            } else if(PRINTER.isALineItem(str, lineNumber) || PRINTER.state == PRINTER.UNTRACKED) {
                if(PRINTER.state == PRINTER.STAGED)
                    console.log(str.staged.staged);
                else if(PRINTER.state == PRINTER.NOT_STAGED)
                    console.log(str.change);
                else if(PRINTER.state == PRINTER.UNTRACKED)
                    console.log(str.change);
                else
                    console.log(str);

            } else {
                console.log(str);
            }
        }
    };

    PRINTER.isGood = function(str, lineNumber) {
        return str.indexOf("Your branch is up-to-date") != -1 || str.indexOf("nothing to commit, working directory clean") != -1;
    };

    PRINTER.isALineItem = function(str, lineNumber) {
        return str.indexOf("modified:") != -1 || str.indexOf("new file:") != -1 || str.indexOf("deleted") != -1;
    };

    PRINTER.isVerbose = function(str, lineNumber) {
        return str.indexOf("On branch") != -1;
    };

    PRINTER.isImportant = function(str, lineNumber) {
        return PRINTER.notStaged(str) || PRINTER.untracked(str) || PRINTER.isStaged(str);
    };

    PRINTER.isStaged = function(str) {
        var b = str.indexOf("Changes to be committed:") != -1;
        if(b)
            PRINTER.state = PRINTER.STAGED;
        return b;
    };

    PRINTER.notStaged = function(str) {
        var b = str.indexOf("Changes not staged for commit:") != -1 || str.indexOf("Unstaged changes after reset:") != -1;
        if(b)
            PRINTER.state = PRINTER.NOT_STAGED;
        return b;
    };

    PRINTER.untracked = function(str){
        var b = str.indexOf("Untracked files:") != -1;
        if(b)
            PRINTER.state = PRINTER.UNTRACKED;
        return b;
    };

    PRINTER.isChange = function(str, lineNumber) {
        return false;
    };

    PRINTER.hide = function(str, lineNumber) {
        return str.indexOf("(use \"git ") != -1;
    };

    PRINTER.hr = function(prefix) {
        prefix = prefix || "";
        console.log(prefix + "----------------------------------------------------------------------------------");
    };

    return PRINTER;
}

<|endoftext|>


<commit_before>var utils = require('./utils'),
    path = require('path'),
    semver = require('semver'),
    async = require('async'),
    mkdirp = require('mkdirp'),
    ncp = require('ncp').ncp,
    fs = require('fs'),
    _ = require('underscore');

var pathExists = fs.exists || path.exists;

exports.readPackageJSON = function (p, callback) {
    utils.readJSON(p, function (err, pkg) {
        if (err) {
            return callback(err, null, p);
        }
        try {
            exports.validate(pkg, p);
        }
        catch (e) {
            return callback(e);
        }
        return callback(null, pkg, p);
    });
};

/**
 * Looks for a project's package.json file. Walks up the directory tree until
 * it finds a package.json file or hits the root. Does not throw when no
 * packages.json is found, just returns null.
 *
 * @param {String} p - The starting path to search upwards from
 * @param {Function} callback(err, path)
 */

exports.findPackageJSON = function (p, callback) {
    var filename = path.resolve(p, 'package.json');
    pathExists(filename, function (exists) {
        if (exists) {
            return callback(null, filename);
        }
        var newpath = path.dirname(p);
        if (newpath === p) { // root directory
            return callback(null, null);
        }
        else {
            return exports.findPackageJSON(newpath, callback);
        }
        exports.readPackageJSON(p, callback);
    });
};

/**
 * Searches for package.json and returns an object with it's contents,
 * returns a default empty package.json object if no file found. Final
 * argument of the callback is the matching file path for package.json,
 * or null if none were found.
 *
 * @param {String} cwd - directory to search upwards from for package.json
 * @param {Function} callback(err, package_obj, path)
 */

exports.loadPackageJSON = async.memoize(function (cwd, callback) {
    exports.findPackageJSON(cwd, function (err, p) {
        if (err) {
            return callback(err, null, p);
        }
        if (!p) {
            // no package.json found, return default object
            // TODO: change the default to use jam.dependnecies
            return callback(null, {dependencies: {}}, p);
        }
        exports.readPackageJSON(p, callback);
    });
});

exports.validate = function (settings, filename) {
    // nothing to validate yet
};

/*
exports.createMeta = function (callback) {
    utils.getJamVersion(function (err, version) {
        if (err) {
            return callback(err);
        }
        callback(null, {
            jam_version: version,
            dependencies: {}
        });
    });
};

exports.writeMeta = function (package_dir, data, callback) {
    // TODO: add _rev field to meta file and check if changed since last read
    // before writing
    var filename = path.resolve(package_dir, 'jam.json');
    try {
        var str = JSON.stringify(data, null, 4);
    }
    catch (e) {
        return callback(e);
    }
    mkdirp(package_dir, function (err) {
        if (err) {
            return callback(err);
        }
        logger.info('updating', path.relative(process.cwd(), filename));
        fs.writeFile(filename, str, function (err) {
            // TODO: after adding _rev field, return updated _rev value in data here
            return callback(err, data);
        });
    });
};
*/

// adds RequireJS to project directory
exports.makeRequireJS = function (package_dir, config, callback) {
    var source = path.resolve(__dirname,'../node_modules/requirejs/require.js');
    var dest = path.resolve(package_dir, 'require.js');
    logger.info('updating', path.relative(process.cwd(), dest));
    fs.readFile(source, function (err, content) {
        if (err) {
            return callback(err);
        }
        var src = content.toString() + '\n' + config;
        fs.writeFile(dest, src, callback);
    });
};

exports.getAllPackages = function (dir, callback) {
    utils.listDirs(dir, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        async.map(dirs, function (d, cb) {
            var filename = path.resolve(d, 'package.json');
            exports.readPackageJSON(filename, function (err, cfg, p) {
                cb(err, err ? null: {cfg: cfg, dir: path.relative(dir, d)});
            });
        }, callback);
    });
};

exports.updateRequireConfig = function (package_dir, baseurl, requireConfig, callback) {

    var packages = [];
    var shims = {};

    var requireConfig = typeof requireConfig === 'function' ? {} : requireConfig || {};
    var basedir = baseurl ? path.relative(baseurl, package_dir): package_dir;
    var dir = basedir.split(path.sep).map(encodeURIComponent).join('/');

    exports.getAllPackages(package_dir, function (err, pkgs) {
        if (err) {
            return callback(err);
        }

        pkgs.forEach(function (pkg) {
            var cfg = pkg.cfg;
            var val = {
                name: cfg.name,
                location: dir + '/' + encodeURIComponent(pkg.dir)
            };
            var main = cfg.main;
            if (cfg.browser && cfg.browser.main) {
                main = cfg.browser.main;
            }
            if (cfg.jam && cfg.jam.main) {
                main = cfg.jam.main;
            }
            if (main) {
                val.main = main;
            }
            if (cfg.jam && cfg.jam.name) {
                val.name = cfg.jam.name;
            }
            packages.push(val);
            if (cfg.shim) {
                shims[cfg.name] = cfg.shim;
            }
            if (cfg.browser && cfg.browser.shim) {
                shims[cfg.name] = cfg.browser.shim;
            }
            if (cfg.jam && cfg.jam.shim) {
                shims[cfg.name] = cfg.jam.shim;
            }
            if (cfg.jam && cfg.jam.extra_packages) {
                var extra_packages = Object.keys(cfg.jam.extra_packages);
                extra_packages.forEach(function(extra_pkg){
                    var extra_val  = {
                        name: extra_pkg,
                        location: dir + '/' + encodeURIComponent(pkg.dir),
                        main: cfg.jam.extra_packages[extra_pkg].main,
                        local: true
                    }
                    packages.push(extra_val);
                    if (extra_pkg.shim) {
                        shims[extra_pkg.name] = extra_pkg.name;
                    }
                });
            }
        });

        utils.getJamVersion(function (err, version) {
            if (err) {
                return callback(err);
            }

            var data = {
                // TODO: useful option for cache-busting
                //urlArgs: '_jam_build=' + (new Date().getTime()),
                packages: packages,
                version: version,
                shim: shims
            }

            // now bring in other require.config.js options to make available
            // earlier versions had variable substitution that breaks on r.js compilation
            // now there is duplication - however, the original jam has been left untouched.
            var cfg = _.clone(requireConfig);
            cfg.packages = _.union(requireConfig.packages || [], packages);
            cfg.shim = _.extend({}, requireConfig.shim || {}, shims);
            var configStr = JSON.stringify(cfg, null, 4);

            var src = 'var jam = ' + JSON.stringify(data, null, 4) + ';\n' +
                '\n' +
                'if (typeof require !== "undefined" && require.config) {\n' +
                '    require.config(' + configStr + ');\n' +
                '}\n' +
                'else {\n' +
                '    var require = ' + configStr + ';\n' +
                '}\n' +
                '\n' +
                'if (typeof exports !== "undefined" && ' +
                    'typeof module !== "undefined") {\n' +
                '    module.exports = jam;\n' +
                '}';

            var filename = path.resolve(package_dir, 'require.config.js');
            mkdirp(package_dir, function (err) {
                if (err) {
                    return callback(err);
                }
                logger.info('updating', path.relative(process.cwd(), filename));
                async.parallel([
                    async.apply(fs.writeFile, filename, src),
                    async.apply(exports.makeRequireJS, package_dir, src)
                ], callback);
            });
        });
    });
};

exports.getJamDependencies = function (cfg) {
    if (cfg.jam && cfg.jam.dependencies) {
        return cfg.jam.dependencies;
    }
    return {};
};

exports.setJamDependencies = function (cfg, deps) {
    if (!cfg.jam) {
        cfg.jam = {};
    }
    cfg.jam.dependencies = deps;
    return cfg;
};

exports.addJamDependency = function (cfg, name, range) {
    var deps = exports.getJamDependencies(cfg);
    deps[name] = range;
    return exports.setJamDependencies(cfg, deps);
};

exports.removeJamDependency = function (cfg, name) {
    var deps = exports.getJamDependencies(cfg);
    delete deps[name];
    return exports.setJamDependencies(cfg, deps);
};
<commit_msg>make initial require config argument to updateRequireConfig optional, fixes some issues with #112<commit_after>var utils = require('./utils'),
    path = require('path'),
    semver = require('semver'),
    async = require('async'),
    mkdirp = require('mkdirp'),
    ncp = require('ncp').ncp,
    fs = require('fs'),
    _ = require('underscore');

var pathExists = fs.exists || path.exists;

exports.readPackageJSON = function (p, callback) {
    utils.readJSON(p, function (err, pkg) {
        if (err) {
            return callback(err, null, p);
        }
        try {
            exports.validate(pkg, p);
        }
        catch (e) {
            return callback(e);
        }
        return callback(null, pkg, p);
    });
};

/**
 * Looks for a project's package.json file. Walks up the directory tree until
 * it finds a package.json file or hits the root. Does not throw when no
 * packages.json is found, just returns null.
 *
 * @param {String} p - The starting path to search upwards from
 * @param {Function} callback(err, path)
 */

exports.findPackageJSON = function (p, callback) {
    var filename = path.resolve(p, 'package.json');
    pathExists(filename, function (exists) {
        if (exists) {
            return callback(null, filename);
        }
        var newpath = path.dirname(p);
        if (newpath === p) { // root directory
            return callback(null, null);
        }
        else {
            return exports.findPackageJSON(newpath, callback);
        }
        exports.readPackageJSON(p, callback);
    });
};

/**
 * Searches for package.json and returns an object with it's contents,
 * returns a default empty package.json object if no file found. Final
 * argument of the callback is the matching file path for package.json,
 * or null if none were found.
 *
 * @param {String} cwd - directory to search upwards from for package.json
 * @param {Function} callback(err, package_obj, path)
 */

exports.loadPackageJSON = async.memoize(function (cwd, callback) {
    exports.findPackageJSON(cwd, function (err, p) {
        if (err) {
            return callback(err, null, p);
        }
        if (!p) {
            // no package.json found, return default object
            // TODO: change the default to use jam.dependnecies
            return callback(null, {dependencies: {}}, p);
        }
        exports.readPackageJSON(p, callback);
    });
});

exports.validate = function (settings, filename) {
    // nothing to validate yet
};

/*
exports.createMeta = function (callback) {
    utils.getJamVersion(function (err, version) {
        if (err) {
            return callback(err);
        }
        callback(null, {
            jam_version: version,
            dependencies: {}
        });
    });
};

exports.writeMeta = function (package_dir, data, callback) {
    // TODO: add _rev field to meta file and check if changed since last read
    // before writing
    var filename = path.resolve(package_dir, 'jam.json');
    try {
        var str = JSON.stringify(data, null, 4);
    }
    catch (e) {
        return callback(e);
    }
    mkdirp(package_dir, function (err) {
        if (err) {
            return callback(err);
        }
        logger.info('updating', path.relative(process.cwd(), filename));
        fs.writeFile(filename, str, function (err) {
            // TODO: after adding _rev field, return updated _rev value in data here
            return callback(err, data);
        });
    });
};
*/

// adds RequireJS to project directory
exports.makeRequireJS = function (package_dir, config, callback) {
    var source = path.resolve(__dirname,'../node_modules/requirejs/require.js');
    var dest = path.resolve(package_dir, 'require.js');
    logger.info('updating', path.relative(process.cwd(), dest));
    fs.readFile(source, function (err, content) {
        if (err) {
            return callback(err);
        }
        var src = content.toString() + '\n' + config;
        fs.writeFile(dest, src, callback);
    });
};

exports.getAllPackages = function (dir, callback) {
    utils.listDirs(dir, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        async.map(dirs, function (d, cb) {
            var filename = path.resolve(d, 'package.json');
            exports.readPackageJSON(filename, function (err, cfg, p) {
                cb(err, err ? null: {cfg: cfg, dir: path.relative(dir, d)});
            });
        }, callback);
    });
};

exports.updateRequireConfig = function (package_dir, baseurl, /*opt*/rcfg, callback) {

    rcfg = rcfg || {};

    if (!callback) {
        callback = rcfg;
        rcfg = {};
    }

    var packages = [];
    var shims = {};

    var basedir = baseurl ? path.relative(baseurl, package_dir): package_dir;
    var dir = basedir.split(path.sep).map(encodeURIComponent).join('/');

    exports.getAllPackages(package_dir, function (err, pkgs) {
        if (err) {
            return callback(err);
        }

        pkgs.forEach(function (pkg) {
            var cfg = pkg.cfg;
            var val = {
                name: cfg.name,
                location: dir + '/' + encodeURIComponent(pkg.dir)
            };
            var main = cfg.main;
            if (cfg.browser && cfg.browser.main) {
                main = cfg.browser.main;
            }
            if (cfg.jam && cfg.jam.main) {
                main = cfg.jam.main;
            }
            if (main) {
                val.main = main;
            }
            if (cfg.jam && cfg.jam.name) {
                val.name = cfg.jam.name;
            }
            packages.push(val);
            if (cfg.shim) {
                shims[cfg.name] = cfg.shim;
            }
            if (cfg.browser && cfg.browser.shim) {
                shims[cfg.name] = cfg.browser.shim;
            }
            if (cfg.jam && cfg.jam.shim) {
                shims[cfg.name] = cfg.jam.shim;
            }
            if (cfg.jam && cfg.jam.extra_packages) {
                var extra_packages = Object.keys(cfg.jam.extra_packages);
                extra_packages.forEach(function(extra_pkg){
                    var extra_val  = {
                        name: extra_pkg,
                        location: dir + '/' + encodeURIComponent(pkg.dir),
                        main: cfg.jam.extra_packages[extra_pkg].main,
                        local: true
                    }
                    packages.push(extra_val);
                    if (extra_pkg.shim) {
                        shims[extra_pkg.name] = extra_pkg.name;
                    }
                });
            }
        });

        utils.getJamVersion(function (err, version) {
            if (err) {
                return callback(err);
            }

            var data = {
                // TODO: useful option for cache-busting
                //urlArgs: '_jam_build=' + (new Date().getTime()),
                packages: packages,
                version: version,
                shim: shims
            }

            // now bring in other require.config.js options to make available
            // earlier versions had variable substitution that breaks on r.js compilation
            // now there is duplication - however, the original jam has been left untouched.
            var cfg = _.clone(rcfg);
            cfg.packages = _.union(rcfg.packages || [], packages);
            cfg.shim = _.extend({}, rcfg.shim || {}, shims);
            var configStr = JSON.stringify(cfg, null, 4);

            var src = 'var jam = ' + JSON.stringify(data, null, 4) + ';\n' +
                '\n' +
                'if (typeof require !== "undefined" && require.config) {\n' +
                '    require.config(' + configStr + ');\n' +
                '}\n' +
                'else {\n' +
                '    var require = ' + configStr + ';\n' +
                '}\n' +
                '\n' +
                'if (typeof exports !== "undefined" && ' +
                    'typeof module !== "undefined") {\n' +
                '    module.exports = jam;\n' +
                '}';

            var filename = path.resolve(package_dir, 'require.config.js');
            mkdirp(package_dir, function (err) {
                if (err) {
                    return callback(err);
                }
                logger.info('updating', path.relative(process.cwd(), filename));
                async.parallel([
                    async.apply(fs.writeFile, filename, src),
                    async.apply(exports.makeRequireJS, package_dir, src)
                ], callback);
            });
        });
    });
};

exports.getJamDependencies = function (cfg) {
    if (cfg.jam && cfg.jam.dependencies) {
        return cfg.jam.dependencies;
    }
    return {};
};

exports.setJamDependencies = function (cfg, deps) {
    if (!cfg.jam) {
        cfg.jam = {};
    }
    cfg.jam.dependencies = deps;
    return cfg;
};

exports.addJamDependency = function (cfg, name, range) {
    var deps = exports.getJamDependencies(cfg);
    deps[name] = range;
    return exports.setJamDependencies(cfg, deps);
};

exports.removeJamDependency = function (cfg, name) {
    var deps = exports.getJamDependencies(cfg);
    delete deps[name];
    return exports.setJamDependencies(cfg, deps);
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

var raml2obj = require('raml2obj');
var program = require('commander');
var fs = require('fs');
var pjson = require('../package.json');
var nunjucks = require('nunjucks');
var Q = require('q');

function render(source, config) {
    config = config || {};
    config.raml2MdVersion = pjson.version;

    return raml2obj.parse(source).then(function(ramlObj) {
        ramlObj.config = config;

        return Q.fcall(function() {
            var result = nunjucks.render(config.template, ramlObj);
            if (config.processOutput) {
                return config.processOutput(result)
            }
            return result;
        });
    })
}

function getDefaultConfig(mainTemplate) {
    if (!mainTemplate) {
        mainTemplate = 'template.nunjucks';
        nunjucks.configure(__dirname);
    }

    return {
        template: mainTemplate,
        processOutput: function(data) {
            return data.replace(/\n{3,}/g, '\n\n');
        }
    };
}

if (require.main === module) {
    program
        .usage('[options] [RAML input file]')
        .version(pjson.version)
        .option('-i, --input [input]', 'RAML input file')
        .option('-o, --output [output]', 'Markdown output file')
        .option('-t, --template [template]', 'Path to custom template.handlebars file')
        .parse(process.argv);

    var input = program.input;

    if (!input) {
        if (program.args.length !== 1) {
            console.error('Error: You need to specify the RAML input file');
            program.help();
            process.exit(1);
        }

        input = program.args[0];
    }

    // Start the rendering process
    render(input, getDefaultConfig(program.template), function(result) {
        if (program.output) {
            fs.writeFileSync(program.output, result);
        } else {
            // Simply output to console
            process.stdout.write(result);
            process.exit(0);
        }
    }, function(error) {
        console.log('Error parsing: ' + error);
        process.exit(1);
    });
}

module.exports.getDefaultConfig = getDefaultConfig;
module.exports.render = render;
<commit_msg>Code style<commit_after>#!/usr/bin/env node

'use strict';

var raml2obj = require('raml2obj');
var program = require('commander');
var fs = require('fs');
var pjson = require('../package.json');
var nunjucks = require('nunjucks');
var Q = require('q');

function render(source, config) {
    config = config || {};
    config.raml2MdVersion = pjson.version;

    return raml2obj.parse(source).then(function(ramlObj) {
        ramlObj.config = config;

        return Q.fcall(function() {
            var result = nunjucks.render(config.template, ramlObj);
            if (config.processOutput) {
                return config.processOutput(result);
            }
            return result;
        });
    })
}

function getDefaultConfig(mainTemplate) {
    if (!mainTemplate) {
        mainTemplate = 'template.nunjucks';
        nunjucks.configure(__dirname);
    }

    return {
        template: mainTemplate,
        processOutput: function(data) {
            return data.replace(/\n{3,}/g, '\n\n');
        }
    };
}

if (require.main === module) {
    program
        .usage('[options] [RAML input file]')
        .version(pjson.version)
        .option('-i, --input [input]', 'RAML input file')
        .option('-o, --output [output]', 'Markdown output file')
        .option('-t, --template [template]', 'Path to custom template.handlebars file')
        .parse(process.argv);

    var input = program.input;

    if (!input) {
        if (program.args.length !== 1) {
            console.error('Error: You need to specify the RAML input file');
            program.help();
            process.exit(1);
        }

        input = program.args[0];
    }

    // Start the rendering process
    render(input, getDefaultConfig(program.template), function(result) {
        if (program.output) {
            fs.writeFileSync(program.output, result);
        } else {
            // Simply output to console
            process.stdout.write(result);
            process.exit(0);
        }
    }, function(error) {
        console.log('Error parsing: ' + error);
        process.exit(1);
    });
}

module.exports.getDefaultConfig = getDefaultConfig;
module.exports.render = render;
<|endoftext|>


<commit_before>'use strict';

let React = require('react-native');
let {
  Animated,
  ScrollView,
  StyleSheet,
  View,
} = React;

let ExHeader = require('./ExHeader');

const STATUS_BAR_HEIGHT = 20;

class ExScreen extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      headerScale: new Animated.Value(1),
      scrollDistance: new Animated.Value(0),
    };
  }

  render() {
    let {
      title,
      headerColor,
      scrollEnabled,
      ...props,
    } = this.props;

    return (
      <View {...props}>
        <ScrollView
          ref={component => { this._scrollView = component; }}
          contentContainerStyle={styles.contentContainer}
          contentInset={{ top: ExHeader.HEIGHT + STATUS_BAR_HEIGHT }}
          scrollEnabled={scrollEnabled}
          showsVerticalScrollIndicator={false}
          scrollEventThrottle={16}
          onScroll={this._handleScroll.bind(this)}>
          {props.children}
        </ScrollView>
        <ExHeader
          title={title}
          scrollDistance={this.state.scrollDistance}
          style={[styles.header, { backgroundColor: headerColor }]}
        />
      </View>
    );
  }

  componentDidMount() {
    this._scrollView.scrollWithoutAnimationTo(-ExHeader.HEIGHT);
  }

  _handleScroll(event) {
    let {
      contentInset: { top: topInset },
      contentOffset: { y: scrollY },
    } = event.nativeEvent;
    let scrollDistance = scrollY + topInset;
    this.state.scrollDistance.setValue(scrollDistance);
  }
}

let styles = StyleSheet.create({
  contentContainer: {
    paddingTop: 10,
  },
  header: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
  },
});

module.exports = ExScreen;
<commit_msg>[template] Update template for android<commit_after>'use strict';

let React = require('react-native');
let {
  Animated,
  ScrollView,
  StyleSheet,
  View,
} = React;

let ExHeader = require('./ExHeader');

const STATUS_BAR_HEIGHT = 20;

class ExScreen extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      headerScale: new Animated.Value(1),
      scrollDistance: new Animated.Value(0),
    };
  }

  render() {
    let {
      title,
      headerColor,
      scrollEnabled,
      ...props,
    } = this.props;

    return (
      <View {...props}>
        <ScrollView
          ref={component => { this._scrollView = component; }}
          contentContainerStyle={styles.contentContainer}
          scrollEnabled={scrollEnabled}
          showsVerticalScrollIndicator={false}
          scrollEventThrottle={16}
          onScroll={this._handleScroll.bind(this)}>
          <View style={{ height: ExHeader.HEIGHT + STATUS_BAR_HEIGHT }} />
          {props.children}
        </ScrollView>
        <ExHeader
          title={title}
          scrollDistance={this.state.scrollDistance}
          style={[styles.header, { backgroundColor: headerColor }]}
        />
      </View>
    );
  }

  _handleScroll(event) {
    let {
      contentInset: { top: topInset },
      contentOffset: { y: scrollY },
    } = event.nativeEvent;
    let scrollDistance = scrollY + topInset;
    this.state.scrollDistance.setValue(scrollDistance);
  }
}

let styles = StyleSheet.create({
  contentContainer: {
    paddingTop: 0,
  },
  header: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
  },
});

module.exports = ExScreen;
<|endoftext|>


<commit_before>'use strict'
const vstamp = require('vigour-stamp')
require('vigour-stamp/debug')(vstamp)

exports.define = {
  receive (data) {
    const hub = this
    const hubcontext = hub.context && hub.context.compute()
    if (!(!data.context && !hubcontext) && data.context != hubcontext) { //eslint-disable-line
      if (data.state && data.state.clients) {
        delete data.state.clients
      }
    }

    hub.set({ incomingStamps: {} }, false)

    // soo much faster again... saves all emits of course..
    // opt the shit out of that listener
    // 200ms to 150ms (25%!!!!)
    // false keeps the test ok which is ofc very strange...
    // something like 'incoming'
    hub.set(data.state, false) // not enough of course (false :/)

    console.log('fire recieve subscription')
    hub.emit('subscription')
    // console.log(Object.keys(hub.incomingStamps))
    for (let stamp in hub.incomingStamps) {
      vstamp.close(stamp)
    }

    hub.set({ incomingStamps: false }, false)
  }
}
<commit_msg>remove stamp debug<commit_after>'use strict'
const vstamp = require('vigour-stamp')

exports.define = {
  receive (data) {
    const hub = this
    const hubcontext = hub.context && hub.context.compute()
    if (!(!data.context && !hubcontext) && data.context != hubcontext) { //eslint-disable-line
      if (data.state && data.state.clients) {
        delete data.state.clients
      }
    }

    hub.set({ incomingStamps: {} }, false)

    // soo much faster again... saves all emits of course..
    // opt the shit out of that listener
    // 200ms to 150ms (25%!!!!)
    // false keeps the test ok which is ofc very strange...
    // something like 'incoming'
    hub.set(data.state, false) // not enough of course (false :/)

    console.log('fire recieve subscription')
    hub.emit('subscription')
    // console.log(Object.keys(hub.incomingStamps))
    for (let stamp in hub.incomingStamps) {
      vstamp.close(stamp)
    }

    hub.set({ incomingStamps: false }, false)
  }
}
<|endoftext|>


<commit_before>// Load in dependencies
var _ = require('underscore');
var assert = require('assert');
var exec = require('child_process').exec;
var async = require('async');
var quote = require('shell-quote').quote;
var semver = require('semver');

// Define constants for our environment variables based on platform
var FOUNDRY_VERSION_VAR = '$FOUNDRY_VERSION';
var FOUNDRY_MESSAGE_VAR = '$FOUNDRY_MESSAGE';
if (process.platform === 'win32') {
  FOUNDRY_VERSION_VAR = '%FOUNDRY_VERSION%';
  FOUNDRY_MESSAGE_VAR = '%FOUNDRY_MESSAGE%';
}

// Define a class to wrap release internals
function Release(releaseCommands, options) {
  // Assert against releaseCommands
  if (!Array.isArray(releaseCommands)) {
    throw new Error('foundry expected `releaseCommands` to be an array. Received: ' + JSON.stringify(releaseCommands));
  }

  // Upcast our releaseCommands from strings to objects
  // TODO: If these one-offs for `releaseCommand` become unwieldy, consider writing a `ReleaseCommand` class
  //   with abstractions for `updateFiles`/etc and `specVersion`
  releaseCommands = releaseCommands.map(function upcastReleaseCommand (releaseCommand) {
    if (typeof releaseCommand === 'string') {
      return {
        type: 'releaseCommand',
        command: releaseCommand
      };
    } else {
      return releaseCommand;
    }
  });

  // Validate each of our command types
  releaseCommands.forEach(function validateReleaseCommand (releaseCommand) {
    if (releaseCommand.type === 'releaseCommand') {
      assert(releaseCommand.command, 'Expected `releaseCommand.command` to be defined but it was not. ' +
        'Received: ' + JSON.stringify(releaseCommand));
    } else if (releaseCommand.type === 'customCommand') {
      var hasValidCommand = releaseCommand.updateFiles || releaseCommand.commit ||
        releaseCommand.publish || releaseCommand.register;
      assert(hasValidCommand, 'Expected `customCommand` to have command for `updateFiles`, `commit`, `publish`, ' +
        'or `register` but none were defined. Received: ' + JSON.stringify(releaseCommand));
    } else {
      assert.fail('Unknown `releaseCommand.type` found, expected `releaseCommand` or `customCommand`. ' +
        'Received: ' + JSON.stringify(releaseCommand));
    }
  });

  // Define commands for our release commands to have a consistent API with custom commands
  releaseCommands = releaseCommands.map(function upcastReleaseCommand (releaseCommand) {
    if (releaseCommand.type === 'releaseCommand') {
      return _.defaults({}, releaseCommand, {
        updateFiles: [releaseCommand.command, 'update-files', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        commit: [releaseCommand.command, 'commit', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        publish: [releaseCommand.command, 'publish', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        register: [releaseCommand.command, 'register', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR]
      });
    } else {
      return releaseCommand;
    }
  });

  // Save releaseCommands and options for later
  this.releaseCommands = releaseCommands;
  this.options = options || {};
}
Release.specVersion = '2.0.0';
Release.prototype = {
  validateSpecVersion: function (callback) {
    var releaseCommands = this.releaseCommands;
    async.parallel(releaseCommands, function getSpecVersion (releaseCommand, cb) {
      // If the command is a release command, get the version
      //   e.g.: foundry-release-git --spec-version
      if (releaseCommand.type === 'releaseCommand') {
        var cmd = quote([releaseCommand.command, '--spec-version']);
        exec(cmd, function handleSpecVersion (err, stdout, stderr) {
          // If there was an error
          if (err) {
            // If there was stderr, callback with it as our error
            if (stderr) {
              return cb(new Error(stderr));
            // Otherwise, callback with our error
            } else {
              return cb(err);
            }
          // Otherwise, callback with a trimmed stdout (removes any newlines)
          } else {
            return cb(null, stdout.trim());
          }
        });
      // Otherwise, assume it's foundry's version
      } else {
        process.nextTick(function replyWithFoundrySpecVersion () {
          cb(null, Release.specVersion);
        });
      }
    }, function handleSpecVersions (err, specVersions) {
      // If there was an error for any command, callback with it
      if (err) {
        return callback(err);
      }

      // Otherwise, validate our spec versions
      var i = 0;
      var len = specVersions.length;
      for (; i < len; i++) {
        // If the specVersion doesn't line up, error out with library info
        var specVersion = specVersions[i];
        if (specVersion !== Release.specVersion) {
          var releaseCommand = releaseCommands[i];
          return callback(new Error('Expected release command "' + releaseCommand.command +
            '" to have --spec-version of "' + Release.specVersion + '" but it was "' + specVersion + '"'));
        }
      }

      // Callback with no error
      return callback(null);
    });
  },
  release: function (version, cb) {
    // DEV: This is directly mimicking behavior from `git-release`
    var that = this;
    var params = {
      version: version,
      message: 'Release ' + version,
      description: null,

      // TODO: Load this from a file (e.g. ~/.config/foundry or ~/.foundry/config.json)
      config: {}
    };
    async.series([
      function validateSpecVersionFn (cb) {
        that.validateSpecVersion(cb);
      },
      function updateFilesFn (cb) {
        that.updateFiles(params, cb);
      },
      function commitFn (cb) {
        that.commit(params, cb);
      },
      function registerFn (cb) {
        // Only run register if we are at the 'register' semver (e.g. 0.1.0)
        // TODO: Make `0.1.0` as the 'registerVersion' a config setting
        if (version === '0.1.0') {
          that.register(params, cb);
        } else {
          process.nextTick(cb);
        }
      },
      function publishFn (cb) {
        that.publish(params, cb);
      }
    ], cb);
  },

  _runReleaseStep: function (step, params, cb) {
    async.forEach(this.releaseCommands, function _runReleaseCommandFn (releaseCommand, cb) {
      if (releaseCommand[step]) {
        releaseCommand[step](params, cb);
      } else {
        process.nextTick(cb);
      }
    }, cb);
  },

  updateFiles: function (params, cb) {
    this._runReleaseStep('updateFiles', params, cb);
  },
  commit: function (params, cb) {
    this._runReleaseStep('commit', params, cb);
  },
  register: function (params, cb) {
    this._runReleaseStep('register', params, cb);
  },
  publish: function (params, cb) {
    this._runReleaseStep('publish', params, cb);
  }
};

// Export Release
module.exports = Release;
<commit_msg>Completed release step<commit_after>// Load in dependencies
var _ = require('underscore');
var assert = require('assert');
var exec = require('child_process').exec;
var async = require('async');
var quote = require('shell-quote').quote;
var semver = require('semver');

// Define constants for our environment variables based on platform
var FOUNDRY_VERSION_VAR = '$FOUNDRY_VERSION';
var FOUNDRY_MESSAGE_VAR = '$FOUNDRY_MESSAGE';
if (process.platform === 'win32') {
  FOUNDRY_VERSION_VAR = '%FOUNDRY_VERSION%';
  FOUNDRY_MESSAGE_VAR = '%FOUNDRY_MESSAGE%';
}

// Define a class to wrap release internals
function Release(releaseCommands, options) {
  // Assert against releaseCommands
  if (!Array.isArray(releaseCommands)) {
    throw new Error('foundry expected `releaseCommands` to be an array. Received: ' + JSON.stringify(releaseCommands));
  }

  // Upcast our releaseCommands from strings to objects
  // TODO: If these one-offs for `releaseCommand` become unwieldy, consider writing a `ReleaseCommand` class
  //   with abstractions for `updateFiles`/etc and `specVersion`
  releaseCommands = releaseCommands.map(function upcastReleaseCommand (releaseCommand) {
    if (typeof releaseCommand === 'string') {
      return {
        type: 'releaseCommand',
        command: releaseCommand
      };
    } else {
      return releaseCommand;
    }
  });

  // Validate each of our command types
  releaseCommands.forEach(function validateReleaseCommand (releaseCommand) {
    if (releaseCommand.type === 'releaseCommand') {
      assert(releaseCommand.command, 'Expected `releaseCommand.command` to be defined but it was not. ' +
        'Received: ' + JSON.stringify(releaseCommand));
    } else if (releaseCommand.type === 'customCommand') {
      var hasValidCommand = releaseCommand.updateFiles || releaseCommand.commit ||
        releaseCommand.publish || releaseCommand.register;
      assert(hasValidCommand, 'Expected `customCommand` to have command for `updateFiles`, `commit`, `publish`, ' +
        'or `register` but none were defined. Received: ' + JSON.stringify(releaseCommand));
    } else {
      assert.fail('Unknown `releaseCommand.type` found, expected `releaseCommand` or `customCommand`. ' +
        'Received: ' + JSON.stringify(releaseCommand));
    }
  });

  // Define commands for our release commands to have a consistent API with custom commands
  releaseCommands = releaseCommands.map(function upcastReleaseCommand (releaseCommand) {
    if (releaseCommand.type === 'releaseCommand') {
      return _.defaults({}, releaseCommand, {
        updateFiles: [releaseCommand.command, 'update-files', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        commit: [releaseCommand.command, 'commit', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        publish: [releaseCommand.command, 'publish', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR],
        register: [releaseCommand.command, 'register', FOUNDRY_VERSION_VAR, FOUNDRY_MESSAGE_VAR]
      });
    } else {
      return releaseCommand;
    }
  });

  // Save releaseCommands and options for later
  this.releaseCommands = releaseCommands;
  this.options = options || {};
}
Release.specVersion = '2.0.0';
Release.prototype = {
  validateSpecVersion: function (callback) {
    var releaseCommands = this.releaseCommands;
    async.parallel(releaseCommands, function getSpecVersion (releaseCommand, cb) {
      // If the command is a release command, get the version
      //   e.g.: foundry-release-git --spec-version
      if (releaseCommand.type === 'releaseCommand') {
        var cmd = quote([releaseCommand.command, '--spec-version']);
        exec(cmd, function handleSpecVersion (err, stdout, stderr) {
          // If there was an error
          if (err) {
            // If there was stderr, callback with it as our error
            if (stderr) {
              return cb(new Error(stderr));
            // Otherwise, callback with our error
            } else {
              return cb(err);
            }
          // Otherwise, callback with a trimmed stdout (removes any newlines)
          } else {
            return cb(null, stdout.trim());
          }
        });
      // Otherwise, assume it's foundry's version
      } else {
        process.nextTick(function replyWithFoundrySpecVersion () {
          cb(null, Release.specVersion);
        });
      }
    }, function handleSpecVersions (err, specVersions) {
      // If there was an error for any command, callback with it
      if (err) {
        return callback(err);
      }

      // Otherwise, validate our spec versions
      var i = 0;
      var len = specVersions.length;
      for (; i < len; i++) {
        // If the specVersion doesn't line up, error out with library info
        var specVersion = specVersions[i];
        if (specVersion !== Release.specVersion) {
          var releaseCommand = releaseCommands[i];
          return callback(new Error('Expected release command "' + releaseCommand.command +
            '" to have --spec-version of "' + Release.specVersion + '" but it was "' + specVersion + '"'));
        }
      }

      // Callback with no error
      return callback(null);
    });
  },
  release: function (version, cb) {
    // DEV: This is directly mimicking behavior from `git-release`
    var that = this;
    var params = {
      version: version,
      message: 'Release ' + version,
      description: null,

      // TODO: Load this from a file (e.g. ~/.config/foundry or ~/.foundry/config.json)
      config: {}
    };
    async.series([
      function validateSpecVersionFn (cb) {
        that.validateSpecVersion(cb);
      },
      function updateFilesFn (cb) {
        that.updateFiles(params, cb);
      },
      function commitFn (cb) {
        that.commit(params, cb);
      },
      function registerFn (cb) {
        // Only run register if we are at the 'register' semver (e.g. 0.1.0)
        // TODO: Make `0.1.0` as the 'registerVersion' a config setting
        if (version === '0.1.0') {
          that.register(params, cb);
        } else {
          process.nextTick(cb);
        }
      },
      function publishFn (cb) {
        that.publish(params, cb);
      }
    ], cb);
  },

  _runReleaseStep: function (step, params, callback) {
    async.eachSeries(this.releaseCommands, function _runReleaseCommandFn (releaseCommand, cb) {
      // If there is a command for this step
      if (releaseCommand[step]) {
        // Log the step we are running
        console.log('Running step: ' + quote(releaseCommand[step]));

        // Prepare and run our command
        var cmd = releaseCommand[step][0];
        var cmdArgs = releaseCommand[step].slice(1);
        // TODO: Test that our `FOUNDRY_VERSION` works
        var cmdEnv = _.defaults({
          FOUNDRY_VERSION: params.version,
          FOUNDRY_MESSAGE: params.message
        }, process.env);
        var child = spawn(cmd, cmdArgs, {stdio: 'inherit', env: cmdEnv});

        // When the child exits, handle its exit code
        child.on('close', function handleChildClose (code) {
          // If the exit code was not zero, complain and leave
          if (code !== 0) {
            cb(new Error('Received non-zero exit code "' + code + '" from command "' + quote(cmd) + '"'));
          // Otherwise, do nothing
          } else {
            cb(null);
          }
        });
      // Otherwise, do nothing
      } else {
        process.nextTick(cb);
      }
    }, callback);
  },

  updateFiles: function (params, cb) {
    this._runReleaseStep('updateFiles', params, cb);
  },
  commit: function (params, cb) {
    this._runReleaseStep('commit', params, cb);
  },
  register: function (params, cb) {
    this._runReleaseStep('register', params, cb);
  },
  publish: function (params, cb) {
    this._runReleaseStep('publish', params, cb);
  }
};

// Export Release
module.exports = Release;
<|endoftext|>