Index: frontend/node_modules/text-table/.travis.yml
===================================================================
--- frontend/node_modules/text-table/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"
Index: frontend/node_modules/text-table/LICENSE
===================================================================
--- frontend/node_modules/text-table/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+This software is released under the MIT license:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/text-table/example/align.js
===================================================================
--- frontend/node_modules/text-table/example/align.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/example/align.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+var table = require('../');
+var t = table([
+    [ 'beep', '1024' ],
+    [ 'boop', '33450' ],
+    [ 'foo', '1006' ],
+    [ 'bar', '45' ]
+], { align: [ 'l', 'r' ] });
+console.log(t);
Index: frontend/node_modules/text-table/example/center.js
===================================================================
--- frontend/node_modules/text-table/example/center.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/example/center.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+var table = require('../');
+var t = table([
+    [ 'beep', '1024', 'xyz' ],
+    [ 'boop', '3388450', 'tuv' ],
+    [ 'foo', '10106', 'qrstuv' ],
+    [ 'bar', '45', 'lmno' ]
+], { align: [ 'l', 'c', 'l' ] });
+console.log(t);
Index: frontend/node_modules/text-table/example/dotalign.js
===================================================================
--- frontend/node_modules/text-table/example/dotalign.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/example/dotalign.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+var table = require('../');
+var t = table([
+    [ 'beep', '1024' ],
+    [ 'boop', '334.212' ],
+    [ 'foo', '1006' ],
+    [ 'bar', '45.6' ],
+    [ 'baz', '123.' ]
+], { align: [ 'l', '.' ] });
+console.log(t);
Index: frontend/node_modules/text-table/example/doubledot.js
===================================================================
--- frontend/node_modules/text-table/example/doubledot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/example/doubledot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+var table = require('../');
+var t = table([
+    [ '0.1.2' ],
+    [ '11.22.33' ],
+    [ '5.6.7' ],
+    [ '1.22222' ],
+    [ '12345.' ],
+    [ '5555.' ],
+    [ '123' ]
+], { align: [ '.' ] });
+console.log(t);
Index: frontend/node_modules/text-table/example/table.js
===================================================================
--- frontend/node_modules/text-table/example/table.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/example/table.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,6 @@
+var table = require('../');
+var t = table([
+    [ 'master', '0123456789abcdef' ],
+    [ 'staging', 'fedcba9876543210' ]
+]);
+console.log(t);
Index: frontend/node_modules/text-table/index.js
===================================================================
--- frontend/node_modules/text-table/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,86 @@
+module.exports = function (rows_, opts) {
+    if (!opts) opts = {};
+    var hsep = opts.hsep === undefined ? '  ' : opts.hsep;
+    var align = opts.align || [];
+    var stringLength = opts.stringLength
+        || function (s) { return String(s).length; }
+    ;
+    
+    var dotsizes = reduce(rows_, function (acc, row) {
+        forEach(row, function (c, ix) {
+            var n = dotindex(c);
+            if (!acc[ix] || n > acc[ix]) acc[ix] = n;
+        });
+        return acc;
+    }, []);
+    
+    var rows = map(rows_, function (row) {
+        return map(row, function (c_, ix) {
+            var c = String(c_);
+            if (align[ix] === '.') {
+                var index = dotindex(c);
+                var size = dotsizes[ix] + (/\./.test(c) ? 1 : 2)
+                    - (stringLength(c) - index)
+                ;
+                return c + Array(size).join(' ');
+            }
+            else return c;
+        });
+    });
+    
+    var sizes = reduce(rows, function (acc, row) {
+        forEach(row, function (c, ix) {
+            var n = stringLength(c);
+            if (!acc[ix] || n > acc[ix]) acc[ix] = n;
+        });
+        return acc;
+    }, []);
+    
+    return map(rows, function (row) {
+        return map(row, function (c, ix) {
+            var n = (sizes[ix] - stringLength(c)) || 0;
+            var s = Array(Math.max(n + 1, 1)).join(' ');
+            if (align[ix] === 'r' || align[ix] === '.') {
+                return s + c;
+            }
+            if (align[ix] === 'c') {
+                return Array(Math.ceil(n / 2 + 1)).join(' ')
+                    + c + Array(Math.floor(n / 2 + 1)).join(' ')
+                ;
+            }
+            
+            return c + s;
+        }).join(hsep).replace(/\s+$/, '');
+    }).join('\n');
+};
+
+function dotindex (c) {
+    var m = /\.[^.]*$/.exec(c);
+    return m ? m.index + 1 : c.length;
+}
+
+function reduce (xs, f, init) {
+    if (xs.reduce) return xs.reduce(f, init);
+    var i = 0;
+    var acc = arguments.length >= 3 ? init : xs[i++];
+    for (; i < xs.length; i++) {
+        f(acc, xs[i], i);
+    }
+    return acc;
+}
+
+function forEach (xs, f) {
+    if (xs.forEach) return xs.forEach(f);
+    for (var i = 0; i < xs.length; i++) {
+        f.call(xs, xs[i], i);
+    }
+}
+
+function map (xs, f) {
+    if (xs.map) return xs.map(f);
+    var res = [];
+    for (var i = 0; i < xs.length; i++) {
+        res.push(f.call(xs, xs[i], i));
+    }
+    return res;
+}
Index: frontend/node_modules/text-table/package.json
===================================================================
--- frontend/node_modules/text-table/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+{
+    "name": "text-table",
+    "version": "0.2.0",
+    "description": "borderless text tables with alignment",
+    "main": "index.js",
+    "devDependencies": {
+        "tap": "~0.4.0",
+        "tape": "~1.0.2",
+        "cli-color": "~0.2.3"
+    },
+    "scripts": {
+        "test": "tap test/*.js"
+    },
+    "testling" : {
+        "files" : "test/*.js",
+        "browsers" : [
+            "ie/6..latest",
+            "chrome/20..latest",
+            "firefox/10..latest",
+            "safari/latest",
+            "opera/11.0..latest",
+            "iphone/6", "ipad/6"
+        ]
+    },
+    "repository": {
+        "type": "git",
+        "url": "git://github.com/substack/text-table.git"
+    },
+    "homepage": "https://github.com/substack/text-table",
+    "keywords": [
+        "text",
+        "table",
+        "align",
+        "ascii",
+        "rows",
+        "tabular"
+    ],
+    "author": {
+        "name": "James Halliday",
+        "email": "mail@substack.net",
+        "url": "http://substack.net"
+    },
+    "license": "MIT"
+}
Index: frontend/node_modules/text-table/readme.markdown
===================================================================
--- frontend/node_modules/text-table/readme.markdown	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/readme.markdown	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,134 @@
+# text-table
+
+generate borderless text table strings suitable for printing to stdout
+
+[![build status](https://secure.travis-ci.org/substack/text-table.png)](http://travis-ci.org/substack/text-table)
+
+[![browser support](https://ci.testling.com/substack/text-table.png)](http://ci.testling.com/substack/text-table)
+
+# example
+
+## default align
+
+``` js
+var table = require('text-table');
+var t = table([
+    [ 'master', '0123456789abcdef' ],
+    [ 'staging', 'fedcba9876543210' ]
+]);
+console.log(t);
+```
+
+```
+master   0123456789abcdef
+staging  fedcba9876543210
+```
+
+## left-right align
+
+``` js
+var table = require('text-table');
+var t = table([
+    [ 'beep', '1024' ],
+    [ 'boop', '33450' ],
+    [ 'foo', '1006' ],
+    [ 'bar', '45' ]
+], { align: [ 'l', 'r' ] });
+console.log(t);
+```
+
+```
+beep   1024
+boop  33450
+foo    1006
+bar      45
+```
+
+## dotted align
+
+``` js
+var table = require('text-table');
+var t = table([
+    [ 'beep', '1024' ],
+    [ 'boop', '334.212' ],
+    [ 'foo', '1006' ],
+    [ 'bar', '45.6' ],
+    [ 'baz', '123.' ]
+], { align: [ 'l', '.' ] });
+console.log(t);
+```
+
+```
+beep  1024
+boop   334.212
+foo   1006
+bar     45.6
+baz    123.
+```
+
+## centered
+
+``` js
+var table = require('text-table');
+var t = table([
+    [ 'beep', '1024', 'xyz' ],
+    [ 'boop', '3388450', 'tuv' ],
+    [ 'foo', '10106', 'qrstuv' ],
+    [ 'bar', '45', 'lmno' ]
+], { align: [ 'l', 'c', 'l' ] });
+console.log(t);
+```
+
+```
+beep    1024   xyz
+boop  3388450  tuv
+foo    10106   qrstuv
+bar      45    lmno
+```
+
+# methods
+
+``` js
+var table = require('text-table')
+```
+
+## var s = table(rows, opts={})
+
+Return a formatted table string `s` from an array of `rows` and some options
+`opts`.
+
+`rows` should be an array of arrays containing strings, numbers, or other
+printable values.
+
+options can be:
+
+* `opts.hsep` - separator to use between columns, default `'  '`
+* `opts.align` - array of alignment types for each column, default `['l','l',...]`
+* `opts.stringLength` - callback function to use when calculating the string length
+
+alignment types are:
+
+* `'l'` - left
+* `'r'` - right
+* `'c'` - center
+* `'.'` - decimal
+
+# install
+
+With [npm](https://npmjs.org) do:
+
+```
+npm install text-table
+```
+
+# Use with ANSI-colors
+
+Since the string length of ANSI color schemes does not equal the length
+JavaScript sees internally it is necessary to pass the a custom string length
+calculator during the main function call.
+
+See the `test/ansi-colors.js` file for an example.
+
+# license
+
+MIT
Index: frontend/node_modules/text-table/test/align.js
===================================================================
--- frontend/node_modules/text-table/test/align.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/align.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+var test = require('tape');
+var table = require('../');
+
+test('align', function (t) {
+    t.plan(1);
+    var s = table([
+        [ 'beep', '1024' ],
+        [ 'boop', '33450' ],
+        [ 'foo', '1006' ],
+        [ 'bar', '45' ]
+    ], { align: [ 'l', 'r' ] });
+    t.equal(s, [
+        'beep   1024',
+        'boop  33450',
+        'foo    1006',
+        'bar      45'
+    ].join('\n'));
+});
Index: frontend/node_modules/text-table/test/ansi-colors.js
===================================================================
--- frontend/node_modules/text-table/test/ansi-colors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/ansi-colors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+var test = require('tape');
+var table = require('../');
+var color = require('cli-color');
+var ansiTrim = require('cli-color/lib/trim');
+
+test('center', function (t) {
+    t.plan(1);
+    var opts = {
+        align: [ 'l', 'c', 'l' ],
+        stringLength: function(s) { return ansiTrim(s).length }
+    };
+    var s = table([
+        [
+            color.red('Red'), color.green('Green'), color.blue('Blue')
+        ],
+        [
+            color.bold('Bold'), color.underline('Underline'),
+            color.italic('Italic')
+        ],
+        [
+            color.inverse('Inverse'), color.strike('Strike'),
+            color.blink('Blink')
+        ],
+        [ 'bar', '45', 'lmno' ]
+    ], opts);
+    t.equal(ansiTrim(s), [
+        'Red        Green    Blue',
+        'Bold     Underline  Italic',
+        'Inverse    Strike   Blink',
+        'bar          45     lmno'
+    ].join('\n'));
+});
Index: frontend/node_modules/text-table/test/center.js
===================================================================
--- frontend/node_modules/text-table/test/center.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/center.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+var test = require('tape');
+var table = require('../');
+
+test('center', function (t) {
+    t.plan(1);
+    var s = table([
+        [ 'beep', '1024', 'xyz' ],
+        [ 'boop', '3388450', 'tuv' ],
+        [ 'foo', '10106', 'qrstuv' ],
+        [ 'bar', '45', 'lmno' ]
+    ], { align: [ 'l', 'c', 'l' ] });
+    t.equal(s, [
+        'beep    1024   xyz',
+        'boop  3388450  tuv',
+        'foo    10106   qrstuv',
+        'bar      45    lmno'
+    ].join('\n'));
+});
Index: frontend/node_modules/text-table/test/dotalign.js
===================================================================
--- frontend/node_modules/text-table/test/dotalign.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/dotalign.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+var test = require('tape');
+var table = require('../');
+
+test('dot align', function (t) {
+    t.plan(1);
+    var s = table([
+        [ 'beep', '1024' ],
+        [ 'boop', '334.212' ],
+        [ 'foo', '1006' ],
+        [ 'bar', '45.6' ],
+        [ 'baz', '123.' ]
+    ], { align: [ 'l', '.' ] });
+    t.equal(s, [
+        'beep  1024',
+        'boop   334.212',
+        'foo   1006',
+        'bar     45.6',
+        'baz    123.'
+    ].join('\n'));
+});
Index: frontend/node_modules/text-table/test/doubledot.js
===================================================================
--- frontend/node_modules/text-table/test/doubledot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/doubledot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+var test = require('tape');
+var table = require('../');
+
+test('dot align', function (t) {
+    t.plan(1);
+    var s = table([
+        [ '0.1.2' ],
+        [ '11.22.33' ],
+        [ '5.6.7' ],
+        [ '1.22222' ],
+        [ '12345.' ],
+        [ '5555.' ],
+        [ '123' ]
+    ], { align: [ '.' ] });
+    t.equal(s, [
+        '  0.1.2',
+        '11.22.33',
+        '  5.6.7',
+        '    1.22222',
+        '12345.',
+        ' 5555.',
+        '  123'
+    ].join('\n'));
+});
Index: frontend/node_modules/text-table/test/table.js
===================================================================
--- frontend/node_modules/text-table/test/table.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/text-table/test/table.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+var test = require('tape');
+var table = require('../');
+
+test('table', function (t) {
+    t.plan(1);
+    var s = table([
+        [ 'master', '0123456789abcdef' ],
+        [ 'staging', 'fedcba9876543210' ]
+    ]);
+    t.equal(s, [
+        'master   0123456789abcdef',
+        'staging  fedcba9876543210'
+    ].join('\n'));
+});
