app.json
Version:
Create, validate, and render Heroku app.json manifests
1,448 lines (1,324 loc) • 298 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"/Users/zeke/code/hero/app.json/fake_8948f19d.js":[function(require,module,exports){
window.App = require('./')
},{"./":"/Users/zeke/code/hero/app.json/index.js"}],"/Users/zeke/code/hero/app.json/index.js":[function(require,module,exports){
(function (Buffer){
'use strict'
var url = require("url")
var http = require("http")
var hogan = require("hogan.js")
var gh = require("github-url-to-object")
var superagent = require("superagent")
var revalidator = require("revalidator")
var flatten = require("flatten")
var isURL = require("is-url")
var addons = require("./lib/addons")
var schema = require("./lib/schema")
var App = module.exports = (function() {
function App(raw) {
var key
if (typeof(raw) === 'string') {
// Filename?
if (raw.match(/\.json$/i)) {
raw = fs.readFileSync(raw)
}
try {
raw = JSON.parse(raw)
} catch(err) {
throw new Error("Malformed JSON")
}
}
for (key in raw) {
if (raw.hasOwnProperty(key)) {
this[key] = raw[key]
}
}
this.__defineGetter__("valid", function(){
return revalidator.validate(this, schema).valid
})
this.__defineGetter__("errors", function(){
return revalidator.validate(this, schema).errors
})
this.__defineGetter__("errorString", function(){
return this.errors.map(function(error) {
return ["-", error.property, error.message].join(" ")
}).join("\n")
})
this.__defineGetter__("toJSON", function(){
var key
var out = {}
var validProps = Object.keys(schema.properties)
for (key in this) {
if (this.hasOwnProperty(key) && validProps.indexOf(key) > -1) {
out[key] = this[key]
}
}
return JSON.stringify(out, null, 2)
})
return this
}
App.prototype.getAddonPrices = function(cb) {
var _this = this
App.addons.getPrices(this.addons, function(err, prices){
if (err) return cb(err)
_this.prices = prices
cb(null, prices)
})
}
App.new = function(raw) {
return new App(raw)
}
App.fetch = function(url, cb) {
if (!gh(url)) return cb("Not a valid GitHub URL: " + url)
var proxy_url = "https://github-raw-cors-proxy.herokuapp.com/" + gh(url).user + "/" + gh(url).repo + "/blob/master/app.json"
superagent.get(proxy_url, function(res){
cb(null, App.new(res.body))
})
}
// Hogan Templates FTW
App.templates = {}
if (module.parent) {
App.templates.app = hogan.compile(Buffer("PGxpIGNsYXNzPSJhcHAiPgoKICA8YSBjbGFzcz0ibG9nbyBhY3RpdmF0b3IiPgogICAgPGltZyBzcmM9Int7bG9nb319Ij4KICA8L2E+CgogIDxkaXYgY2xhc3M9Im1ldGEiPgoKICAgIDxoMj48YSBjbGFzcz0iYWN0aXZhdG9yIj57e25hbWV9fTwvYT48L2gyPgoKICAgIDxkaXYgY2xhc3M9ImRyYXdlciI+CgogICAgICB7eyNkZXNjcmlwdGlvbn19CiAgICAgICAgPHA+e3tkZXNjcmlwdGlvbn19PC9wPgogICAgICB7ey9kZXNjcmlwdGlvbn19CgogICAgICB7eyNyZXBvc2l0b3J5fX0KICAgICAgICA8YSBocmVmPSJ7e3JlcG9zaXRvcnl9fSIgY2xhc3M9InJlcG9zaXRvcnkiPnt7cmVwb3NpdG9yeX19PC9hPgogICAgICB7ey9yZXBvc2l0b3J5fX0KCiAgICAgIHt7I3dlYnNpdGV9fQogICAgICAgIDxhIGhyZWY9Int7d2Vic2l0ZX19IiBjbGFzcz0id2Vic2l0ZSI+e3t3ZWJzaXRlfX08L2E+CiAgICAgIHt7L3dlYnNpdGV9fQoKICAgICAge3sjcHJpY2VzfX0KICAgICAgICA8aDM+QWRkb25zPC9oMz4KICAgICAgICA8dWwgY2xhc3M9ImFkZG9ucyI+CiAgICAgICAgICB7eyNwbGFuc319CiAgICAgICAgICAgIDxsaT4KICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL2FkZG9ucy5oZXJva3UuY29tL3t7bmFtZX19Ij4KICAgICAgICAgICAgICAgIDxpbWcgc3JjPSJ7e2xvZ299fSI+CiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iZGVzY3JpcHRpb24iPnt7ZGVzY3JpcHRpb259fTwvc3Bhbj4KICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcmljZSI+e3twcmV0dHlQcmljZX19PC9zcGFuPgogICAgICAgICAgICAgIDwvYT4KICAgICAgICAgICAgPC9saT4KICAgICAgICAgIHt7L3BsYW5zfX0KICAgICAgICA8L3VsPgogICAgICB7ey9wcmljZXN9fQoKICAgICAgPGZvcm0gY2xhc3M9ImRlcGxveSI+CiAgICAgICAgPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0ic291cmNlIiB2YWx1ZT0ie3tyZXBvc2l0b3J5fX0iPgogICAgICAgIDxpbnB1dCB0eXBlPSJzdWJtaXQiIHZhbHVlPSJEZXBsb3kgZm9yIHt7cHJpY2VzLnRvdGFsUHJpY2V9fSI+CiAgICAgIDwvZm9ybT4KCiAgICAgIDxkaXYgY2xhc3M9Im91dHB1dCI+PC9kaXY+CgogICAgPC9kaXY+CgogIDwvZGl2PgoKPC9saT4K","base64").toString())
App.templates.build = hogan.compile(Buffer("e3sjYXBwfX0KICA8cD4KICAgIFlvdXIgYXBwIGlzIGRlcGxveWluZyB0bwogICAgPGEgaHJlZj0iaHR0cHM6Ly97e2FwcC5uYW1lfX0uaGVyb2t1YXBwLmNvbSI+e3thcHAubmFtZX19Lmhlcm9rdWFwcC5jb208L2E+LAogICAgYW5kIHdpbGwgYmUgcmVhZHkgc29vbi4KICA8L3A+Cnt7L2FwcH19Cgp7e15hcHB9fQogIDxwIGNsYXNzPSJlcnJvciI+CiAgICBCdWlsZCBmYWlsZWQuIHt7bWVzc2FnZX19CiAgPC9wPgp7ey9hcHB9fQo=","base64").toString())
App.templates.schema = hogan.compile(Buffer("YGFwcC5qc29uYCBpcyBhIG1hbmlmZXN0IGZvcm1hdCBmb3IgZGVzY3JpYmluZyB3ZWIgYXBwcy4gSXQgZGVjbGFyZXMgZW52aXJvbm1lbnQKdmFyaWFibGVzLCBhZGRvbnMsIGFuZCBvdGhlciBpbmZvcm1hdGlvbiByZXF1aXJlZCB0byBydW4gYW4gYXBwIG9uIEhlcm9rdS4gVGhpcwpkb2N1bWVudCBkZXNjcmliZXMgdGhlIHNjaGVtYSBpbiBkZXRhaWwuCgojIyBFeGFtcGxlIGFwcC5qc29uCgpgYGBqc29uCnt7e2V4YW1wbGVKU09OfX19CmBgYAoKIyMgU2NoZW1hIFJlZmVyZW5jZQoKe3sjcHJvcGVydGllc0FycmF5fX0KCiMjIyB7e25hbWV9fQoKKih7e3R5cGV9fSwge3tyZXF1aXJlZE9yT3B0aW9uYWx9fSkqIHt7ZGVzY3JpcHRpb259fQoKYGBganNvbgp7e3tleGFtcGxlSlNPTn19fQpgYGAKCnt7L3Byb3BlcnRpZXNBcnJheX19Cg==","base64").toString())
} else {
App.templates.app = require('./templates/app.mustache.html')
App.templates.build = require('./templates/build.mustache.html')
App.templates.schema = require('./templates/schema.mustache.html')
}
App.example = new App(schema.example)
App.addons = addons
App.schema = schema
return App
})()
}).call(this,require("buffer").Buffer)
},{"./lib/addons":"/Users/zeke/code/hero/app.json/lib/addons.js","./lib/schema":"/Users/zeke/code/hero/app.json/lib/schema.js","./templates/app.mustache.html":"/Users/zeke/code/hero/app.json/templates/app.mustache.html","./templates/build.mustache.html":"/Users/zeke/code/hero/app.json/templates/build.mustache.html","./templates/schema.mustache.html":"/Users/zeke/code/hero/app.json/templates/schema.mustache.html","buffer":"/Users/zeke/code/hero/app.json/node_modules/browserify/node_modules/buffer/index.js","flatten":"/Users/zeke/code/hero/app.json/node_modules/flatten/index.js","github-url-to-object":"/Users/zeke/code/hero/app.json/node_modules/github-url-to-object/index.js","hogan.js":"/Users/zeke/code/hero/app.json/node_modules/hogan.js/lib/hogan.js","http":"/Users/zeke/code/hero/app.json/node_modules/browserify/node_modules/http-browserify/index.js","is-url":"/Users/zeke/code/hero/app.json/node_modules/is-url/index.js","revalidator":"/Users/zeke/code/hero/app.json/node_modules/revalidator/lib/revalidator.js","superagent":"/Users/zeke/code/hero/app.json/node_modules/superagent/lib/client.js","url":"/Users/zeke/code/hero/app.json/node_modules/browserify/node_modules/url/url.js"}],"/Users/zeke/code/hero/app.json/lib/addons.js":[function(require,module,exports){
'use strict'
var async = require('async')
var superagent = require('superagent')
var addons = module.exports = {}
addons.getPrices = function(slugs, cb) {
// Assemble an empty API response
if (!slugs || slugs === []) {
return cb(null, {
plans: [],
totalPrice: "Free",
totalPriceInCents: 0
})
}
async.map(slugs, addons.getPlan, function(err, plans) {
if (err) return cb(err)
var prices = {}
prices.totalPriceInCents = plans.reduce(function(sum, plan) {
return plan.price.cents + sum
}, 0)
prices.totalPrice = formatPrice(prices.totalPriceInCents)
prices.plans = plans
cb(null, prices)
})
}
addons.getPlan = function(slug, cb) {
if (slug.match(/:/)) {
// format is 'addon:plan'
var addon = slug.split(":")[0]
var plan = slug.split(":")[1]
superagent
.get('https://api.heroku.com/addon-services/'+addon+'/plans/'+plan)
.set('Accept', 'application/vnd.heroku+json; version=3')
.end(function(err, res){
if (err) return cb(err)
if (res.statusCode == 404) return cb(res.body)
var plan = res.body
plan.prettyPrice = formatPrice(plan.price.cents)
plan.logo = "https://addons.heroku.com/addons/" + addon + "/icons/original.png"
cb(null, plan)
})
} else {
// plan not specified; find the default plan
superagent
.get('https://api.heroku.com/addon-services/'+slug+'/plans')
.set('Accept', 'application/vnd.heroku+json; version=3')
.end(function(err, res){
if (err) return cb(err)
if (res.statusCode == 404) return cb(res.body)
var plan = res.body.filter(function(plan) { return plan.default })[0]
plan.prettyPrice = formatPrice(plan.price.cents)
plan.logo = "https://addons.heroku.com/addons/" + slug + "/icons/original.png"
cb(null, plan)
})
}
}
function formatPrice(price) {
return (price == 0) ? "Free" : "$" + price/100 + "/mo"
}
},{"async":"/Users/zeke/code/hero/app.json/node_modules/async/lib/async.js","superagent":"/Users/zeke/code/hero/app.json/node_modules/superagent/lib/client.js"}],"/Users/zeke/code/hero/app.json/lib/schema.js":[function(require,module,exports){
'use strict'
var schema = {
"properties": {
"name": {
"description": "A clean and simple name to identify the template.",
"type": "string",
"minLength": 3,
"maxLength": 30,
"allowEmpty": false,
"example": "Small Sharp Tool"
},
"description": {
"description": "A brief summary of the app: what it does, who it's for, why it exists, etc.",
"type": "string",
"example": "This app does one little thing, and does it well."
},
"keywords": {
"description": "An array of strings describing the app.",
"type": "array",
"example": ["productivity", "HTML5", "scalpel"]
},
"website": {
"description": "The project's website.",
"type": "string",
"format": "url",
"allowEmpty": false,
"example": "https://small-sharp-tool.com/"
},
"repository": {
"description": "The location of the application's source code, such as a Git URL, GitHub URL, Subversion URL, or Mercurial URL.",
"type": "string",
"format": "url",
"allowEmpty": false,
"example": "https://github.com/jane-doe/small-sharp-tool"
},
"logo": {
"description": "The URL of the application's logo image. Dimensions should be square. Format can be SVG, PNG, or JPG.",
"type": "string",
"format": "url",
"allowEmpty": false,
"example": "https://small-sharp-tool.com/logo.svg"
},
"success_url": {
"description": "A URL specifying where to redirect the user once their new app is deployed. If value is a fully-qualified URL, the user should be redirected to that URL. If value begins with a slash `/`, the user should be redirected to that path in their newly deployed app.",
"type": "string",
"allowEmpty": false,
"example": "/welcome"
},
"scripts": {
"description": "A key-value object specifying scripts or shell commands to execute at different stages in the build/release process. Currently, `postdeploy` is the only supported script.",
"type": "object",
"example": {"postdeploy": "bundle exec rake bootstrap"}
},
"env": {
"description": "A key-value object for environment variables, or [config vars](https://devcenter.heroku.com/articles/config-vars) in Heroku parlance. Keys are the names of the environment variables. Values can be strings or objects. If the value is a string, it will be used. If the value is an object, it defines specific requirements for that variable:\n\n- `description`: a human-friendly blurb about what the value is for and how to determine what it should be\n- `value`: a default value to use. This should always be a string.\n- `required`: A boolean indicating whether the given value is required for the app to function.\n- `generator`: a string representing a function to call to generate the value. Currently the only supported generator is `secret`, which generates a pseudo-random string of characters.",
"type": "object",
"example": {
"BUILDPACK_URL": "https://github.com/stomita/heroku-buildpack-phantomjs",
"SECRET_TOKEN": {
"description": "A secret key for verifying the integrity of signed cookies.",
"generator": "secret"
},
"WEB_CONCURRENCY": {
"description": "The number of processes to run.",
"value": "5"
}
}
},
"addons": {
"description": "An array of strings specifying Heroku addons to provision on the app before deploying. Each addon should be in the format `addon:plan` or `addon`. If plan is omitted, that addon's default plan will be provisioned.",
"type": "array",
"example": [
"openredis",
"mongolab:shared-single-small"
]
}
}
}
// Assemble an example schema
schema.example = {}
Object.keys(schema.properties).map(function(key){
schema.example[key] = schema.properties[key].example
})
// Assemble a template-ready stringified version of the schema
schema.exampleJSON = JSON.stringify(schema.example, null, 2)
// Coerce schema properties into a template-friendly format
schema.propertiesArray = Object.keys(schema.properties).map(function(name) {
var prop = schema.properties[name]
prop.name = name
prop.requiredOrOptional = prop.required ? "required" : "optional"
var jsonDoc = {}
jsonDoc[prop.name] = prop.example
prop.exampleJSON = JSON.stringify(jsonDoc, null, 2)
return prop
})
module.exports = schema
},{}],"/Users/zeke/code/hero/app.json/node_modules/async/lib/async.js":[function(require,module,exports){
(function (process){
/*jshint onevar: false, indent:4 */
/*global setImmediate: false, setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root, previous_async;
root = this;
if (root != null) {
previous_async = root.async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
function only_once(fn) {
var called = false;
return function() {
if (called) throw new Error("Callback was already called.");
called = true;
fn.apply(root, arguments);
}
}
//// cross-browser compatiblity functions ////
var _toString = Object.prototype.toString;
var _isArray = Array.isArray || function (obj) {
return _toString.call(obj) === '[object Array]';
};
var _each = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_each(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_each(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof process === 'undefined' || !(process.nextTick)) {
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
async.setImmediate = async.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
async.setImmediate = async.nextTick;
}
}
else {
async.nextTick = process.nextTick;
if (typeof setImmediate !== 'undefined') {
async.setImmediate = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
}
else {
async.setImmediate = async.nextTick;
}
}
async.each = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x) {
iterator(x, only_once(done) );
});
function done(err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
}
}
};
async.forEach = async.each;
async.eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
async.forEachSeries = async.eachSeries;
async.eachLimit = function (arr, limit, iterator, callback) {
var fn = _eachLimit(limit);
fn.apply(null, [arr, iterator, callback]);
};
async.forEachLimit = async.eachLimit;
var _eachLimit = function (limit) {
return function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length || limit <= 0) {
return callback();
}
var completed = 0;
var started = 0;
var running = 0;
(function replenish () {
if (completed >= arr.length) {
return callback();
}
while (running < limit && started < arr.length) {
started += 1;
running += 1;
iterator(arr[started - 1], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
running -= 1;
if (completed >= arr.length) {
callback();
}
else {
replenish();
}
}
});
}
})();
};
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.each].concat(args));
};
};
var doParallelLimit = function(limit, fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [_eachLimit(limit)].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.eachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
async.mapLimit = function (arr, limit, iterator, callback) {
return _mapLimit(limit)(arr, iterator, callback);
};
var _mapLimit = function(limit) {
return doParallelLimit(limit, _asyncMap);
};
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.eachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
main_callback = function () {};
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
var remainingTasks = keys.length
if (!remainingTasks) {
return callback();
}
var results = {};
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
remainingTasks--
_each(listeners.slice(0), function (fn) {
fn();
});
};
addListener(function () {
if (!remainingTasks) {
var theCallback = callback;
// prevent final callback from calling itself if it errors
callback = function () {};
theCallback(null, results);
}
});
_each(keys, function (k) {
var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
var taskCallback = function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
if (err) {
var safeResults = {};
_each(_keys(results), function(rkey) {
safeResults[rkey] = results[rkey];
});
safeResults[k] = args;
callback(err, safeResults);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
results[k] = args;
async.setImmediate(taskComplete);
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
}, true) && !results.hasOwnProperty(k);
};
if (ready()) {
task[task.length - 1](taskCallback, results);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback, results);
}
};
addListener(listener);
}
});
};
async.retry = function(times, task, callback) {
var DEFAULT_TIMES = 5;
var attempts = [];
// Use defaults if times not passed
if (typeof times === 'function') {
callback = task;
task = times;
times = DEFAULT_TIMES;
}
// Make sure times is a number
times = parseInt(times, 10) || DEFAULT_TIMES;
var wrappedTask = function(wrappedCallback, wrappedResults) {
var retryAttempt = function(task, finalAttempt) {
return function(seriesCallback) {
task(function(err, result){
seriesCallback(!err || finalAttempt, {err: err, result: result});
}, wrappedResults);
};
};
while (times) {
attempts.push(retryAttempt(task, !(times-=1)));
}
async.series(attempts, function(done, data){
data = data[data.length - 1];
(wrappedCallback || callback)(data.err, data.result);
});
}
// If a callback is passed, run this as a controll flow
return callback ? wrappedTask() : wrappedTask
};
async.waterfall = function (tasks, callback) {
callback = callback || function () {};
if (!_isArray(tasks)) {
var err = new Error('First argument to waterfall must be an array of functions');
return callback(err);
}
if (!tasks.length) {
return callback();
}
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback.apply(null, arguments);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.setImmediate(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
var _parallel = function(eachfn, tasks, callback) {
callback = callback || function () {};
if (_isArray(tasks)) {
eachfn.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
eachfn.each(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.parallel = function (tasks, callback) {
_parallel({ map: async.map, each: async.each }, tasks, callback);
};
async.parallelLimit = function(tasks, limit, callback) {
_parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (_isArray(tasks)) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
async.eachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.doWhilst = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = Array.prototype.slice.call(arguments, 1);
if (test.apply(null, args)) {
async.doWhilst(iterator, test, callback);
}
else {
callback();
}
});
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.doUntil = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
var args = Array.prototype.slice.call(arguments, 1);
if (!test.apply(null, args)) {
async.doUntil(iterator, test, callback);
}
else {
callback();
}
});
};
async.queue = function (worker, concurrency) {
if (concurrency === undefined) {
concurrency = 1;
}
function _insert(q, data, pos, callback) {
if (!q.started){
q.started = true;
}
if (!_isArray(data)) {
data = [data];
}
if(data.length == 0) {
// call drain immediately if there are no tasks
return async.setImmediate(function() {
if (q.drain) {
q.drain();
}
});
}
_each(data, function(task) {
var item = {
data: task,
callback: typeof callback === 'function' ? callback : null
};
if (pos) {
q.tasks.unshift(item);
} else {
q.tasks.push(item);
}
if (q.saturated && q.tasks.length === q.concurrency) {
q.saturated();
}
async.setImmediate(q.process);
});
}
var workers = 0;
var q = {
tasks: [],
concurrency: concurrency,
saturated: null,
empty: null,
drain: null,
started: false,
paused: false,
push: function (data, callback) {
_insert(q, data, false, callback);
},
kill: function () {
q.drain = null;
q.tasks = [];
},
unshift: function (data, callback) {
_insert(q, data, true, callback);
},
process: function () {
if (!q.paused && workers < q.concurrency && q.tasks.length) {
var task = q.tasks.shift();
if (q.empty && q.tasks.length === 0) {
q.empty();
}
workers += 1;
var next = function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
if (q.drain && q.tasks.length + workers === 0) {
q.drain();
}
q.process();
};
var cb = only_once(next);
worker(task.data, cb);
}
},
length: function () {
return q.tasks.length;
},
running: function () {
return workers;
},
idle: function() {
return q.tasks.length + workers === 0;
},
pause: function () {
if (q.paused === true) { return; }
q.paused = true;
q.process();
},
resume: function () {
if (q.paused === false) { return; }
q.paused = false;
q.process();
}
};
return q;
};
async.cargo = function (worker, payload) {
var working = false,
tasks = [];
var cargo = {
tasks: tasks,
payload: payload,
saturated: null,
empty: null,
drain: null,
drained: true,
push: function (data, callback) {
if (!_isArray(data)) {
data = [data];
}
_each(data, function(task) {
tasks.push({
data: task,
callback: typeof callback === 'function' ? callback : null
});
cargo.drained = false;
if (cargo.saturated && tasks.length === payload) {
cargo.saturated();
}
});
async.setImmediate(cargo.process);
},
process: function process() {
if (working) return;
if (tasks.length === 0) {
if(cargo.drain && !cargo.drained) cargo.drain();
cargo.drained = true;
return;
}
var ts = typeof payload === 'number'
? tasks.splice(0, payload)
: tasks.splice(0, tasks.length);
var ds = _map(ts, function (task) {
return task.data;
});
if(cargo.empty) cargo.empty();
working = true;
worker(ds, function () {
working = false;
var args = arguments;
_each(ts, function (data) {
if (data.callback) {
data.callback.apply(null, args);
}
});
process();
});
},
length: function () {
return tasks.length;
},
running: function () {
return working;
}
};
return cargo;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_each(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
var queues = {};
hasher = hasher || function (x) {
return x;
};
var memoized = function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
async.nextTick(function () {
callback.apply(null, memo[key]);
});
}
else if (key in queues) {
queues[key].push(callback);
}
else {
queues[key] = [callback];
fn.apply(null, args.concat([function () {
memo[key] = arguments;
var q = queues[key];
delete queues[key];
for (var i = 0, l = q.length; i < l; i++) {
q[i].apply(null, arguments);
}
}]));
}
};
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
async.unmemoize = function (fn) {
return function () {
return (fn.unmemoized || fn).apply(null, arguments);
};
};
async.times = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.map(counter, iterator, callback);
};
async.timesSeries = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.mapSeries(counter, iterator, callback);
};
async.seq = function (/* functions... */) {
var fns = arguments;
return function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
async.reduce(fns, args, function (newargs, fn, cb) {
fn.apply(that, newargs.concat([function () {
var err = arguments[0];
var nextargs = Array.prototype.slice.call(arguments, 1);
cb(err, nextargs);
}]))
},
function (err, results) {
callback.apply(that, [err].concat(results));
});
};
};
async.compose = function (/* functions... */) {
return async.seq.apply(null, Array.prototype.reverse.call(arguments));
};
var _applyEach = function (eachfn, fns /*args...*/) {
var go = function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
return eachfn(fns, function (fn, cb) {
fn.apply(that, args.concat([cb]));
},
callback);
};
if (arguments.length > 2) {
var args = Array.prototype.slice.call(arguments, 2);
return go.apply(this, args);
}
else {
return go;
}
};
async.applyEach = doParallel(_applyEach);
async.applyEachSeries = doSeries(_applyEach);
async.forever = function (fn, callback) {
function next(err) {
if (err) {
if (callback) {
return callback(err);
}
throw err;
}
fn(next);
}
next();
};
// Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
else if (typeof define !== 'undefined' && define.amd) {
define([], function () {
return async;
});
}
// included directly via <script> tag
else {
root.async = async;
}
}());
}).call(this,require("FWaASH"))
},{"FWaASH":"/Users/zeke/code/hero/app.json/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zeke/code/hero/app.json/node_modules/browserify/node_modules/buffer/index.js":[function(require,module,exports){
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
var base64 = require('base64-js')
var ieee754 = require('ieee754')
exports.Buffer = Buffer
exports.SlowBuffer = Buffer
exports.INSPECT_MAX_BYTES = 50
Buffer.poolSize = 8192
/**
* If `Buffer._useTypedArrays`:
* === true Use Uint8Array implementation (fastest)
* === false Use Object implementation (compatible down to IE6)
*/
Buffer._useTypedArrays = (function () {
// Detect if browser supports Typed Arrays. Supported browsers are IE 10+, Firefox 4+,
// Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. If the browser does not support adding
// properties to `Uint8Array` instances, then that's the same as no `Uint8Array` support
// because we need to be able to add all the node Buffer API methods. This is an issue
// in Firefox 4-29. Now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
try {
var buf = new ArrayBuffer(0)
var arr = new Uint8Array(buf)
arr.foo = function () { return 42 }
return 42 === arr.foo() &&
typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
} catch (e) {
return false
}
})()
/**
* Class: Buffer
* =============
*
* The Buffer constructor returns instances of `Uint8Array` that are augmented
* with function properties for all the node `Buffer` API functions. We use
* `Uint8Array` so that square bracket notation works as expected -- it returns
* a single octet.
*
* By augmenting the instances, we can avoid modifying the `Uint8Array`
* prototype.
*/
function Buffer (subject, encoding, noZero) {
if (!(this instanceof Buffer))
return new Buffer(subject, encoding, noZero)
var type = typeof subject
// Workaround: node's base64 implementation allows for non-padded strings
// while base64-js does not.
if (encoding === 'base64' && type === 'string') {
subject = stringtrim(subject)
while (subject.length % 4 !== 0) {
subject = subject + '='
}
}
// Find the length
var length
if (type === 'number')
length = coerce(subject)
else if (type === 'string')
length = Buffer.byteLength(subject, encoding)
else if (type === 'object')
length = coerce(subject.length) // assume that object is array-like
else
throw new Error('First argument needs to be a number, array or string.')
var buf
if (Buffer._useTypedArrays) {
// Preferred: Return an augmented `Uint8Array` instance for best performance
buf = Buffer._augment(new Uint8Array(length))
} else {
// Fallback: Return THIS instance of Buffer (created by `new`)
buf = this
buf.length = length
buf._isBuffer = true
}
var i
if (Buffer._useTypedArrays && typeof subject.byteLength === 'number') {
// Speed optimization -- use set if we're copying from a typed array
buf._set(subject)
} else if (isArrayish(subject)) {
// Treat array-ish objects as a byte array
for (i = 0; i < length; i++) {
if (Buffer.isBuffer(subject))
buf[i] = subject.readUInt8(i)
else
buf[i] = subject[i]
}
} else if (type === 'string') {
buf.write(subject, 0, encoding)
} else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
for (i = 0; i < length; i++) {
buf[i] = 0
}
}
return buf
}
// STATIC METHODS
// ==============
Buffer.isEncoding = function (encoding) {
switch (String(encoding).toLowerCase()) {
case 'hex'