<commit_before>"use strict";

require('es6-collections');

var yaml = require('js-yaml');
var fs = Promise.promisifyAll(require('fs'));
var util = require('util');

var swaggerRouter = require('swagger-router');
var Node = swaggerRouter.Node;
var URI = swaggerRouter.URI;
var SwaggerRouter = swaggerRouter.Router;
var request_parser = require('./proxyHandler');

function Router (options) {
    this._options = options || {};
    this._nodes = new Map();
    this._modules = new Map();
    this.router = new SwaggerRouter();
}

Router.prototype._readSpec = function(path) {
    // XXX: make the spec path configurable?
    var fsPath = __dirname + '/../specs/' + path + '.yaml';
    // Let errors bubble up for now. Fail loud & early.
    return fs.readFileAsync(fsPath)
    .then(function(yamlString) {
        return yaml.safeLoad(yamlString);
    });
};

// Extend an existing route tree with a new path by walking the existing tree
// and inserting new subtrees at the desired location.
Router.prototype._buildPath = function route(node, path) {
    var params = {};
    for (var i = 0; i < path.length; i++) {
        var nextNode = node.getChild(path[i], params);
        if (!nextNode) {
            nextNode = new Node();
            node.setChild(path[i], nextNode);
            node = nextNode;
        } else {
            node = nextNode;
        }
    }
    return node;
};

Router.prototype._loadModule = function (modDef, symbols) {
    var self = this;
    var loadPath;
    // determine the module's load path
    switch (modDef.type) {
        case 'file':
            if (modDef.path && /^\//.test(modDef.path)) {
                // absolute path
                loadPath = modDef.path;
            } else {
                // relative path or missing
                loadPath = __dirname + '/../mods/';
                if (modDef.path) {
                    // the path has been provided, use it
                    loadPath += modDef.path;
                } else {
                    // no path given, so assume the file
                    // name matches the module name
                    loadPath += modDef.name;
                }
            }
            break;
        case 'npm':
            loadPath = modDef.name;
            break;
        default:
            throw new Error('unknown module type ' + modDef.type + ' (for module ' + modDef.name + ').');
    }
    // append the log property to module options, if it is not present
    modDef.options = modDef.options || {};
    if (!modDef.options.log) {
        modDef.options.log = this._options.log || function() {};
    }
    // let the error propagate in case the module cannot be loaded
    var modObj = require(loadPath);
    if (!modObj) {
        return Promise.reject("Loading module " + loadPath + " failed.");
    }
    // Call if it's a function
    if (modObj instanceof Function) {
        modObj = modObj(modDef.options);
    }
    if (!(modObj instanceof Promise)) {
        // wrap
        modObj = Promise.resolve(modObj);
    }
    return modObj.then(function(mod) {
        //console.log(loadPath, mod);
        self._modules.set(modDef, mod);
        Object.keys(mod).forEach(function(symbol) {
            // check for duplicate symbols
            if (symbol === 'module_info') {
                // skip the module info, as it should
                // be exported by each module
                return;
            } else if (symbols[symbol]) {
                throw new Error("Duplicate symbol " + symbol + " in module " + modDef.name);
            } else {
                symbols[symbol] = mod[symbol];
            }
        });
        return mod;
    });
};

// handle one spec path
Router.prototype._handleRESTBasePathSpec = function(node, subspec, symbols, uri) {
    var self = this;
    var xrb = subspec['x-restbase'];
    var xRestbasePromise;
    if (xrb) {
        symbols = symbols || {};
        xRestbasePromise = Promise.all(
            // modules
            (xrb.modules || []).map(function(m) {
                // load each module
                // Share modules
                if (!self._modules.has(m)) {
                    return self._loadModule(m, symbols)
                    .then(function(module) {
                        //console.log(module);
                        if (module && module.module_info && module.module_info.resources) {
                            node.value.resources = (node.value.resources || [])
                                .concat(module.module_info.resources);
                        }
                    });
                }
            })
        )
        .then(function() {
            // specs / interfaces
            if (Array.isArray(xrb.specs)) {
                return Promise.all(
                    xrb.specs.map(function(subSpecOrPath) {
                        var subSpecPromise;
                        if (subSpecOrPath instanceof Object) {
                            // Inline sub-spec: return directly
                            subSpecPromise = Promise.resolve(subSpecOrPath);
                        } else {
                            subSpecPromise = self._readSpec(subSpecOrPath);
                        }
                        return subSpecPromise
                        .then(function(subSpec) {
                            return self._handleRESTBaseSpec(node, subSpec, symbols, uri);
                        });
                    })
                );
            }
        });
    } else {
        // nothing to do
        xRestbasePromise = Promise.resolve();
    }

    return xRestbasePromise
    .then(function() {
        Object.keys(subspec).forEach(function(methodName) {
            if (methodName === 'x-restbase') {
                return;
            }
            // Other methods
            var method = subspec[methodName];
            var mxrb = method['x-restbase'];
            if (mxrb && mxrb.service) {
                // set up a handler
                // XXX: share?
                var eval_req = new request_parser().eval_request;
                eval_req = eval_req(mxrb.service);
                node.value.methods[methodName] = function (restbase, req) {
                    return restbase.request(eval_req(req));
                };
            } else if (method.operationId) {
                var handler = symbols[method.operationId];
                if (handler) {
                    node.value.methods[methodName] = handler;
                    node.value.m = [node.value.m, methodName];
                    //console.log(method.operationId, node.value);
                } else {
                    throw new Error('No known handler associated with operationId ' + method.operationId);
                }
            }
        });
    });
};

Router.prototype._handleRESTBaseSpec = function (rootNode, spec, modules, uri) {
    var self = this;
    function handlePaths (paths) {
        if (!paths || !Object.keys(paths).length) {
            // no paths here, nothing to do
            return Promise.resolve();
        }
        // handle paths
        return Promise.all(Object.keys(paths).map(function(pathPattern) {
            var pathSpec = paths[pathPattern];
            var pathURI = new URI(pathPattern);
            var path = pathURI.path;
            // Expected to return
            // - rootNode for single-element path
            // - a subnode for longer paths
            var branchNode = self._buildPath(rootNode, path.slice(0, path.length - 1));
            // Check if we can share the path spec
            var subtree = self._nodes.get(pathSpec);
            var specPromise;
            if (!subtree) {
                //console.log('not shared:', pathPattern);
                // Build a new tree
                subtree = new Node();
                // Set up our specific value object
                subtree.value = {
                    methods: {}
                };
                // Assign the node before building the tree, so that sharing
                // opportunities with the same spec are discovered while doing so
                self._nodes.set(pathSpec, subtree);

                // Keep track of the nesting level
                uri.pushSuffix(pathURI);
                // Handle the path spec
                specPromise = self._handleRESTBasePathSpec(subtree, pathSpec, modules, uri);
                uri.popSuffix(pathURI);
            } else {
                //console.log('shared:', pathPattern);
                subtree = subtree.clone();
                specPromise = Promise.resolve();
            }
            return specPromise
            .then(function() {

                // XXX: Set ACLs and other value properties for path
                // subtree.value.acls = ...;

                // XXX: check for conflicts!
                branchNode.setChild(path[path.length - 1], subtree);
            });
        }));
    }

    // TODO: handle global spec settings

    return handlePaths(spec.paths || {});
};

Router.prototype.handleResources = function(restbase) {
    var self = this;
    return this.tree.visitAsync(function(value, path) {
        if (value && Array.isArray(value.resources)) {
            return Promise.resolve(value.resources)
            .each(function(req) {
                if (!req.uri) {
                    throw new Error("Missing resource URI in spec for "
                            + JSON.stringify(path));
                }
                req.uri = new URI(req.uri, {
                    domain: path[0]
                });
                req.method = req.method || 'put';
                //console.log(path, req);
                return restbase.request(req);
            });
        } else {
            return Promise.resolve();
        }
    });
};

Router.prototype.loadSpec = function(spec, restbase) {
    var self = this;
    var rootNode = new Node();
    var specPromise;
    if (spec && spec.constructor === String) {
        specPromise = this._readSpec(spec);
    } else {
        specPromise = Promise.resolve(spec);
    }
    return specPromise
    .then(function(spec) {
        return self._handleRESTBaseSpec(rootNode, spec, {}, new URI([]));
    })
    .then(function() {
        // Only set the tree after loading everything
        self.tree = rootNode;
        //console.log(JSON.stringify(rootNode, null, 2));
        self.router.setTree(rootNode);
        return self.handleResources(restbase);
    })
    .then(function() {
        return self;
    });
};

Router.prototype.route = function (uri) {
    return this.router.lookup(uri);
};

module.exports = Router;
<commit_msg>Update URI parsing and -templating<commit_after>"use strict";

require('es6-collections');

var yaml = require('js-yaml');
var fs = Promise.promisifyAll(require('fs'));
var util = require('util');

var swaggerRouter = require('swagger-router');
var Node = swaggerRouter.Node;
var URI = swaggerRouter.URI;
var SwaggerRouter = swaggerRouter.Router;

function Router (options) {
    this._options = options || {};
    this._nodes = new Map();
    this._modules = new Map();
    this.router = new SwaggerRouter();
}

Router.prototype._readSpec = function(path) {
    // XXX: make the spec path configurable?
    var fsPath = __dirname + '/../specs/' + path + '.yaml';
    // Let errors bubble up for now. Fail loud & early.
    return fs.readFileAsync(fsPath)
    .then(function(yamlString) {
        return yaml.safeLoad(yamlString);
    });
};

// Extend an existing route tree with a new path by walking the existing tree
// and inserting new subtrees at the desired location.
Router.prototype._buildPath = function route(node, path) {
    var params = {};
    for (var i = 0; i < path.length; i++) {
        var nextNode = node.getChild(path[i], params);
        if (!nextNode) {
            nextNode = new Node();
            node.setChild(path[i], nextNode);
            node = nextNode;
        } else {
            node = nextNode;
        }
    }
    return node;
};

Router.prototype._loadModule = function (modDef, symbols) {
    var self = this;
    var loadPath;
    // determine the module's load path
    switch (modDef.type) {
        case 'file':
            if (modDef.path && /^\//.test(modDef.path)) {
                // absolute path
                loadPath = modDef.path;
            } else {
                // relative path or missing
                loadPath = __dirname + '/../mods/';
                if (modDef.path) {
                    // the path has been provided, use it
                    loadPath += modDef.path;
                } else {
                    // no path given, so assume the file
                    // name matches the module name
                    loadPath += modDef.name;
                }
            }
            break;
        case 'npm':
            loadPath = modDef.name;
            break;
        default:
            throw new Error('unknown module type ' + modDef.type + ' (for module ' + modDef.name + ').');
    }
    // append the log property to module options, if it is not present
    modDef.options = modDef.options || {};
    if (!modDef.options.log) {
        modDef.options.log = this._options.log || function() {};
    }
    // let the error propagate in case the module cannot be loaded
    var modObj = require(loadPath);
    if (!modObj) {
        return Promise.reject("Loading module " + loadPath + " failed.");
    }
    // Call if it's a function
    if (modObj instanceof Function) {
        modObj = modObj(modDef.options);
    }
    if (!(modObj instanceof Promise)) {
        // wrap
        modObj = Promise.resolve(modObj);
    }
    return modObj.then(function(mod) {
        //console.log(loadPath, mod);
        self._modules.set(modDef, mod);
        Object.keys(mod).forEach(function(symbol) {
            // check for duplicate symbols
            if (symbol === 'module_info') {
                // skip the module info, as it should
                // be exported by each module
                return;
            } else if (symbols[symbol]) {
                throw new Error("Duplicate symbol " + symbol + " in module " + modDef.name);
            } else {
                symbols[symbol] = mod[symbol];
            }
        });
        return mod;
    });
};

function makeRequestTemplate(spec) {
    var uri = new URI(spec.uri, {}, true);
    return function (restbase, req) {
        // FIXME:
        // - Better way to get a URI clone with parameters expanded, without
        //   going via a string.
        // - Template other request parts
        return restbase.request({
            uri: new URI(uri.bind(req.params)).toString(),
            method: req.method,
            body: req.body,
            headers: req.headers,
            query: req.query
        });
    };
};

// handle one spec path
Router.prototype._handleRESTBasePathSpec = function(node, subspec, symbols, uri) {
    var self = this;
    var xrb = subspec['x-restbase'];
    var xRestbasePromise;
    if (xrb) {
        symbols = symbols || {};
        xRestbasePromise = Promise.all(
            // modules
            (xrb.modules || []).map(function(m) {
                // load each module
                // Share modules
                if (!self._modules.has(m)) {
                    return self._loadModule(m, symbols)
                    .then(function(module) {
                        //console.log(module);
                        if (module && module.module_info && module.module_info.resources) {
                            node.value.resources = (node.value.resources || [])
                                .concat(module.module_info.resources);
                        }
                    });
                }
            })
        )
        .then(function() {
            // specs / interfaces
            if (Array.isArray(xrb.specs)) {
                return Promise.all(
                    xrb.specs.map(function(subSpecOrPath) {
                        var subSpecPromise;
                        if (subSpecOrPath instanceof Object) {
                            // Inline sub-spec: return directly
                            subSpecPromise = Promise.resolve(subSpecOrPath);
                        } else {
                            subSpecPromise = self._readSpec(subSpecOrPath);
                        }
                        return subSpecPromise
                        .then(function(subSpec) {
                            return self._handleRESTBaseSpec(node, subSpec, symbols, uri);
                        });
                    })
                );
            }
        });
    } else {
        // nothing to do
        xRestbasePromise = Promise.resolve();
    }

    return xRestbasePromise
    .then(function() {
        Object.keys(subspec).forEach(function(methodName) {
            if (methodName === 'x-restbase') {
                return;
            }
            // Other methods
            var method = subspec[methodName];
            var mxrb = method['x-restbase'];
            if (mxrb && mxrb.service) {
                // set up a handler
                // XXX: share?
                var templatedReq = makeRequestTemplate(mxrb.service);
                node.value.methods[methodName] = function (restbase, req) {
                    return templatedReq(restbase, req);
                };
            } else if (method.operationId) {
                var handler = symbols[method.operationId];
                if (handler) {
                    node.value.methods[methodName] = handler;
                    node.value.m = [node.value.m, methodName];
                    //console.log(method.operationId, node.value);
                } else {
                    throw new Error('No known handler associated with operationId ' + method.operationId);
                }
            }
        });
    });
};

Router.prototype._handleRESTBaseSpec = function (rootNode, spec, modules, uri) {
    var self = this;
    function handlePaths (paths) {
        if (!paths || !Object.keys(paths).length) {
            // no paths here, nothing to do
            return Promise.resolve();
        }
        // handle paths
        return Promise.all(Object.keys(paths).map(function(pathPattern) {
            var pathSpec = paths[pathPattern];
            var pathURI = new URI(pathPattern, {}, true);
            var path = pathURI.path;
            // Expected to return
            // - rootNode for single-element path
            // - a subnode for longer paths
            var branchNode = self._buildPath(rootNode, path.slice(0, path.length - 1));
            // Check if we can share the path spec
            var subtree = self._nodes.get(pathSpec);
            var specPromise;
            if (!subtree) {
                //console.log('not shared:', pathPattern);
                // Build a new tree
                subtree = new Node();
                // Set up our specific value object
                subtree.value = {
                    methods: {}
                };
                // Assign the node before building the tree, so that sharing
                // opportunities with the same spec are discovered while doing so
                self._nodes.set(pathSpec, subtree);

                // Keep track of the nesting level
                uri.pushSuffix(pathURI);
                // Handle the path spec
                specPromise = self._handleRESTBasePathSpec(subtree, pathSpec, modules, uri);
                uri.popSuffix(pathURI);
            } else {
                //console.log('shared:', pathPattern);
                subtree = subtree.clone();
                specPromise = Promise.resolve();
            }
            return specPromise
            .then(function() {

                // XXX: Set ACLs and other value properties for path
                // subtree.value.acls = ...;

                // XXX: check for conflicts!
                branchNode.setChild(path[path.length - 1], subtree);
            });
        }));
    }

    // TODO: handle global spec settings

    return handlePaths(spec.paths || {});
};

Router.prototype.handleResources = function(restbase) {
    var self = this;
    return this.tree.visitAsync(function(value, path) {
        if (value && Array.isArray(value.resources)) {
            return Promise.resolve(value.resources)
            .each(function(req) {
                if (!req.uri) {
                    throw new Error("Missing resource URI in spec for "
                            + JSON.stringify(path));
                }
                req.uri = new URI(req.uri, {
                    domain: path[0]
                }, true);
                req.method = req.method || 'put';
                //console.log(path, req);
                return restbase.request(req);
            });
        } else {
            return Promise.resolve();
        }
    });
};

Router.prototype.loadSpec = function(spec, restbase) {
    var self = this;
    var rootNode = new Node();
    var specPromise;
    if (spec && spec.constructor === String) {
        specPromise = this._readSpec(spec);
    } else {
        specPromise = Promise.resolve(spec);
    }
    return specPromise
    .then(function(spec) {
        return self._handleRESTBaseSpec(rootNode, spec, {}, new URI([]));
    })
    .then(function() {
        // Only set the tree after loading everything
        self.tree = rootNode;
        //console.log(JSON.stringify(rootNode, null, 2));
        self.router.setTree(rootNode);
        return self.handleResources(restbase);
    })
    .then(function() {
        return self;
    });
};

Router.prototype.route = function (uri) {
    return this.router.lookup(uri);
};

module.exports = Router;
<|endoftext|>


<commit_before>var botb_api = require('./botb_api.js');

module.exports = {

	aliases: {
		chord: 'ultrachord',
		g: 'google',
		gi: 'image',
		h: 'help',
		i: 'imdb',
		images: 'image',
		uc: 'ultrachord',
		w: 'wikipedia',
		wiki: 'wikipedia',
		y: 'youtube',
		yt: 'youtube',
		b: 'battle',
		ohc: 'battle',
		ohb: 'battle',
		compo: 'battle',
		up: 'uptime',
		pic: 'pix'
	},

	battle: function(bot, info, words) {
		var p = botb_api.request('battle/current');
		p.then(function(data) {
			data.forEach(function(battle) {
				var response = battle.title;
				// XXX bit period v entry period stuff
				response += ' :: ' + battle.entry_count + ' entries';
				response += ' :: ' + battle.period + ' period deadline';
				response += ' ' + battle.period_end_date;
				response += ' ' + battle.period_end_time_left;
				response += ' :: final results ' + battle.end_date;
				response += ' ' + battle.end_time_left;
				response += ' :: ' + battle.profile_url;
				bot.say(info.channel, response);
			});
		}).catch(function(error) {
			bot.say(info.channel, 'No current Battles teh running! =0');
		});
	},

	botbr: function(bot, info, words) {
		var name = words.slice(1).join(' ');
		if (typeof name === 'undefined' || name.length < 2) {
			bot.say(info.channel, 'Moar characters!! =X');
			return;
		}
		var p = botb_api.request('botbr/search/' + name);
		var none_found = function() {
			bot.say(info.channel, 'BotBr no found! =0');
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var botbr;
			if (data.length > 1) {
				var response;
				var botbrs = [];
				data.forEach(function(botbr_object) {
					botbrs.push(botbr_object.name);
					if (name == botbr_object.name) {
						botbr = botbr_object;
					}
				});
				if (typeof botbr === 'undefined') {
					response = 'Possible matches :: ';
					response += botbrs.join(', ');
					bot.say(info.channel, response);
					return;
				}
			}
			if (data.length == 1) {
				botbr = data[0];
			}
			var response = botbr.name;
			response += ' :: Lvl ' + botbr.level;
			response += ' ' + botbr.class;
			response += ' :: ' + botbr.profile_url;
			bot.say(info.channel, response);
		}).catch(function(error) {
			none_found();
		});
	},

	entry: function(bot, info, words) {
		var title = words.slice(1).join(' ');
		var p;
		if (typeof title === 'undefined' || title.length < 2) {
			p = botb_api.request('entry/random');
		}
		else {
			p = botb_api.request('entry/search/' + title);
		}
		var none_found = function() {
			bot.say(info.channel, 'String "' + title + '" does not match entry %title%;');
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var entry;
			if (data.length == 1) {
				entry = data[0];
			}
			if (data.length > 1) {
				entry = data[Math.floor(Math.random() * data.length)];
			}
			var response = entry.botbr.name;
			response += ' - ' + entry.title;
			response += ' :: ' + entry.profile_url;
			bot.say(info.channel, response);
		}).catch(function(error) {
			none_found();
		});
	},

	help: function(bot, info, words) {
		bot.say(info.channel, info.from + ', you have found the help');
	},

	top: function(bot, info, words) {
		var filter = words.slice(1).join(' ');
		var p;
		if (typeof filter === 'undefined' || filter.length < 2) {
			p = botb_api.request('botbr/list/0/5?sort=points&desc=true');
		}
		else {
			p = botb_api.request('botbr/list/0/5?filters=class~' + filter + '&sort=points&desc=true');
		}
		var none_found = function() {
			bot.say(info.channel, "Couldn't find anything! Did you spell the class right?");
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var response = '';
			var botbrs = [];
			data.forEach(function(botbr_object) {
				if (response !== '') {
					response += ', ';
				}
				response += botbr_object.name;
				response += ' :: ';
				response += 'Lvl ' + botbr_object.level;
				if (typeof filter === 'undefined' || filter.length < 2) {
					response += ' ' + botbr_object.class;
				}
			});
			if (response === '') {
				none_found();
			}
			else {
				bot.say(info.channel, response);
			}
		}).catch(function(error) {
			none_found();
		});
	},

	uptime: function(bot, info, words) {
		String.prototype.toHHMMSS = function () {
			var sec_num = parseInt(this, 10); // don't forget the second param
			var hours   = Math.floor(sec_num / 3600);
			var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
			var seconds = sec_num - (hours * 3600) - (minutes * 60);

			// if (hours   < 10) {hours   = "0" + hours;}
			// if (minutes < 10) {minutes = "0" + minutes;}
			// if (seconds < 10) {seconds = "0" + seconds;}
			var time    = hours + ' hours, ' + minutes + ' minutes, and ' + seconds + " seconds.";
			return time;
		}

		var time = process.uptime();
		var uptime = (time + "").toHHMMSS();

		bot.say(info.channel, "BotB has been running for " + uptime);
	},

	unknown: function(bot, info, words) {
		console.log(info.from + ' unknown command');
		bot.say(info.channel, 'you are in need of ' + info.command_prefix + 'help');
	},

	/// web commands

	google: function(bot, info, words) {
		bot.say(info.channel, "https://encrypted.google.com/search?q=" + words.slice(1).join('%20'));
	},

	image: function(bot, info, words) {
		bot.say(info.channel, "https://www.google.com/search?tbm=isch&q=" + words.slice(1).join('%20'));
	},

	wikipedia: function(bot, info, words) {
		bot.say(info.channel, "https://en.wikipedia.org/w/index.php?search=" + words.slice(1).join('%20'));
	},

	imdb: function(bot, info, words) {
		bot.say(info.channel, "http://www.imdb.com/find?s=all&q=" + words.slice(1).join('%20'));
	},

	youtube: function(bot, info, words) {
		bot.say(info.channel, "https://www.youtube.com/results?search_query=" + words.slice(1).join('%20'))
	},

	ultrachord: function(bot, info, words) { // TODO
		const execSync = require('child_process').execSync;
		var timbre = "sin"
		var note = []

		function makeid() {
    		var text = "";
    		var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

   			for(var i = 0; i < 16; i++)
    		    text += possible.charAt(Math.floor(Math.random() * possible.length));

    		return text;
		}

		var i = 0;
		var id = makeid();

		words.forEach(function() {
			switch(words[i]) {
				case "C3":
					note[i-1] = "130.8";
					break;
				case "C#3":
					note[i-1] = "138.6";
					break;
				case "Db3":
					note[i-1] = "138.6";
					break;
				case "D3":
					note[i-1] = "146.8";
					break;
				case "D#3":
					note[i-1] = "155.6";
					break;
				case "Eb3":
					note[i-1] = "155.6";
					break;
				case "E3":
					note[i-1] = "164.8";
					break;
				case "F3":
					note[i-1] = "174.6";
					break;
				case "F#3":
					note[i-1] = "185.0";
					break;
				case "Gb3":
					note[i-1] = "185.0";
					break;
				case "G3":
					note[i-1] = "196.0";
					break;
				case "G#3":
					note[i-1] = "207.7";
					break;
				case "Ab3":
					note[i-1] = "207.7";
					break;
				case "A3":
					note[i-1] = "220.0";
					break;
				case "A#3":
					note[i-1] = "233.1";
					break;
				case "Bb3":
					note[i-1] = "233.1";
					break;
				case "B3":
					note[i-1] = "246.9";
					break;
				case "C4":
					note[i-1] = "261.6";
					break;
				case "C#4":
					note[i-1] = "277.2";
					break;
				case "Db4":
					note[i-1] = "277.2";
					break;
				case "D4":
					note[i-1] = "293.7";
					break;
				case "D#4":
					note[i-1] = "311.1";
					break;
				case "Eb4":
					note[i-1] = "311.1";
					break;
				case "E4":
					note[i-1] = "329.6";
					break;
				case "F4":
					note[i-1] = "349.2";
					break;
				case "F#4":
					note[i-1] = "370.0";
					break;
				case "Gb4":
					note[i-1] = "370.0";
					break;
				case "G4":
					note[i-1] = "392.0";
					break;
				case "G#4":
					note[i-1] = "415.3";
					break;
				case "Ab4":
					note[i-1] = "415.3";
					break;
				case "A4":
					note[i-1] = "440";
					break;
				case "A#4":
					note[i-1] = "466.2";
					break;
				case "Bb4":
					note[i-1] = "466.2";
					break;
				case "B4": // B4 what?
					note[i-1] = "493.9";
					break;
				case "pluck":
					timbre = "pluck";
					break;
				case "square":
					timbre = "square";
					break;
				case "triangle":
					timbre = "triangle";
					break;
				case "sawtooth":
					timbre = "sawtooth";
					break;
				case "sin":
					timbre = "sin";
					break;
			};
			i++;
		});

		// you probably shouldn't look at this code
		console.log(note);
		console.log(words);

		code = execSync('sox -n ' + id + '.wav synth 5 ' + timbre + " " + note.join(" " + timbre + " "));
		upload = execSync('curl -i -F file=@' + id + '.wav https://uguu.se/api.php?d=upload-tool')

		var link = upload.toString().split(/\r?\n/);
		bot.say(info.args[0], link[link.length - 1]);

		console.log(link);

		del = execSync('rm ' + id + '.wav');
		bot.say(info.args[0], "toen work!")
	},

	levelup: function(bot, info, words) { // TODO

	},

	pix: function(bot, info, words) { // TODO

	}
};
<commit_msg>refactored ultrachord<commit_after>var botb_api = require('./botb_api.js');

module.exports = {

	aliases: {
		chord: 'ultrachord',
		g: 'google',
		gi: 'image',
		h: 'help',
		i: 'imdb',
		images: 'image',
		uc: 'ultrachord',
		w: 'wikipedia',
		wiki: 'wikipedia',
		y: 'youtube',
		yt: 'youtube',
		b: 'battle',
		ohc: 'battle',
		ohb: 'battle',
		compo: 'battle',
		up: 'uptime',
		pic: 'pix'
	},

	battle: function(bot, info, words) {
		var p = botb_api.request('battle/current');
		p.then(function(data) {
			data.forEach(function(battle) {
				var response = battle.title;
				// XXX bit period v entry period stuff
				response += ' :: ' + battle.entry_count + ' entries';
				response += ' :: ' + battle.period + ' period deadline';
				response += ' ' + battle.period_end_date;
				response += ' ' + battle.period_end_time_left;
				response += ' :: final results ' + battle.end_date;
				response += ' ' + battle.end_time_left;
				response += ' :: ' + battle.profile_url;
				bot.say(info.channel, response);
			});
		}).catch(function(error) {
			bot.say(info.channel, 'No current Battles teh running! =0');
		});
	},

	botbr: function(bot, info, words) {
		var name = words.slice(1).join(' ');
		if (typeof name === 'undefined' || name.length < 2) {
			bot.say(info.channel, 'Moar characters!! =X');
			return;
		}
		var p = botb_api.request('botbr/search/' + name);
		var none_found = function() {
			bot.say(info.channel, 'BotBr no found! =0');
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var botbr;
			if (data.length > 1) {
				var response;
				var botbrs = [];
				data.forEach(function(botbr_object) {
					botbrs.push(botbr_object.name);
					if (name == botbr_object.name) {
						botbr = botbr_object;
					}
				});
				if (typeof botbr === 'undefined') {
					response = 'Possible matches :: ';
					response += botbrs.join(', ');
					bot.say(info.channel, response);
					return;
				}
			}
			if (data.length == 1) {
				botbr = data[0];
			}
			var response = botbr.name;
			response += ' :: Lvl ' + botbr.level;
			response += ' ' + botbr.class;
			response += ' :: ' + botbr.profile_url;
			bot.say(info.channel, response);
		}).catch(function(error) {
			none_found();
		});
	},

	entry: function(bot, info, words) {
		var title = words.slice(1).join(' ');
		var p;
		if (typeof title === 'undefined' || title.length < 2) {
			p = botb_api.request('entry/random');
		}
		else {
			p = botb_api.request('entry/search/' + title);
		}
		var none_found = function() {
			bot.say(info.channel, 'String "' + title + '" does not match entry %title%;');
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var entry;
			if (data.length == 1) {
				entry = data[0];
			}
			if (data.length > 1) {
				entry = data[Math.floor(Math.random() * data.length)];
			}
			var response = entry.botbr.name;
			response += ' - ' + entry.title;
			response += ' :: ' + entry.profile_url;
			bot.say(info.channel, response);
		}).catch(function(error) {
			none_found();
		});
	},

	help: function(bot, info, words) {
		bot.say(info.channel, info.from + ', you have found the help');
	},

	top: function(bot, info, words) {
		var filter = words.slice(1).join(' ');
		var p;
		if (typeof filter === 'undefined' || filter.length < 2) {
			p = botb_api.request('botbr/list/0/5?sort=points&desc=true');
		}
		else {
			p = botb_api.request('botbr/list/0/5?filters=class~' + filter + '&sort=points&desc=true');
		}
		var none_found = function() {
			bot.say(info.channel, "Couldn't find anything! Did you spell the class right?");
		}
		p.then(function(data) {
			if (data.length == 0) {
				none_found();
				return;
			}
			var response = '';
			var botbrs = [];
			data.forEach(function(botbr_object) {
				if (response !== '') {
					response += ', ';
				}
				response += botbr_object.name;
				response += ' :: ';
				response += 'Lvl ' + botbr_object.level;
				if (typeof filter === 'undefined' || filter.length < 2) {
					response += ' ' + botbr_object.class;
				}
			});
			if (response === '') {
				none_found();
			}
			else {
				bot.say(info.channel, response);
			}
		}).catch(function(error) {
			none_found();
		});
	},

	uptime: function(bot, info, words) {
		String.prototype.toHHMMSS = function () {
			var sec_num = parseInt(this, 10); // don't forget the second param
			var hours   = Math.floor(sec_num / 3600);
			var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
			var seconds = sec_num - (hours * 3600) - (minutes * 60);

			// if (hours   < 10) {hours   = "0" + hours;}
			// if (minutes < 10) {minutes = "0" + minutes;}
			// if (seconds < 10) {seconds = "0" + seconds;}
			var time    = hours + ' hours, ' + minutes + ' minutes, and ' + seconds + " seconds.";
			return time;
		}

		var time = process.uptime();
		var uptime = (time + "").toHHMMSS();

		bot.say(info.channel, "BotB has been running for " + uptime);
	},

	unknown: function(bot, info, words) {
		console.log(info.from + ' unknown command');
		bot.say(info.channel, 'you are in need of ' + info.command_prefix + 'help');
	},

	/// web commands

	google: function(bot, info, words) {
		bot.say(info.channel, "https://encrypted.google.com/search?q=" + words.slice(1).join('%20'));
	},

	image: function(bot, info, words) {
		bot.say(info.channel, "https://www.google.com/search?tbm=isch&q=" + words.slice(1).join('%20'));
	},

	wikipedia: function(bot, info, words) {
		bot.say(info.channel, "https://en.wikipedia.org/w/index.php?search=" + words.slice(1).join('%20'));
	},

	imdb: function(bot, info, words) {
		bot.say(info.channel, "http://www.imdb.com/find?s=all&q=" + words.slice(1).join('%20'));
	},

	youtube: function(bot, info, words) {
		bot.say(info.channel, "https://www.youtube.com/results?search_query=" + words.slice(1).join('%20'))
	},

	ultrachord: function(bot, info, words) { // TODO
		const execSync = require('child_process').execSync;

		function makeid() {
			var text = "";
			var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
			for(var i = 0; i < 16; i++) {
				text += possible.charAt(Math.floor(Math.random() * possible.length));
			}
			return text;
		}

		var note_names = [
			'c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b',
		];
		// var note_alias = {};  // for flats!
		var note_hertz = {
			3: ['130.8', '138.6', '146.8', '155.6', '164.8', '174.6', '185.0', '196.0', '207.7', '220.0', '233.1', '246.9'],
			4: ['261.6', '277.2', '293.7', '311.1', '329.6', '349.2', '370.0', '392.0', '415.3', '440.0', '466.2', '493.9']
		};
		var timbres = ['pluck', 'square', 'triangle', 'sawtooth', 'sin'];
		var timbre = timbres[0]

		var notes = [];
		words.forEach(function(word, i) {
			var param = word.toLowerCase();
			if (timbres.indexOf(param) !== -1) {
				timbre = param;
			}
			var possible_note = word.substr(0, word.length-1);
			var note_val;
			if (note_names.indexOf(possible_note) !== -1) {
				note_val = note_names.indexOf(possible_note);
			}
			var possible_octave = parseInt(word.substr(-1), 10);
			if (Array.isArray(note_hertz[possible_octave])) {
				notes.push(note_hertz[possible_octave][note_val]);
			};
		});

		// you probably shouldn't look at this code
		console.log(notes);
		console.log(words);

		var id = makeid();
		code = execSync('sox -n ' + id + '.wav synth 5 ' + timbre + " " + notes.join(" " + timbre + " "));
		upload = execSync('curl -i -F file=@' + id + '.wav https://uguu.se/api.php?d=upload-tool')

		var link = upload.toString().split(/\r?\n/);
		bot.say(info.channel, link[link.length - 1]);

		console.log(link);

		del = execSync('rm ' + id + '.wav');
		bot.say(info.channel, "toen work!")
	},

	levelup: function(bot, info, words) { // TODO

	},

	pix: function(bot, info, words) { // TODO

	}
};
<|endoftext|>


<commit_before>var subscriptions = new SubsManager();

Router.configure({
	layoutTemplate: 'layout',
	loadingTemplate: 'loading',
	notFoundTemplate: 'notFound'
});

Router.route('/gameStats/:_id', {
	name: 'gameStats',
	waitOn: function() {
		return subscriptions.subscribe('oneGame', this.params._id);
	},
	data: function() {
		return Games.findOne(this.params._id);
	}
});

Router.route('/gameDefinition', {
	name: 'gameDefinition',
	waitOn: function() {
		return [subscriptions.subscribe('clubName'), subscriptions.subscribe('championshipLevel'), subscriptions.subscribe('championshipGroup')];
	}
});

Router.route('/myGames', {
	name: 'myGames',
	waitOn: function() {
		return subscriptions.subscribe('myGames', Meteor.userId());
	}
});

Router.route('/liveGames', {
	name: 'liveGames',
	waitOn: function() {
		return subscriptions.subscribe('liveGames');
	}
});

Router.route('/about', {
	name: 'about'
});

Router.route('/proVersionTest', {
	name: 'proVersionTest'
});

Router.route('/myAccount', {
	name: 'myAccount',
	data: function() {
		return Meteor.users.findOne({
			_id: Meteor.userId()
		});
	}
});

Router.route('/admin', {
	name: 'admin',
	waitOn: function() {
		return [subscriptions.subscribe('games'), subscriptions.subscribe('clubs'), subscriptions.subscribe("federationConfig")];
	}
});

Router.route('/createNewClub', {
	name: 'createNewClub',
	waitOn: function() {
		return subscriptions.subscribe("federationConfig");
	}
});

Router.route('/myClub', {
	name: 'myClub',
	waitOn: function() {
		return subscriptions.subscribe('myClub', Meteor.userId());
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/myClub/newTeamDefinition', {
	name: 'newTeamDefinition',
	waitOn: function() {
		return [subscriptions.subscribe("federationConfig"), subscriptions.subscribe('myClub', Meteor.userId())];
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/myClub/teamEdition', {
	name: 'teamEdition',
	waitOn: function() {
		return [subscriptions.subscribe('federationConfig'), subscriptions.subscribe('myClub', Meteor.userId())];
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/', {
	name: 'home',
	waitOn: function() {
		return [subscriptions.subscribe('last3LiveGames'), subscriptions.subscribe('last3EndedGames')];
	},
	fastRender: true
});
<commit_msg>Remove data from gameStats route<commit_after>var subscriptions = new SubsManager();

Router.configure({
	layoutTemplate: 'layout',
	loadingTemplate: 'loading',
	notFoundTemplate: 'notFound'
});

Router.route('/gameStats/:_id', {
	name: 'gameStats',
	waitOn: function() {
		return subscriptions.subscribe('oneGame', this.params._id);
	}
});

Router.route('/gameDefinition', {
	name: 'gameDefinition',
	waitOn: function() {
		return [subscriptions.subscribe('clubName'), subscriptions.subscribe('championshipLevel'), subscriptions.subscribe('championshipGroup')];
	}
});

Router.route('/myGames', {
	name: 'myGames',
	waitOn: function() {
		return subscriptions.subscribe('myGames', Meteor.userId());
	}
});

Router.route('/liveGames', {
	name: 'liveGames',
	waitOn: function() {
		return subscriptions.subscribe('liveGames');
	}
});

Router.route('/about', {
	name: 'about'
});

Router.route('/proVersionTest', {
	name: 'proVersionTest'
});

Router.route('/myAccount', {
	name: 'myAccount',
	data: function() {
		return Meteor.users.findOne({
			_id: Meteor.userId()
		});
	}
});

Router.route('/admin', {
	name: 'admin',
	waitOn: function() {
		return [subscriptions.subscribe('games'), subscriptions.subscribe('clubs'), subscriptions.subscribe("federationConfig")];
	}
});

Router.route('/createNewClub', {
	name: 'createNewClub',
	waitOn: function() {
		return subscriptions.subscribe("federationConfig");
	}
});

Router.route('/myClub', {
	name: 'myClub',
	waitOn: function() {
		return subscriptions.subscribe('myClub', Meteor.userId());
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/myClub/newTeamDefinition', {
	name: 'newTeamDefinition',
	waitOn: function() {
		return [subscriptions.subscribe("federationConfig"), subscriptions.subscribe('myClub', Meteor.userId())];
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/myClub/teamEdition', {
	name: 'teamEdition',
	waitOn: function() {
		return [subscriptions.subscribe('federationConfig'), subscriptions.subscribe('myClub', Meteor.userId())];
	},
	data: function() {
		return Clubs.findOne({
			createdBy: Meteor.userId()
		});
	}
});

Router.route('/', {
	name: 'home',
	waitOn: function() {
		return [subscriptions.subscribe('last3LiveGames'), subscriptions.subscribe('last3EndedGames')];
	},
	fastRender: true
});
<|endoftext|>


<commit_before>(function(){

  function ParameterMissing(message) {
   this.message = message;
  }
  ParameterMissing.prototype = new Error();

  var defaults = {
    prefix: 'PREFIX',
    format: 'DEFAULT_FORMAT'
  };

  var Utils = {

    serialize: function(obj){
      if (obj === null) {return '';}
      var s = [];
      for (prop in obj){
        if (obj[prop]) {
          if (obj[prop] instanceof Array) {
            for (var i=0; i < obj[prop].length; i++) {
              key = prop + encodeURIComponent("[]");
              s.push(key + "=" + encodeURIComponent(obj[prop][i].toString()));
            }
          } else {
            s.push(prop + "=" + encodeURIComponent(obj[prop].toString()));
          }
        }
      }
      if (s.length === 0) {
        return '';
      }
      return "?" + s.join('&');
    },

    clean_path: function(path) {
      return path.replace(/\/+/g, "/").replace(/[\)\(]/g, "").replace(/\.$/m, '').replace(/\/$/m, '');
    },

    set_default_format: function(options) {
      if (!options.hasOwnProperty("format")) options.format = defaults.format;
    },

    extract_anchor: function(options) {
      var anchor = options.hasOwnProperty("anchor") ? options.anchor : null;
      delete options.anchor;
      return anchor ? "#" + anchor : "";
    },

    extract_options: function(number_of_params, args) {
      if (args.length > number_of_params) {
        return typeof(args[args.length-1]) == "object" ?  args.pop() : {};
      } else {
        return {};
      }
    },

    path_identifier: function(object) {
      if (!object) {
        return "";
      }
      if (typeof(object) == "object") {
        return ((typeof(object.to_param) == "function" && object.to_param()) || object.to_param || object.id || object).toString();
      } else {
        return object.toString();
      }
    },

    build_path: function(required_parameters, route, args) {
      args = Array.prototype.slice.call(args);
      var opts = this.extract_options(required_parameters.length, args);
      this.set_default_format(opts)
      if (args.length > required_parameters.length) {
        throw new Error("Too many parameters provided for path");
      }

      var result = Utils.get_prefix();
      var anchor = Utils.extract_anchor(opts);

      for (var i=0; i < required_parameters.length; i++) {
        opts[required_parameters[i]] = args[i];
      }
      result += this.visit(route, opts)
      return Utils.clean_path(result + anchor) + Utils.serialize(opts);
    },

    visit: function(route, options) {
      var type = route[0];
      var left = route[1];
      var right = route[2];
      switch (type) {
        case "GROUP":
          try {
            return this.visit(left, options);
          } catch(e) {
            if (e instanceof ParameterMissing) {
              return "";
            } else {
              throw e;
            }
          }
        case "CAT":
          return this.visit(left, options) + this.visit(right, options);
        case "SYMBOL":
          var value = options[left];
          if (value) {
            delete options[left];
            return this.path_identifier(value);
          } else {
            throw new ParameterMissing("Route parameter missing: " + left);
          }
        //case "OR":
          //break;
        //case "STAR":
          //break;
        case "LITERAL":
          return left;
        case "SLASH":
          return left;
        case "DOT":
          return left;
        default:
          throw new Error("Unknown Rails node type");
      }

    },

    specified: function(value) {
      return !(value === undefined || value === null);
    },

    optional_part: function(part) {
      return part.match(/\(/);
    },

    get_prefix: function(){
      var prefix = defaults.prefix;

      if( prefix !== "" ){
        prefix = prefix.match('\/$') ? prefix : ( prefix + '/');
      }

      return prefix;
    }

  };

  window.NAMESPACE = ROUTES;
  window.NAMESPACE.options = defaults;
})();
<commit_msg>Cleanup<commit_after>(function(){

  function ParameterMissing(message) {
   this.message = message;
  }
  ParameterMissing.prototype = new Error();

  var defaults = {
    prefix: 'PREFIX',
    format: 'DEFAULT_FORMAT'
  };

  var Utils = {

    serialize: function(obj){
      if (obj === null) {return '';}
      var s = [];
      for (prop in obj){
        if (obj[prop]) {
          if (obj[prop] instanceof Array) {
            for (var i=0; i < obj[prop].length; i++) {
              key = prop + encodeURIComponent("[]");
              s.push(key + "=" + encodeURIComponent(obj[prop][i].toString()));
            }
          } else {
            s.push(prop + "=" + encodeURIComponent(obj[prop].toString()));
          }
        }
      }
      if (s.length === 0) {
        return '';
      }
      return "?" + s.join('&');
    },

    clean_path: function(path) {
      return path.replace(/\/+/g, "/").replace(/[\)\(]/g, "").replace(/\.$/m, '').replace(/\/$/m, '');
    },

    set_default_format: function(options) {
      if (!options.hasOwnProperty("format")) options.format = defaults.format;
    },

    extract_anchor: function(options) {
      var anchor = options.hasOwnProperty("anchor") ? options.anchor : null;
      delete options.anchor;
      return anchor ? "#" + anchor : "";
    },

    extract_options: function(number_of_params, args) {
      if (args.length > number_of_params) {
        return typeof(args[args.length-1]) == "object" ?  args.pop() : {};
      } else {
        return {};
      }
    },

    path_identifier: function(object) {
      if (!object) {
        return "";
      }
      if (typeof(object) == "object") {
        return ((typeof(object.to_param) == "function" && object.to_param()) || object.to_param || object.id || object).toString();
      } else {
        return object.toString();
      }
    },

    build_path: function(required_parameters, route, args) {
      args = Array.prototype.slice.call(args);
      var opts = this.extract_options(required_parameters.length, args);
      this.set_default_format(opts)
      if (args.length > required_parameters.length) {
        throw new Error("Too many parameters provided for path");
      }

      var result = Utils.get_prefix();
      var anchor = Utils.extract_anchor(opts);

      for (var i=0; i < required_parameters.length; i++) {
        opts[required_parameters[i]] = args[i];
      }
      result += this.visit(route, opts)
      return Utils.clean_path(result + anchor) + Utils.serialize(opts);
    },

    visit: function(route, options) {
      var type = route[0];
      var left = route[1];
      var right = route[2];
      switch (type) {
        case "GROUP":
          try {
            return this.visit(left, options);
          } catch(e) {
            if (e instanceof ParameterMissing) {
              return "";
            } else {
              throw e;
            }
          }
        case "CAT":
          return this.visit(left, options) + this.visit(right, options);
        case "SYMBOL":
          var value = options[left];
          if (value) {
            delete options[left];
            return this.path_identifier(value);
          } else {
            throw new ParameterMissing("Route parameter missing: " + left);
          }
        //case "OR":
          //break;
        //case "STAR":
          //break;
        case "LITERAL":
          return left;
        case "SLASH":
          return left;
        case "DOT":
          return left;
        default:
          throw new Error("Unknown Rails node type");
      }

    },

    get_prefix: function(){
      var prefix = defaults.prefix;

      if( prefix !== "" ){
        prefix = prefix.match('\/$') ? prefix : ( prefix + '/');
      }

      return prefix;
    }

  };

  window.NAMESPACE = ROUTES;
  window.NAMESPACE.options = defaults;
})();
<|endoftext|>


<commit_before>'use strict';

module.exports = function generateRoutes(router, modelName, actions, prefix) {
  if (prefix === null) {
    prefix = '';
  }

  router.get(prefix + ('/' + modelName), actions.findAll);
  router.get(prefix + ('/' + modelName + '/:id'), actions.findById);
  router.post(prefix + ('/' + modelName), actions.create);
  router.post(prefix + ('/' + modelName + '/:id'), actions.updateById);
  router.del(prefix + ('/' + modelName + '/:id'), actions.deleteById);
  router.put(prefix + ('/' + modelName), actions.create);
  router.put(prefix + ('/' + modelName + '/:id'), actions.replaceById);
  router.patch(prefix + ('/' + modelName + '/:id'), actions.updateById);
};
<commit_msg>refactor(routes): add  condition<commit_after>'use strict';

module.exports = function generateRoutes(router, modelName, actions, prefix) {
  if (prefix === null && typeof prefix === 'undefined') {
    prefix = '';
  }

  router.get(prefix + ('/' + modelName), actions.findAll);
  router.get(prefix + ('/' + modelName + '/:id'), actions.findById);
  router.post(prefix + ('/' + modelName), actions.create);
  router.post(prefix + ('/' + modelName + '/:id'), actions.updateById);
  router.del(prefix + ('/' + modelName + '/:id'), actions.deleteById);
  router.put(prefix + ('/' + modelName), actions.create);
  router.put(prefix + ('/' + modelName + '/:id'), actions.replaceById);
  router.patch(prefix + ('/' + modelName + '/:id'), actions.updateById);
};
<|endoftext|>


<commit_before>var proxy = require('json-proxy');
var fs = require('fs');
var path = require('path');
var authenticate = require('./auth').authenticate;
var authenticateAdmin = require('./auth').authenticateAdmin;
var request = require('request');
var util = require('util');
var nconf = require('nconf');
var _ = require('lodash');

var samlAddons = ['samlp', 'salesforce_api', 'salesforce_sandbox_api', 'salesforce', 'box', 'concur', 'sharepoint']
var wsFedAddons = ['wsfed'];

module.exports = function(app) {

  /* GET home page. */
  var mapRouteToIndex = function(route) {
    app.get(route, function(req, res, next) {
      var config = {
        auth0_client_id: nconf.get('auth0_client_id'),
        auth0_domain: nconf.get('auth0_domain'),
        app_title: nconf.get('title'),
      };
      res.render('index', {
        title: nconf.get('title'),
        config: JSON.stringify(config)
      });
    });
  };

  ['/', '/admin', '/admin/users', '/admin/settings', '/admin/clients', '/account'].map(mapRouteToIndex);

  // All requests to the API require authentication
  app.use('/api', authenticate);

  app.get('/api/apps', function(req, res) {
    request({
      // BUG: https://github.com/auth0/api2/issues/216
      //url: 'https://' + process.env.AUTH0_DOMAIN + '/api/v2/clients?fields=name,client_id,addons,global,callbacks',
      url: 'https://' + nconf.get('auth0_domain') + '/api/v2/clients',
      headers: {
        'Authorization': 'Bearer ' + nconf.get('auth0_api_token')
      }
    }, function(error, response, body) {
      var apps = JSON.parse(body);

      var filterApps = function(apps) {
        var filtered = [];
        for (var i = 0; i < apps.length; i++) {
          var app = apps[i];
          // Filter our this app and the global 'all applications' app
          if (nconf.get('auth0_client_id') !== app.client_id && app.global === false) {
            // App is allowed, now check permissions
            cleanApp(app);
            filtered.push(app);
          }
        }
        return filtered;
      };

      var getAuthProtocol = function(app) {
        if (app.addons) {
          for (var addon in app.addons) {
            if (samlAddons.indexOf(addon) > -1) {
              return 'samlp';
            } else if (wsFedAddons.indexOf(addon) > -1) {
              return 'ws-fed';
            }
          }
        }

        return 'openid-connect';
      }

      var cleanApp = function(app) {
        var authProtocol = getAuthProtocol(app);
        switch (authProtocol) {
          case 'samlp':
            app.login_url = util.format(
              'https://%s/samlp/%s',
              nconf.get('auth0_domain'),
              app.client_id);
            break;
          case 'ws-fed':
            app.login_url = 'https://ws-fed';
            break;
          case 'openid-connect':
            app.login_url = util.format(
              'https://%s/authorize?response_type=code&scope=openid&client_id=%s&redirect_uri=%s&connection=%s',
              nconf.get('auth0_domain'),
              app.client_id,
              app.callbacks[0], // Select the first callback url, this isn't really ideal though
              process.env.AUTH0_CONNECTION)
            break;
          default:
            throw 'unknown auth protocol';
        }
        delete app.addons;
        delete app.callbacks

        app.logo_url = '/img/logos/auth0.png';
        var clients = nconf.get('clients');
        var clientData = _.find(clients, { 'client_id': app.client_id });
        if (clientData) {
          if (clientData.logo_url) {
            app.logo_url = clientData.logo_url;
          }
        }
      };

      var filteredApps = filterApps(apps);
      res.json(filteredApps);
    });
  });

  //app.use('/api/proxy', authenticateAdmin);

  app.use(proxy.initialize({
    proxy: {
      forward: {
        '/api/proxy/(.*)': 'https://' + nconf.get('auth0_domain') + '/api/v2/$1'
      },
      headers: {
        'Authorization': 'Bearer ' + nconf.get('auth0_api_token')
      }
    }
  }));
};
<commit_msg>Updated apps url after bug fix<commit_after>var proxy = require('json-proxy');
var fs = require('fs');
var path = require('path');
var authenticate = require('./auth').authenticate;
var authenticateAdmin = require('./auth').authenticateAdmin;
var request = require('request');
var util = require('util');
var nconf = require('nconf');
var _ = require('lodash');

var samlAddons = ['samlp', 'salesforce_api', 'salesforce_sandbox_api', 'salesforce', 'box', 'concur', 'sharepoint']
var wsFedAddons = ['wsfed'];

module.exports = function(app) {

  /* GET home page. */
  var mapRouteToIndex = function(route) {
    app.get(route, function(req, res, next) {
      var config = {
        auth0_client_id: nconf.get('auth0_client_id'),
        auth0_domain: nconf.get('auth0_domain'),
        app_title: nconf.get('title'),
      };
      res.render('index', {
        title: nconf.get('title'),
        config: JSON.stringify(config)
      });
    });
  };

  ['/', '/admin', '/admin/users', '/admin/settings', '/admin/clients', '/account'].map(mapRouteToIndex);

  // All requests to the API require authentication
  app.use('/api', authenticate);

  app.get('/api/apps', function(req, res) {
    request({
      url: 'https://' + nconf.get('auth0_domain') + '/api/v2/clients?fields=name,client_id,addons,global,callbacks',
      headers: {
        'Authorization': 'Bearer ' + nconf.get('auth0_api_token')
      }
    }, function(error, response, body) {
      var apps = JSON.parse(body);

      var filterApps = function(apps) {
        var filtered = [];
        for (var i = 0; i < apps.length; i++) {
          var app = apps[i];
          // Filter our this app and the global 'all applications' app
          if (nconf.get('auth0_client_id') !== app.client_id && app.global === false) {
            // App is allowed, now check permissions
            cleanApp(app);
            filtered.push(app);
          }
        }
        return filtered;
      };

      var getAuthProtocol = function(app) {
        if (app.addons) {
          for (var addon in app.addons) {
            if (samlAddons.indexOf(addon) > -1) {
              return 'samlp';
            } else if (wsFedAddons.indexOf(addon) > -1) {
              return 'ws-fed';
            }
          }
        }

        return 'openid-connect';
      }

      var cleanApp = function(app) {
        var authProtocol = getAuthProtocol(app);
        switch (authProtocol) {
          case 'samlp':
            app.login_url = util.format(
              'https://%s/samlp/%s',
              nconf.get('auth0_domain'),
              app.client_id);
            break;
          case 'ws-fed':
            app.login_url = 'https://ws-fed';
            break;
          case 'openid-connect':
            app.login_url = util.format(
              'https://%s/authorize?response_type=code&scope=openid&client_id=%s&redirect_uri=%s&connection=%s',
              nconf.get('auth0_domain'),
              app.client_id,
              app.callbacks[0], // Select the first callback url, this isn't really ideal though
              process.env.AUTH0_CONNECTION)
            break;
          default:
            throw 'unknown auth protocol';
        }
        delete app.addons;
        delete app.callbacks

        app.logo_url = '/img/logos/auth0.png';
        var clients = nconf.get('clients');
        var clientData = _.find(clients, { 'client_id': app.client_id });
        if (clientData) {
          if (clientData.logo_url) {
            app.logo_url = clientData.logo_url;
          }
        }
      };

      var filteredApps = filterApps(apps);
      res.json(filteredApps);
    });
  });

  //app.use('/api/proxy', authenticateAdmin);

  app.use(proxy.initialize({
    proxy: {
      forward: {
        '/api/proxy/(.*)': 'https://' + nconf.get('auth0_domain') + '/api/v2/$1'
      },
      headers: {
        'Authorization': 'Bearer ' + nconf.get('auth0_api_token')
      }
    }
  }));
};
<|endoftext|>


<commit_before>'use strict';

var logger = require('./logger');

var mock = false;

var plugins;
var lamassuConfig;

module.exports = {
  init: init,
  getFingerprint: getFingerprint
};

// Make sure these are higher than polling interval
// or there will be a lot of errors
var STALE_TICKER  = 180000;
var STALE_BALANCE = 180000;

function poll(req, res) {
  var rateRec = plugins.getDeviceRate();
  var balanceRec = plugins.getBalance();

  // `rateRec` and `balanceRec` are both objects, so there's no danger
  // of misinterpreting rate or balance === 0 as 'Server initializing'.
  if (!rateRec || !balanceRec) {
    return res.json({err: 'Server initializing'});
  }

  var now = Date.now();
  if (now - rateRec.timestamp > STALE_TICKER) {
    return res.json({err: 'Stale ticker'});
  }

  if (now - balanceRec.timestamp > STALE_BALANCE) {
    return res.json({err: 'Stale balance'});
  }

  var rate = rateRec.rates.ask;
  var fiatRate = rateRec.rates.bid || rate;

  if (rate === null) return res.json({err: 'No rate available'});
  if (!fiatRate)
    logger.warn('No bid rate, using ask rate');

  var fiatBalance = plugins.fiatBalance();
  if (fiatBalance === null) {
    logger.warn('No balance available.');
    return res.json({err: 'No balance available'});
  }

  var config = plugins.getCachedConfig();
  var settings = config.exchanges.settings;
  var complianceSettings = settings.compliance;
  var fiatCommission = settings.fiatCommission || settings.commission;

  plugins.pollQueries(session(req), function(err, results) {
    if (err) return logger.error(err);
    var cartridges = results.cartridges;
    var response = {
      err: null,
      rate: rate * settings.commission,
      fiatRate: fiatRate / fiatCommission,
      fiat: fiatBalance,
      locale: config.brain.locale,
      txLimit: parseInt(complianceSettings.maximum.limit, 10),
      idVerificationEnabled: complianceSettings.idVerificationEnabled,
      cartridges: cartridges,
      twoWayMode: cartridges ? true : false,
      zeroConfLimit: settings.zeroConfLimit,
      fiatTxLimit: settings.fiatTxLimit
    };

    if (response.idVerificationEnabled)
      response.idVerificationLimit = complianceSettings.idVerificationLimit;

    res.json(response);
  });
}

function trade(req, res) {
  plugins.trade(session(req), req.body, function(err) {
    var statusCode = err ? 500 : 201;
    res.json(statusCode, {err: err});
  });
}

function send(req, res) {
  plugins.sendBitcoins(session(req), req.body, function(err, status) {
    // TODO: use status.statusCode here after confirming machine compatibility
    // FIX: (joshm) set txHash to status.txId instead of previous status.txHash which wasn't being set
    // Need to clean up txHash vs txId
    res.json({
      errType: err && err.name,
      err: err && err.message,
      txHash: status && status.txHash,
      txId: status && status.txId
    });
  });
}

function cashOut(req, res) {
  logger.info({tx: req.body, cmd: 'cashOut'});
  plugins.cashOut(session(req), req.body, function(err, bitcoinAddress) {
    if (err) logger.error(err);

    res.json({
      err: err && err.message,
      errType: err && err.name,
      bitcoinAddress: bitcoinAddress
    });
  });
}

function dispenseAck(req, res) {
  plugins.dispenseAck(session(req), req.body);
  res.json(200);
}

function deviceEvent(req, res) {
  plugins.logEvent(session(req), req.body);
  res.json({err: null});
}

function verifyUser(req, res) {
  if (mock) return res.json({success: true});

  plugins.verifyUser(req.body, function (err, idResult) {
    if (err) {
      logger.error(err);
      return res.json({err: 'Verification failed'});
    }

    res.json(idResult);
  });
}

function verifyTx(req, res) {
  if (mock) return res.json({success: true});

  plugins.verifyTx(req.body, function (err, idResult) {
    if (err) {
      logger.error(err);
      return res.json({err: 'Verification failed'});
    }

    res.json(idResult);
  });
}

function pair(req, res) {
  var token = req.body.token;
  var name = req.body.name;

  lamassuConfig.pair(
    token,
    getFingerprint(req),
    name,
    function(err) {
      if (err) return res.json(500, { err: err.message });

      res.json(200);
    }
  );
}

function raqia(req, res) {
  var raqiaCreds;
  try {
    var raqiaRec = require('../raqia.json');
    raqiaCreds = raqiaRec[getFingerprint(req)].apiKeys[0];
  } catch(ex) {
    raqiaCreds = null;
  }
  res.json(raqiaCreds || {});
}

function init(localConfig) {
  lamassuConfig = localConfig.lamassuConfig;
  plugins = localConfig.plugins;
  mock = localConfig.mock;

  var authMiddleware = localConfig.authMiddleware;
  var app = localConfig.app;

  app.get('/poll', authMiddleware, poll);

  app.post('/trade', authMiddleware, trade);
  app.post('/send', authMiddleware, send);

  app.post('/cash_out', authMiddleware, cashOut);
  app.post('/dispense_ack', authMiddleware, dispenseAck);

  app.post('/event', authMiddleware, deviceEvent);
  app.post('/verify_user', authMiddleware, verifyUser);
  app.post('/verify_transaction', authMiddleware, verifyTx);
  app.post('/pair', pair);
  app.get('/raqia', raqia);

  return app;
}

function session(req) {
  return {fingerprint: getFingerprint(req), id: req.get('session-id')};
}

function getFingerprint(req) {
  return typeof req.connection.getPeerCertificate === 'function' &&
    req.connection.getPeerCertificate().fingerprint;
}
<commit_msg>add poll request logging back in<commit_after>'use strict';

var logger = require('./logger');

var mock = false;

var plugins;
var lamassuConfig;

module.exports = {
  init: init,
  getFingerprint: getFingerprint
};

// Make sure these are higher than polling interval
// or there will be a lot of errors
var STALE_TICKER  = 180000;
var STALE_BALANCE = 180000;

function poll(req, res) {
  var rateRec = plugins.getDeviceRate();
  var balanceRec = plugins.getBalance();

  logger.debug('poll request from: %s', getFingerprint(req));

  // `rateRec` and `balanceRec` are both objects, so there's no danger
  // of misinterpreting rate or balance === 0 as 'Server initializing'.
  if (!rateRec || !balanceRec) {
    return res.json({err: 'Server initializing'});
  }

  var now = Date.now();
  if (now - rateRec.timestamp > STALE_TICKER) {
    return res.json({err: 'Stale ticker'});
  }

  if (now - balanceRec.timestamp > STALE_BALANCE) {
    return res.json({err: 'Stale balance'});
  }

  var rate = rateRec.rates.ask;
  var fiatRate = rateRec.rates.bid || rate;

  if (rate === null) return res.json({err: 'No rate available'});
  if (!fiatRate)
    logger.warn('No bid rate, using ask rate');

  var fiatBalance = plugins.fiatBalance();
  if (fiatBalance === null) {
    logger.warn('No balance available.');
    return res.json({err: 'No balance available'});
  }

  var config = plugins.getCachedConfig();
  var settings = config.exchanges.settings;
  var complianceSettings = settings.compliance;
  var fiatCommission = settings.fiatCommission || settings.commission;

  plugins.pollQueries(session(req), function(err, results) {
    if (err) return logger.error(err);
    var cartridges = results.cartridges;
    var response = {
      err: null,
      rate: rate * settings.commission,
      fiatRate: fiatRate / fiatCommission,
      fiat: fiatBalance,
      locale: config.brain.locale,
      txLimit: parseInt(complianceSettings.maximum.limit, 10),
      idVerificationEnabled: complianceSettings.idVerificationEnabled,
      cartridges: cartridges,
      twoWayMode: cartridges ? true : false,
      zeroConfLimit: settings.zeroConfLimit,
      fiatTxLimit: settings.fiatTxLimit
    };

    if (response.idVerificationEnabled)
      response.idVerificationLimit = complianceSettings.idVerificationLimit;

    res.json(response);
  });
}

function trade(req, res) {
  plugins.trade(session(req), req.body, function(err) {
    var statusCode = err ? 500 : 201;
    res.json(statusCode, {err: err});
  });
}

function send(req, res) {
  plugins.sendBitcoins(session(req), req.body, function(err, status) {
    // TODO: use status.statusCode here after confirming machine compatibility
    // FIX: (joshm) set txHash to status.txId instead of previous status.txHash which wasn't being set
    // Need to clean up txHash vs txId
    res.json({
      errType: err && err.name,
      err: err && err.message,
      txHash: status && status.txHash,
      txId: status && status.txId
    });
  });
}

function cashOut(req, res) {
  logger.info({tx: req.body, cmd: 'cashOut'});
  plugins.cashOut(session(req), req.body, function(err, bitcoinAddress) {
    if (err) logger.error(err);

    res.json({
      err: err && err.message,
      errType: err && err.name,
      bitcoinAddress: bitcoinAddress
    });
  });
}

function dispenseAck(req, res) {
  plugins.dispenseAck(session(req), req.body);
  res.json(200);
}

function deviceEvent(req, res) {
  plugins.logEvent(session(req), req.body);
  res.json({err: null});
}

function verifyUser(req, res) {
  if (mock) return res.json({success: true});

  plugins.verifyUser(req.body, function (err, idResult) {
    if (err) {
      logger.error(err);
      return res.json({err: 'Verification failed'});
    }

    res.json(idResult);
  });
}

function verifyTx(req, res) {
  if (mock) return res.json({success: true});

  plugins.verifyTx(req.body, function (err, idResult) {
    if (err) {
      logger.error(err);
      return res.json({err: 'Verification failed'});
    }

    res.json(idResult);
  });
}

function pair(req, res) {
  var token = req.body.token;
  var name = req.body.name;

  lamassuConfig.pair(
    token,
    getFingerprint(req),
    name,
    function(err) {
      if (err) return res.json(500, { err: err.message });

      res.json(200);
    }
  );
}

function raqia(req, res) {
  var raqiaCreds;
  try {
    var raqiaRec = require('../raqia.json');
    raqiaCreds = raqiaRec[getFingerprint(req)].apiKeys[0];
  } catch(ex) {
    raqiaCreds = null;
  }
  res.json(raqiaCreds || {});
}

function init(localConfig) {
  lamassuConfig = localConfig.lamassuConfig;
  plugins = localConfig.plugins;
  mock = localConfig.mock;

  var authMiddleware = localConfig.authMiddleware;
  var app = localConfig.app;

  app.get('/poll', authMiddleware, poll);

  app.post('/trade', authMiddleware, trade);
  app.post('/send', authMiddleware, send);

  app.post('/cash_out', authMiddleware, cashOut);
  app.post('/dispense_ack', authMiddleware, dispenseAck);

  app.post('/event', authMiddleware, deviceEvent);
  app.post('/verify_user', authMiddleware, verifyUser);
  app.post('/verify_transaction', authMiddleware, verifyTx);
  app.post('/pair', pair);
  app.get('/raqia', raqia);

  return app;
}

function session(req) {
  return {fingerprint: getFingerprint(req), id: req.get('session-id')};
}

function getFingerprint(req) {
  return typeof req.connection.getPeerCertificate === 'function' &&
    req.connection.getPeerCertificate().fingerprint;
}
<|endoftext|>


<commit_before>// @flow

var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  firstline = require("firstline"),
  path = require("path"),
  finder = require('./finder.js'),
  installReadElmi = require("../installer"),
  builder = require('xmlbuilder');

function copyNativeSrcFiles(newPackageName/*:string*/, srcPath/*:string*/, dest/*:string*/) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename/*: string*/) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository/*:string*/) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/\.]+)\.git/);

  if (matches instanceof Array) {
    var username = matches[1];
    var repoName = matches[2];

    if (typeof username === "string" && typeof repoName === "string") {
      // From the above example, return "rtfeldman$node_test_runner"
      return [
        matches[1].replace(/-/g, "_"),
        matches[2].replace(/-/g, "_")
      ].join("$");
    } else {
      throw ("Unable to convert repository " + repository + " to package name.")
    }
  } else {
    throw ("Unable to convert repository " + repository + " to package name.")
  }
}

function findNearestElmPackageDir(filePaths/*:Array<string>*/) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args/*:Array<string>*/, report/*:string*/, compiledCode/*:string*/) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function moduleFromFilePath(filePathArg) {
  var parsed = path.parse(path.normalize(filePathArg));
  var basename = path.basename(parsed.base, ".elm");

  // Turn these into module name checks to be performed, in order.
  // e.g. 'tests/All/Passing.elm' ===> ['Passing', 'All', 'tests']
  // This way, if we're given 'All.Passing' as a module name, we can also
  // flip it into ['Passing', 'All'], and see if the first N elements line up.
  return _.compact(parsed.dir.split(path.sep).concat([basename])).reverse();
}

function moduleFromTestName(testName) {
  return testName.split(".").reverse();
}

function toPathsAndModules(testFilePaths/*:Array<string>*/, testSourceDirs/*:Array<string>*/) {
  var paths = testFilePaths.map(function(filePath) {
    return {filePath: filePath, module: moduleFromFilePath(filePath)};
  });

  // Each module must correspond to a file path, by way of a source directory.
  // This filters out stale modules left over from previous builds, for example
  // what happened in https://github.com/rtfeldman/node-test-runner/issues/122
  return function(testModule) {
    var moduleAsFilename = testModule.name.replace(/[\.]/g, path.sep) + ".elm";

    // for early return purposes, use old-school `for` loops
    for (var pathIndex=0; pathIndex < paths.length; pathIndex++) {
      var currentPath = paths[pathIndex];

      for (var testSourceDirIndex=0; testSourceDirIndex < testSourceDirs.length; testSourceDirIndex++) {
        var testSourceDir = testSourceDirs[testSourceDirIndex];

        if (currentPath.filePath === path.join(testSourceDir, moduleAsFilename)) {
          return [{
            name: testModule.name,
            tests: testModule.tests,
            path: currentPath.filePath
          }];
        }
      }
    }

    return [];
  };
}

function findTests(elmPackageJsonPath/*: string*/, testFilePaths/*: Array<string>*/, sourceDirs/*: Array<string>*/) {
  return new Promise(function(resolve, reject) {
    function finish() {
      var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
      var jsonStr = "";
      var stderrStr = "";

      process.stdout.on('data', function(data) {
        jsonStr += data;
      });

      process.stderr.on('data', function(data) {
        stderrStr += data;
      });

      process.on('close', function(code) {
        if (stderrStr !== "") {
          reject(stderrStr);
        } else if (code !== 0) {
          reject("Finding test interfaces failed, exiting with code " + code);
        }

        var modules;

        try {
          modules = JSON.parse(jsonStr);
        } catch(err) {
          reject("Received invalid JSON from test interface search: " + err);
        }

        var filteredModules = _.flatMap(modules, function(mod) {
          var eligible = _.flatMap(mod.types, function(typ) {
            if (typ.signature === "Test.Test") {
              return typ.name;
            } else {
              return [];
            }
          });

          // Must have at least 1 value of type Test. Otherwise ignore this module.
          if (eligible.length > 0) {
            return [{name: mod.moduleName, tests: eligible}];
          } else {
            return [];
          }
        });

        return verifyModules(testFilePaths).then(function() {
          return Promise.all(
            _.map(_.flatMap(filteredModules, toPathsAndModules(testFilePaths, sourceDirs)), filterExposing)
          ).then(resolve).catch(reject);
        }).catch(reject);
      });
    }

    if (fs.existsSync(readElmiPath)) {
      // elm-interface-to-json was already downloaded successfully. We're good!
      return finish();
    } else {
      // it wasn't downloaded, possibly because we were installed with
      // --ignore-scripts - so download it!
      return installReadElmi().then(finish).catch(reject);
    }
  });
}

// Check for modules where the name doesn't match the filename.
// elm-make won't get a chance to detect this; they'll be filtered out first.
function verifyModules(filePaths) {
  return Promise.all(
    _.map(filePaths, function(filePath) {
      return firstline(filePath).then(function(line) {
        var matches = line.match(/^(?:(?:port|effect)\s+)?module\s+(\S+)\s*/);

        if (matches) {
          var moduleName = matches[1];
          var testModulePaths = moduleFromTestName(moduleName);
          var modulePath = moduleFromFilePath(filePath);

          // A module path matches if it lines up completely with a known one.
          if (!testModulePaths.every(function(testModulePath, index) {
            return testModulePath === modulePath[index];
          })) {
            return Promise.reject(filePath + " has a module declaration of \"" + moduleName + "\" - which does not match its filename!");
          }
        } else {
          return Promise.reject(filePath + " has an invalid module declaration. Check the first line of the file and make sure it has a valid module declaration there!");
        }
      });
    })
  )
}

function filterExposing(pathAndModule) {
  return new Promise(function(resolve, reject) {
    return finder.readExposing(pathAndModule.path).then(function(exposedValues) {
      var newTests =
        exposedValues.length === 1 && exposedValues[0] === '..'
          // null exposedValues means "the module was exposing (..), so keep everything"
          ? pathAndModule.tests

          // Only keep the tests that were exposed.
          : _.intersection(exposedValues, pathAndModule.tests);

      if (newTests.length < pathAndModule.tests.length) {
        return reject(
          "\n`" + pathAndModule.name + "` is a module with top-level Test values which it does not expose:\n\n" +
          _.difference(pathAndModule.tests, newTests).map(function(test){ return test + " : Test"; }).join("\n") +
          "\n\nThese tests will not get run. Please either expose them or move them out of the top level.");
      } else {
        return resolve({name: pathAndModule.name, tests: newTests});
      }
    }).catch(reject);
  });
}

module.exports = {
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<commit_msg>Match dots in the Github repository name in 'repositoryToNativePackageName'. Fixes https://github.com/rtfeldman/node-test-runner/issues/165<commit_after>// @flow

var fs = require("fs-extra"),
  findParentDir = require('find-parent-dir'),
  _            = require("lodash"),
  spawn        = require("cross-spawn"),
  chalk = require("chalk"),
  firstline = require("firstline"),
  path = require("path"),
  finder = require('./finder.js'),
  installReadElmi = require("../installer"),
  builder = require('xmlbuilder');

function copyNativeSrcFiles(newPackageName/*:string*/, srcPath/*:string*/, dest/*:string*/) {
  fs.readdirSync(srcPath).forEach(function(filename) {
    var filePath = path.join(srcPath, filename);
    var newDest = path.join(dest, filename);
    var stats = fs.lstatSync(filePath);

    if (stats.isDirectory()) {
      fs.mkdirpSync(newDest);

      copyNativeSrcFiles(newPackageName, filePath, newDest);
    } else if ((stats.isFile() || stats.isSymbolicLink()) && isJsFile(filename)) {
      var contents = fs.readFileSync(filePath, "utf8");

      // These Native files need to use the local package name,
      // because of how we're hacking them in.
      var newContents = contents.replace(
        /rtfeldman\$node_test_runner([\.=\s]*)/gm,
        newPackageName + "$1"
      );

      fs.writeFileSync(newDest, newContents);
    }
  });
}

function isJsFile(filename) {
  return /\.js$/.test(filename);
}

function isElmFile(filename/*: string*/) {
  return /\.elm$/.test(filename);
}

function repositoryToNativePackageName(repository/*:string*/) {
  // https://github.com/rtfeldman/node-test-runner.git
  //
  // matches[1] = "rtfeldman"
  // matches[2] = "node-test-runner"
  var matches = repository.match(/\/([^\/]+)\/([^\/]+)\.git/);

  if (matches instanceof Array) {
    var username = matches[1];
    var repoName = matches[2];

    if (typeof username === "string" && typeof repoName === "string") {
      // From the above example, return "rtfeldman$node_test_runner"
      return [
        matches[1].replace(/-/g, "_"),
        matches[2].replace(/-/g, "_")
      ].join("$");
    } else {
      throw ("Unable to convert repository " + repository + " to package name.")
    }
  } else {
    throw ("Unable to convert repository " + repository + " to package name.")
  }
}

function findNearestElmPackageDir(filePaths/*:Array<string>*/) {
  // For each of the given files, try to find an ancestor elm-package.json
  // As soon as we find one, return it.
  for (var index=0; index < filePaths.length; index++) {
    var currentDir = path.dirname(filePaths[index]);
    var result = findParentDir.sync(currentDir, "elm-package.json");

    if (result !== null) {
      return result;
    }
  }

  // If we didn't find any, fall back on the current working directory.
  return process.cwd();
}

function evalElmCode (args/*:Array<string>*/, report/*:string*/, compiledCode/*:string*/) {
  // Apply Node polyfills as necessary.
  var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
  var document = {body: {}, createTextNode: function() {}};
  if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
  if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }

  var Elm = function(module) { eval(compiledCode); return module.exports; }({});

  // Make sure necessary things are defined.
  if (typeof Elm === 'undefined') { throw 'test runner config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }

  var potentialModuleNames = Object.keys(Elm.Test.Generated);

  if (potentialModuleNames.length !== 1) {
    console.error("Multiple potential generated modules to run in the Elm.Test.Generated namespace: ", potentialModuleNames, " - this should never happen!");
    process.exit(1);
  }

  var testModule = Elm.Test.Generated[potentialModuleNames[0]];
  var initialSeed = null;

  if (args.seed !== undefined) {
    initialSeed = args.seed;
  }

  // Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
  var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];

  function windowsify(str) {
    return windowsSubstitutions.reduce(
      function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
  }

  function chalkify(messages) {
    return messages.map(function(msg) {
      var path = msg.styles;
      var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;

      if (path.length === 0) {
        return text;
      } else {
        var fn = chalk;

        path.forEach(function(nextPath) { fn = fn[nextPath]; });

        return fn(text);
      }
    }).join('');
  }

  // Run the Elm app.
  var app = testModule.worker({seed: initialSeed, report: report});

  // Receive messages from ports and translate them into appropriate JS calls.
  app.ports.emit.subscribe(function(msg) {
    var msgType = msg[0];
    var data = msg[1];

    if (msgType === 'FINISHED') {
      if (data.format === "CHALK") {
        console.log(chalkify(data.message));
      } else if (data.format === "JUNIT") {
        console.log(builder.create(data.message).end());
      } else {
        console.log(JSON.stringify(data.message));
      }

      if (!args.watch) {
        process.exit(data.exitCode);
      }
    } else if (msgType === "STARTED" || msgType === "TEST_COMPLETED")  {
        if (data.format === "CHALK") {
          console.log(chalkify(data.message));
        } else if (data.format === "JSON") {
          console.log(JSON.stringify(data.message));
        }

    }
  });
}

var binaryExtension = process.platform === "win32" ? ".exe" : "";
var readElmiPath = path.join(__dirname, "..", "bin", "elm-interface-to-json") + binaryExtension;

function moduleFromFilePath(filePathArg) {
  var parsed = path.parse(path.normalize(filePathArg));
  var basename = path.basename(parsed.base, ".elm");

  // Turn these into module name checks to be performed, in order.
  // e.g. 'tests/All/Passing.elm' ===> ['Passing', 'All', 'tests']
  // This way, if we're given 'All.Passing' as a module name, we can also
  // flip it into ['Passing', 'All'], and see if the first N elements line up.
  return _.compact(parsed.dir.split(path.sep).concat([basename])).reverse();
}

function moduleFromTestName(testName) {
  return testName.split(".").reverse();
}

function toPathsAndModules(testFilePaths/*:Array<string>*/, testSourceDirs/*:Array<string>*/) {
  var paths = testFilePaths.map(function(filePath) {
    return {filePath: filePath, module: moduleFromFilePath(filePath)};
  });

  // Each module must correspond to a file path, by way of a source directory.
  // This filters out stale modules left over from previous builds, for example
  // what happened in https://github.com/rtfeldman/node-test-runner/issues/122
  return function(testModule) {
    var moduleAsFilename = testModule.name.replace(/[\.]/g, path.sep) + ".elm";

    // for early return purposes, use old-school `for` loops
    for (var pathIndex=0; pathIndex < paths.length; pathIndex++) {
      var currentPath = paths[pathIndex];

      for (var testSourceDirIndex=0; testSourceDirIndex < testSourceDirs.length; testSourceDirIndex++) {
        var testSourceDir = testSourceDirs[testSourceDirIndex];

        if (currentPath.filePath === path.join(testSourceDir, moduleAsFilename)) {
          return [{
            name: testModule.name,
            tests: testModule.tests,
            path: currentPath.filePath
          }];
        }
      }
    }

    return [];
  };
}

function findTests(elmPackageJsonPath/*: string*/, testFilePaths/*: Array<string>*/, sourceDirs/*: Array<string>*/) {
  return new Promise(function(resolve, reject) {
    function finish() {
      var process = spawn(readElmiPath, ["--path", elmPackageJsonPath]);
      var jsonStr = "";
      var stderrStr = "";

      process.stdout.on('data', function(data) {
        jsonStr += data;
      });

      process.stderr.on('data', function(data) {
        stderrStr += data;
      });

      process.on('close', function(code) {
        if (stderrStr !== "") {
          reject(stderrStr);
        } else if (code !== 0) {
          reject("Finding test interfaces failed, exiting with code " + code);
        }

        var modules;

        try {
          modules = JSON.parse(jsonStr);
        } catch(err) {
          reject("Received invalid JSON from test interface search: " + err);
        }

        var filteredModules = _.flatMap(modules, function(mod) {
          var eligible = _.flatMap(mod.types, function(typ) {
            if (typ.signature === "Test.Test") {
              return typ.name;
            } else {
              return [];
            }
          });

          // Must have at least 1 value of type Test. Otherwise ignore this module.
          if (eligible.length > 0) {
            return [{name: mod.moduleName, tests: eligible}];
          } else {
            return [];
          }
        });

        return verifyModules(testFilePaths).then(function() {
          return Promise.all(
            _.map(_.flatMap(filteredModules, toPathsAndModules(testFilePaths, sourceDirs)), filterExposing)
          ).then(resolve).catch(reject);
        }).catch(reject);
      });
    }

    if (fs.existsSync(readElmiPath)) {
      // elm-interface-to-json was already downloaded successfully. We're good!
      return finish();
    } else {
      // it wasn't downloaded, possibly because we were installed with
      // --ignore-scripts - so download it!
      return installReadElmi().then(finish).catch(reject);
    }
  });
}

// Check for modules where the name doesn't match the filename.
// elm-make won't get a chance to detect this; they'll be filtered out first.
function verifyModules(filePaths) {
  return Promise.all(
    _.map(filePaths, function(filePath) {
      return firstline(filePath).then(function(line) {
        var matches = line.match(/^(?:(?:port|effect)\s+)?module\s+(\S+)\s*/);

        if (matches) {
          var moduleName = matches[1];
          var testModulePaths = moduleFromTestName(moduleName);
          var modulePath = moduleFromFilePath(filePath);

          // A module path matches if it lines up completely with a known one.
          if (!testModulePaths.every(function(testModulePath, index) {
            return testModulePath === modulePath[index];
          })) {
            return Promise.reject(filePath + " has a module declaration of \"" + moduleName + "\" - which does not match its filename!");
          }
        } else {
          return Promise.reject(filePath + " has an invalid module declaration. Check the first line of the file and make sure it has a valid module declaration there!");
        }
      });
    })
  )
}

function filterExposing(pathAndModule) {
  return new Promise(function(resolve, reject) {
    return finder.readExposing(pathAndModule.path).then(function(exposedValues) {
      var newTests =
        exposedValues.length === 1 && exposedValues[0] === '..'
          // null exposedValues means "the module was exposing (..), so keep everything"
          ? pathAndModule.tests

          // Only keep the tests that were exposed.
          : _.intersection(exposedValues, pathAndModule.tests);

      if (newTests.length < pathAndModule.tests.length) {
        return reject(
          "\n`" + pathAndModule.name + "` is a module with top-level Test values which it does not expose:\n\n" +
          _.difference(pathAndModule.tests, newTests).map(function(test){ return test + " : Test"; }).join("\n") +
          "\n\nThese tests will not get run. Please either expose them or move them out of the top level.");
      } else {
        return resolve({name: pathAndModule.name, tests: newTests});
      }
    }).catch(reject);
  });
}

module.exports = {
  findTests: findTests,
  evalElmCode: evalElmCode,
  isElmFile: isElmFile,
  copyNativeSrcFiles: copyNativeSrcFiles,
  repositoryToNativePackageName: repositoryToNativePackageName,
  findNearestElmPackageDir: findNearestElmPackageDir
};
<|endoftext|>