<commit_before>/*!
 * Brackets Node Debugger
 *
 * @author Benjamin August
 * @license http://opensource.org/licenses/MIT
 */

define(function (require, exports, module) {
    "use strict";

    var CommandManager = brackets.getModule("command/CommandManager"),
		DocumentManager = brackets.getModule("document/DocumentManager"),
		Editor = brackets.getModule("editor/EditorManager"),
        Menus          = brackets.getModule("command/Menus"),
		AppInit        = brackets.getModule("utils/AppInit"),
		PanelManager = brackets.getModule("view/PanelManager"),
        NodeDomain = brackets.getModule("utils/NodeDomain"),
        ExtensionUtils = brackets.getModule("utils/ExtensionUtils");

    ExtensionUtils.loadStyleSheet(module, "assets/style.css");

	var breakpointGutters = require('./breakpointGutter');
	console.log('foo!!');

	var logContainerHTML = require("text!debuggerLog.html");

	var $logPanel = $(null);

	var nodeDebuggerDomain = new NodeDomain("brackets-node-debugger", ExtensionUtils.getModulePath(module, "node/main"));

	AppInit.appReady(function() {
		breakpointGutters.init();
		//Adds a new line to the log within brackets
		function addLog(msg) {
			var h = '
' + msg + '
';
			$(h).appendTo($logPanel.find('#brackets-node-debugger-content'));
		}

		$(nodeDebuggerDomain).on("connect", function() {
			addLog('Debugger connected');
		});

		$(nodeDebuggerDomain).on("close", function() {
			addLog('Debugger disconnected');
		});

		$(nodeDebuggerDomain).on("break", function(e, body) {
			var docPath = body.script.name;

			console.log(body);

			addLog("Break on: " + docPath + " : " + body.sourceLine);
			//Make sure the panel is open
			panel.setVisible(true);

			DocumentManager.getDocumentForPath(docPath)
				.done(function(doc) {
					DocumentManager.setCurrentDocument( doc );
					Editor.getActiveEditor().setCursorPos( body.sourceLine - 1 );
				}).fail(function(err) {
					console.log('[Node Debugger] Failed to open Document: ' + docPath);
				});

		});

		$(nodeDebuggerDomain).on("eval", function(e, body) {
			console.log(body);
			addLog('<< ' + body.value);
		});

		//UI Actions
		$logPanel.find('.close').on('click', function() {
			toggleLog();
		});

		$logPanel.find('.activate').on('click', function() {
			//Starts the socket and connects to the V8 debugger
			nodeDebuggerDomain.exec("start");
		});

		$logPanel.find('.next').on('click', function() {
			nodeDebuggerDomain.exec('stepNext');
		});

		$logPanel.find('.in').on('click', function() {
			nodeDebuggerDomain.exec('stepIn');
		});

		$logPanel.find('.out').on('click', function() {
			nodeDebuggerDomain.exec('stepOut');
		});

		$logPanel.find('.continue').on('click', function() {
			nodeDebuggerDomain.exec('continue');
		});

		$logPanel.find('.action').on('click', function() {
			var com = $logPanel.find('#brackets-node-debugger-input').val();

			if(com.length > 0) {
				addLog('>> ' + com);
				nodeDebuggerDomain.exec('eval', com);
			}
		});
	});

    // Function to run when the menu item is clicked
    function toggleLog() {
        panel.setVisible(!panel.isVisible());
    }

    var MY_COMMAND_ID = "brackets-node-debugger.log";
    CommandManager.register("Node.js Debugger", MY_COMMAND_ID, toggleLog);

    // Then create a menu item bound to the command
    // The label of the menu item is the name we gave the command (see above)
    var menu = Menus.getMenu('debug-menu');
    menu.addMenuItem(MY_COMMAND_ID);

	var panel = PanelManager.createBottomPanel("brackets-node-debugger.log", $(logContainerHTML));
	$logPanel = panel.$panel;

    // We could also add a key binding at the same time:
    //menu.addMenuItem(MY_COMMAND_ID, "Ctrl-Shift-I");
    // (Note: "Ctrl" is automatically mapped to "Cmd" on Mac)
});<commit_msg>fixed path to HTML<commit_after>/*!
 * Brackets Node Debugger
 *
 * @author Benjamin August
 * @license http://opensource.org/licenses/MIT
 */

define(function (require, exports, module) {
    "use strict";

    var CommandManager = brackets.getModule("command/CommandManager"),
		DocumentManager = brackets.getModule("document/DocumentManager"),
		Editor = brackets.getModule("editor/EditorManager"),
        Menus          = brackets.getModule("command/Menus"),
		AppInit        = brackets.getModule("utils/AppInit"),
		PanelManager = brackets.getModule("view/PanelManager"),
        NodeDomain = brackets.getModule("utils/NodeDomain"),
        ExtensionUtils = brackets.getModule("utils/ExtensionUtils");

    ExtensionUtils.loadStyleSheet(module, "assets/style.css");

	var breakpointGutters = require('./breakpointGutter');
	console.log('foo!!');

	var logContainerHTML = require("text!assets/debuggerLog.html");

	var $logPanel = $(null);

	var nodeDebuggerDomain = new NodeDomain("brackets-node-debugger", ExtensionUtils.getModulePath(module, "node/main"));

	AppInit.appReady(function() {
		breakpointGutters.init();
		//Adds a new line to the log within brackets
		function addLog(msg) {
			var h = '
' + msg + '
';
			$(h).appendTo($logPanel.find('#brackets-node-debugger-content'));
		}

		$(nodeDebuggerDomain).on("connect", function() {
			addLog('Debugger connected');
		});

		$(nodeDebuggerDomain).on("close", function() {
			addLog('Debugger disconnected');
		});

		$(nodeDebuggerDomain).on("break", function(e, body) {
			var docPath = body.script.name;

			console.log(body);

			addLog("Break on: " + docPath + " : " + body.sourceLine);
			//Make sure the panel is open
			panel.setVisible(true);

			DocumentManager.getDocumentForPath(docPath)
				.done(function(doc) {
					DocumentManager.setCurrentDocument( doc );
					Editor.getActiveEditor().setCursorPos( body.sourceLine - 1 );
				}).fail(function(err) {
					console.log('[Node Debugger] Failed to open Document: ' + docPath);
				});

		});

		$(nodeDebuggerDomain).on("eval", function(e, body) {
			console.log(body);
			addLog('<< ' + body.value);
		});

		//UI Actions
		$logPanel.find('.close').on('click', function() {
			toggleLog();
		});

		$logPanel.find('.activate').on('click', function() {
			//Starts the socket and connects to the V8 debugger
			nodeDebuggerDomain.exec("start");
		});

		$logPanel.find('.next').on('click', function() {
			nodeDebuggerDomain.exec('stepNext');
		});

		$logPanel.find('.in').on('click', function() {
			nodeDebuggerDomain.exec('stepIn');
		});

		$logPanel.find('.out').on('click', function() {
			nodeDebuggerDomain.exec('stepOut');
		});

		$logPanel.find('.continue').on('click', function() {
			nodeDebuggerDomain.exec('continue');
		});

		$logPanel.find('.action').on('click', function() {
			var com = $logPanel.find('#brackets-node-debugger-input').val();

			if(com.length > 0) {
				addLog('>> ' + com);
				nodeDebuggerDomain.exec('eval', com);
			}
		});
	});

    // Function to run when the menu item is clicked
    function toggleLog() {
        panel.setVisible(!panel.isVisible());
    }

    var MY_COMMAND_ID = "brackets-node-debugger.log";
    CommandManager.register("Node.js Debugger", MY_COMMAND_ID, toggleLog);

    // Then create a menu item bound to the command
    // The label of the menu item is the name we gave the command (see above)
    var menu = Menus.getMenu('debug-menu');
    menu.addMenuItem(MY_COMMAND_ID);

	var panel = PanelManager.createBottomPanel("brackets-node-debugger.log", $(logContainerHTML));
	$logPanel = panel.$panel;

    // We could also add a key binding at the same time:
    //menu.addMenuItem(MY_COMMAND_ID, "Ctrl-Shift-I");
    // (Note: "Ctrl" is automatically mapped to "Cmd" on Mac)
});<|endoftext|>


<commit_before>var fs = require('fs');
var https = require('https');
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var crypto = require('crypto');
var macaroons = require('macaroons.js');
var pathToRegexp = require('path-to-regexp');
var basicAuth = require('basic-auth');
var baseCat = require('./base-cat.json');

var PORT = process.env.PORT || 8080;

var HTTPS_SERVER_CERT = process.env.HTTPS_SERVER_CERT || '';
var HTTPS_SERVER_PRIVATE_KEY = process.env.HTTPS_SERVER_PRIVATE_KEY || '';

var CM_KEY = process.env.CM_KEY || '';

var containers = {};

var app = express();

var credentials = {
	key:  HTTPS_SERVER_PRIVATE_KEY,
	cert: HTTPS_SERVER_CERT,
};

// TODO: Check
app.enable('trust proxy');
app.disable('x-powered-by');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
	extended: true
}));

app.get('/status', function(req, res){
	res.send('active');
});

/**********************************************************/

app.all([ '/cat', '/token', '/store/*', '/cm/*'], function (req, res, next) {
	var creds = basicAuth(req);
	var key = req.get('X-Api-Key') || (creds && creds.name);

	if (!key) {
		res.status(401).send('Missing API key');
		return;
	}

	req.key = key;

	for (name in containers) {
		var container = containers[name];
		if (!container.key || container.key !== key)
			continue;
		req.container = container;
		break;
	}

	next();
});

/**********************************************************/

app.all('/cm/*', function (req, res, next) {
	if (req.key !== CM_KEY) {
		res.status(401).send('Unauthorized: Arbiter key invalid');
		return;
	}
	next();
});

/**********************************************************/

app.post('/cm/upsert-container-info', function (req, res) {
	var data = req.body;

	if (data == null || !data.name) {
		res.status(400).send('Missing parameters');
		return;
	}

	// TODO: Store in a DB maybe? Probably not.
	if (data.type === 'store' && (!(data.name in containers) || containers[data.name].type !== 'store')) {
		containers[data.name] = {
			catItem: {
				'item-metadata': [
					{
						rel: 'urn:X-hypercat:rels:isContentType',
						val: 'application/vnd.hypercat.catalogue+json'
					},
					{
						rel: 'urn:X-hypercat:rels:hasDescription:en',
						val: data.name
					}
				],
				href: 'https://' + data.name + ':8080'
			}
		};
	} else {
		containers[data.name] = {}
	}

	// TODO: Restrict POSTed data to namespace (else can overwrite catItem)
	for(var key in data) {
		containers[data.name][key] = data[key];
	}

	res.json(containers[data.name]);
});

/**********************************************************/

app.post('/cm/delete-container-info', function (req, res) {
	var data = req.body;

	if (data == null || !data.name) {
		res.status(400).send('Missing parameters');
		return;
	}

	// TODO: Error if it wasn't there to begin with?
	delete containers[data.name];

	res.send();
});

/**********************************************************/

app.post('/cm/grant-container-permissions', function (req, res) {
	var data = req.body;

	// TODO: Allow all at once?
	if (data == null || !data.name || !data.route || !data.route.target || !data.route.path || !data.route.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var route = JSON.stringify({
		target: data.route.target,
		path:   data.route.path,
		method: data.route.method
	});

	var pathMapHash = JSON.stringify({
		target: data.route.target,
		method: data.route.method
	});

	// TODO: Error if not yet in in records?
	var container = containers[data.name] = containers[data.name] || { name: data.name };
	container.caveats = container.caveats || {};
	var caveats = container.caveats[route] = container.caveats[route] || [];
	// NOTE: Separate map for constant time instead of O(N)
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];
	container.paths[pathMapHash].push({
		string: data.route.path,
		regExp: pathToRegexp(data.route.path)
	});

	if (!data.caveats) {
		res.json(caveats);
		return;
	}

	Array.prototype.push.apply(caveats, data.caveats);
	res.json(caveats);
});

/**********************************************************/

app.post('/cm/revoke-container-permissions', function (req, res) {
	var data = req.body;

	if (data == null || !data.name || !data.route || !data.route.target || !data.route.path || !data.route.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var route = JSON.stringify({
		target: data.route.target,
		path:   data.route.path,
		method: data.route.method
	});

	var pathMapHash = JSON.stringify({
		target: data.route.target,
		method: data.route.method
	});

	// TODO: Error if not yet in in records?
	var container = containers[data.name] = containers[data.name] || { name: data.name };
	container.caveats = container.caveats || {};
	container.caveats[route] = container.caveats[route] || [];
	// NOTE: Separate map for constant time instead of O(N)
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];
	var wanted = pathToRegexp(data.route.path);
	container.paths[pathMapHash] = container.paths[pathMapHash].filter(path => !wanted.test(path.string));

	if (!data.caveats || !data.caveats.length || data.caveats.length < 1) {
		delete container.caveats[route];
		res.json(null);
		return;
	}

	res.json(container.caveats[route] = container.caveats[route].filter(caveat => !data.caveats.includes(caveat)));
});

/**********************************************************/

// Serve root Hypercat catalogue
app.get('/cat', function(req, res){
	var cat = JSON.parse(JSON.stringify(baseCat));

	for (var name in containers) {
		var container = containers[name];
		// TODO: If CM, show all
		// TODO: Hide items based on container permissions
		// TODO: If discoverable, but not accessible, inform as per PAS 7.3.1.2
		if(container.catItem) {
			cat.items.push(container.catItem);
		}
	}

	res.json(cat);
});

/**********************************************************/

app.post('/token', function(req, res){
	if (!req.container) {
		// NOTE: This can also happen if the CM never uploaded store key
		//       or if the CM added routes and never upserted info
		//       but should never happen if the CM is up to spec.
		res.status(401).send('Invalid API key');
		return;
	}

	var data = req.body;

	if (data == null || !data.target || !data.path || !data.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var targetContainer = containers[data.target];

	if (typeof(targetContainer) == "undefined" && !targetContainer) {
		res.status(400).send("Target " + data.target + " has not been approved for arbitering");
		return;
	}

	if (!targetContainer.secret) {
		res.status(400).send("Target " + data.target + " has not registered itself for arbitering");
		return;
	}

	var route = JSON.stringify({
		target: data.target,
		path:   data.path,
		method: data.method
	});

	var pathMapHash = JSON.stringify({
		target: data.target,
		method: data.method
	});

	var container = req.container;
	container.caveats = container.caveats || {};
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];

	if (!(route in container.caveats) && !container.paths[pathMapHash].find((path) => path.regExp.test(data.path))) {
		res.status(401).send("Insufficient route permissions");
		return;
	}

	crypto.randomBytes(32, function(err, buffer){
		// TODO: Get hostname from environment variable instead of hardcoding
		var mb = new macaroons.MacaroonsBuilder('https://databox-arbiter:' + PORT, targetContainer.secret, buffer.toString('base64'));
		mb
			.add_first_party_caveat('target = ' + data.target)
			.add_first_party_caveat('path = ' + data.path)
			.add_first_party_caveat('method = ' + data.method);
		for (const caveat of container.caveats[route])
			mb.add_first_party_caveat(caveat);
		res.send(mb.getMacaroon().serialize());
	});
});

/**********************************************************/

app.get('/store/secret', function (req, res) {
	if (!req.container) {
		// NOTE: This can also happen if the CM never uploaded store key
		//       or if the CM added routes and never upserted info
		//       but should never happen if the CM is up to spec.
		res.status(401).send('Invalid API key');
		return;
	}

	if (!req.container.type) {
		// NOTE: This should never happen if the CM is up to spec.
		res.status(500).send('Container type unknown by arbiter');
		return;
	}

	if (req.container.type !== 'store') {
		res.status(403).send('Container type "' + req.container.type + '" cannot use arbiter token minting capabilities as it is not a store type');
		return;
	}

	if (req.container.secret) {
		res.status(409).send('Store shared secret already retrieved');
		return;
	}

	crypto.randomBytes(macaroons.MacaroonsConstants.MACAROON_SUGGESTED_SECRET_LENGTH, function(err, buffer){
		if (err != null) {
			res.status(500).send('Unable to register container (secret generation)');
			return;
		}

		req.container.secret = buffer;
		res.send(buffer.toString('base64'));
	});
});

https.createServer(credentials, app).listen(PORT);

module.exports = app;
<commit_msg>Apply path caveats only to exact matches<commit_after>var fs = require('fs');
var https = require('https');
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var crypto = require('crypto');
var macaroons = require('macaroons.js');
var pathToRegexp = require('path-to-regexp');
var basicAuth = require('basic-auth');
var baseCat = require('./base-cat.json');

var PORT = process.env.PORT || 8080;

var HTTPS_SERVER_CERT = process.env.HTTPS_SERVER_CERT || '';
var HTTPS_SERVER_PRIVATE_KEY = process.env.HTTPS_SERVER_PRIVATE_KEY || '';

var CM_KEY = process.env.CM_KEY || '';

var containers = {};

var app = express();

var credentials = {
	key:  HTTPS_SERVER_PRIVATE_KEY,
	cert: HTTPS_SERVER_CERT,
};

// TODO: Check
app.enable('trust proxy');
app.disable('x-powered-by');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
	extended: true
}));

app.get('/status', function(req, res){
	res.send('active');
});

/**********************************************************/

app.all([ '/cat', '/token', '/store/*', '/cm/*'], function (req, res, next) {
	var creds = basicAuth(req);
	var key = req.get('X-Api-Key') || (creds && creds.name);

	if (!key) {
		res.status(401).send('Missing API key');
		return;
	}

	req.key = key;

	for (name in containers) {
		var container = containers[name];
		if (!container.key || container.key !== key)
			continue;
		req.container = container;
		break;
	}

	next();
});

/**********************************************************/

app.all('/cm/*', function (req, res, next) {
	if (req.key !== CM_KEY) {
		res.status(401).send('Unauthorized: Arbiter key invalid');
		return;
	}
	next();
});

/**********************************************************/

app.post('/cm/upsert-container-info', function (req, res) {
	var data = req.body;

	if (data == null || !data.name) {
		res.status(400).send('Missing parameters');
		return;
	}

	// TODO: Store in a DB maybe? Probably not.
	if (data.type === 'store' && (!(data.name in containers) || containers[data.name].type !== 'store')) {
		containers[data.name] = {
			catItem: {
				'item-metadata': [
					{
						rel: 'urn:X-hypercat:rels:isContentType',
						val: 'application/vnd.hypercat.catalogue+json'
					},
					{
						rel: 'urn:X-hypercat:rels:hasDescription:en',
						val: data.name
					}
				],
				href: 'https://' + data.name + ':8080'
			}
		};
	} else {
		containers[data.name] = {}
	}

	// TODO: Restrict POSTed data to namespace (else can overwrite catItem)
	for(var key in data) {
		containers[data.name][key] = data[key];
	}

	res.json(containers[data.name]);
});

/**********************************************************/

app.post('/cm/delete-container-info', function (req, res) {
	var data = req.body;

	if (data == null || !data.name) {
		res.status(400).send('Missing parameters');
		return;
	}

	// TODO: Error if it wasn't there to begin with?
	delete containers[data.name];

	res.send();
});

/**********************************************************/

app.post('/cm/grant-container-permissions', function (req, res) {
	var data = req.body;

	// TODO: Allow all at once?
	if (data == null || !data.name || !data.route || !data.route.target || !data.route.path || !data.route.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var route = JSON.stringify({
		target: data.route.target,
		path:   data.route.path,
		method: data.route.method
	});

	var pathMapHash = JSON.stringify({
		target: data.route.target,
		method: data.route.method
	});

	// TODO: Error if not yet in in records?
	var container = containers[data.name] = containers[data.name] || { name: data.name };
	container.caveats = container.caveats || {};
	var caveats = container.caveats[route] = container.caveats[route] || [];
	// NOTE: Separate map for constant time instead of O(N)
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];
	container.paths[pathMapHash].push({
		string: data.route.path,
		regExp: pathToRegexp(data.route.path)
	});

	if (!data.caveats) {
		res.json(caveats);
		return;
	}

	Array.prototype.push.apply(caveats, data.caveats);
	res.json(caveats);
});

/**********************************************************/

app.post('/cm/revoke-container-permissions', function (req, res) {
	var data = req.body;

	if (data == null || !data.name || !data.route || !data.route.target || !data.route.path || !data.route.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var route = JSON.stringify({
		target: data.route.target,
		path:   data.route.path,
		method: data.route.method
	});

	var pathMapHash = JSON.stringify({
		target: data.route.target,
		method: data.route.method
	});

	// TODO: Error if not yet in in records?
	var container = containers[data.name] = containers[data.name] || { name: data.name };
	container.caveats = container.caveats || {};
	container.caveats[route] = container.caveats[route] || [];
	// NOTE: Separate map for constant time instead of O(N)
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];
	var wanted = pathToRegexp(data.route.path);
	container.paths[pathMapHash] = container.paths[pathMapHash].filter(path => !wanted.test(path.string));

	if (!data.caveats || !data.caveats.length || data.caveats.length < 1) {
		delete container.caveats[route];
		res.json(null);
		return;
	}

	res.json(container.caveats[route] = container.caveats[route].filter(caveat => !data.caveats.includes(caveat)));
});

/**********************************************************/

// Serve root Hypercat catalogue
app.get('/cat', function(req, res){
	var cat = JSON.parse(JSON.stringify(baseCat));

	for (var name in containers) {
		var container = containers[name];
		// TODO: If CM, show all
		// TODO: Hide items based on container permissions
		// TODO: If discoverable, but not accessible, inform as per PAS 7.3.1.2
		if(container.catItem) {
			cat.items.push(container.catItem);
		}
	}

	res.json(cat);
});

/**********************************************************/

app.post('/token', function(req, res){
	if (!req.container) {
		// NOTE: This can also happen if the CM never uploaded store key
		//       or if the CM added routes and never upserted info
		//       but should never happen if the CM is up to spec.
		res.status(401).send('Invalid API key');
		return;
	}

	var data = req.body;

	if (data == null || !data.target || !data.path || !data.method) {
		res.status(400).send('Missing parameters');
		return;
	}

	var targetContainer = containers[data.target];

	if (typeof(targetContainer) == "undefined" && !targetContainer) {
		res.status(400).send("Target " + data.target + " has not been approved for arbitering");
		return;
	}

	if (!targetContainer.secret) {
		res.status(400).send("Target " + data.target + " has not registered itself for arbitering");
		return;
	}

	var route = JSON.stringify({
		target: data.target,
		path:   data.path,
		method: data.method
	});

	var pathMapHash = JSON.stringify({
		target: data.target,
		method: data.method
	});

	var container = req.container;
	container.caveats = container.caveats || {};
	container.paths = container.paths || {};
	container.paths[pathMapHash] = container.paths[pathMapHash] || [];

	if (!(route in container.caveats) && !container.paths[pathMapHash].find((path) => path.regExp.test(data.path))) {
		res.status(401).send("Insufficient route permissions");
		return;
	}

	crypto.randomBytes(32, function(err, buffer){
		// TODO: Get hostname from environment variable instead of hardcoding
		var mb = new macaroons.MacaroonsBuilder('https://databox-arbiter:' + PORT, targetContainer.secret, buffer.toString('base64'));
		mb
			.add_first_party_caveat('target = ' + data.target)
			.add_first_party_caveat('path = ' + data.path)
			.add_first_party_caveat('method = ' + data.method);
		if (route in container.caveats)
			for (const caveat of container.caveats[route])
				mb.add_first_party_caveat(caveat);
		res.send(mb.getMacaroon().serialize());
	});
});

/**********************************************************/

app.get('/store/secret', function (req, res) {
	if (!req.container) {
		// NOTE: This can also happen if the CM never uploaded store key
		//       or if the CM added routes and never upserted info
		//       but should never happen if the CM is up to spec.
		res.status(401).send('Invalid API key');
		return;
	}

	if (!req.container.type) {
		// NOTE: This should never happen if the CM is up to spec.
		res.status(500).send('Container type unknown by arbiter');
		return;
	}

	if (req.container.type !== 'store') {
		res.status(403).send('Container type "' + req.container.type + '" cannot use arbiter token minting capabilities as it is not a store type');
		return;
	}

	if (req.container.secret) {
		res.status(409).send('Store shared secret already retrieved');
		return;
	}

	crypto.randomBytes(macaroons.MacaroonsConstants.MACAROON_SUGGESTED_SECRET_LENGTH, function(err, buffer){
		if (err != null) {
			res.status(500).send('Unable to register container (secret generation)');
			return;
		}

		req.container.secret = buffer;
		res.send(buffer.toString('base64'));
	});
});

https.createServer(credentials, app).listen(PORT);

module.exports = app;
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

var async = require('async');
var ai = require('ascii-images');

var tasks = [
  require('../scripts/precommit-hook'),
  require('../scripts/jshintrc'),
  require('../scripts/fancom'),
  require('../scripts/tests'),
  require('../scripts/assert')
];

// I know this carbonara code is awful, but it's 05:27AM
// and my last cigarette break was around 18:30
ai(__dirname+'/../michal.png', function(logo){
  console.log('\u001b[2J\u001b[0;0H');
  console.log(logo);
  require('../scripts/package-json')(function(err, msg) {
    if (err) {
      console.log(err);
      return;
    }
    console.log(msg);

    async.each(
      tasks,
      function(task, cb) {
        task(function(err, msg) {
          if (err) {
            throw new Error(err);
          }
          console.log(msg);
          cb();
        });
      },
      function() {
        require('../scripts/scripts')(function(err, msg){
          if (err) {
            console.log(err);
            return;
          }
          console.log(msg);
          console.log('DONE...');
        });
      }
    );
  });
});
<commit_msg>[MICHAL] - options defined<commit_after>#!/usr/bin/env node
'use strict';

var cliArgs = require('command-line-args');
var async = require('async');
var ai = require('ascii-images');

var cli = cliArgs(
  {
    name: 'all',
    type: Boolean,
    alias: 'a',
    description: 'Install everything'
  },
  {
    name: 'no-test',
    type: Boolean,
    alias:'t',
    description: 'Install everything but tests'
  },
  {
    name: 'basic',
    type: Boolean,
    alias: 'b',
    description: 'Install only package.json, fancom & jshint'
  }
);
//
// var usage = cli.getUsage({
//     header: 'My Initialization Config Handling Automator. LOL.',
//     footer: 'For more information, visit http://example.com'
// });

var options = cli.parse();

var tasks = [
  require('../scripts/precommit-hook'),
  require('../scripts/jshintrc'),
  require('../scripts/fancom'),
  require('../scripts/tests'),
  require('../scripts/assert')
];

// I know this carbonara code is awful, but it's 05:27AM
// and my last cigarette break was around 18:30
ai(__dirname+'/../michal.png', function(logo){
  console.log('\u001b[2J\u001b[0;0H');
  console.log(logo);

  if (Object.keys(options).length === 0) {

  }

  require('../scripts/package-json')(function(err, msg) {
    if (err) {
      console.log(err);
      return;
    }
    console.log(msg);

    async.each(
      tasks,
      function(task, cb) {
        task(function(err, msg) {
          if (err) {
            throw new Error(err);
          }
          console.log(msg);
          cb();
        });
      },
      function() {
        require('../scripts/scripts')(function(err, msg){
          if (err) {
            console.log(err);
            return;
          }
          console.log(msg);
          console.log('DONE...');
        });
      }
    );
  });
});
<|endoftext|>


<commit_before>import PureComponent from '../PureComponent';
import {Card} from 'react-toolbox/lib/card';
import {Button} from 'react-toolbox/lib/button';
import {Dropdown} from 'react-toolbox/lib/dropdown';
import Chart from './chart';
var _ = require('../underscore_ext').default;
import {v, showWizard, suitableColumns} from './utils';
import './icons.css';
import {div, label, h2, i, a, span, el} from './react-hyper';

var button = el(Button);
var card = el(Card);
var chart = el(Chart);
var dropdown = el(Dropdown);

var styles = require('./ChartWizard.module.css');

var closeButton = onClose =>
	a(i({className: 'material-icons ' + styles.close, onClick: onClose}, 'close'));

var doneButton = onDone =>
	button({onClick: onDone, disabled: !onDone, label: 'Done', className: styles.done});

var wizard = ({onClose, title, left = null, right = null}, ...children) =>
	card({className: styles.wizard},
		closeButton(onClose),
		h2(title),
		div(...children),
		div({className: styles.actions}, left, right));

//
// compare subgroups selections
//

var boxOrViolinModes = [
	{'data-chart': 'boxplot', label: 'Box plot',
		icon: i({className: 'icon icon-box'})},
	{'data-chart': 'violin', label: 'Violin plot',
		icon: i({className: 'icon icon-violin'})}
];

var isFloat = (columns, id) => !columns[id].codes;
var optIsFloat = ({columns}) => ({value}) => isFloat(columns, value);
var optNotFloat = x => y => !optIsFloat(x)(y);
var isMulti = _.curry(({columns}, {value}) =>
		isFloat(columns, value) && columns[value].fields.length > 1);

var yIsSet = ({ycolumn}) => v(ycolumn);
var xyIsSet = ({ycolumn, xcolumn}) => v(ycolumn) && v(xcolumn);

// if y is multi, allow 'none' for x to do field boxplot
var noX = ({columns}, id) => v(id) && columns[id].fields.length > 1 ?
	[{value: 'none', label: 'Column fields'}] : [];

var boxOrViolinYDatasets = appState => suitableColumns(appState, true);

var boxOrViolinXDatasets = appState => suitableColumns(appState, false)
	.filter(optNotFloat(appState));

var boxOrViolinDatasets = appState => {
	var x = boxOrViolinXDatasets(appState),
		y = boxOrViolinYDatasets(appState);
	// If x is empty, only allow multi columns
	return {x, y: x.length ? y : y.filter(isMulti(appState))};
};

// If x is 'none' and y is multi, use 'none'.
// If x is set, and isn't same as y, and isn't float, use it.
var getX = (columns, y, id) => id === 'none' && v(y) && isMulti({columns}, {value: y}) ||
	v(id) && id !== y && !isFloat(columns, id) ? id : undefined;

var boxOrViolinInit = appState => {
	var {columns, chartState: {xcolumn, ycolumn, setColumn}} = appState,
		y = v(setColumn) || v(ycolumn), // column selection, or previous view
		x = getX(columns, y, xcolumn);
	return {
		ycolumn: y,
		xcolumn: x
	};
};

var boxOrViolinCanDraw = appState =>
	boxOrViolinDatasets(appState).y.length > 0;

var isValid = ({ycolumn, xcolumn}, appState) =>
	v(ycolumn) && v(xcolumn) || v(ycolumn) && isMulti(appState, {value: ycolumn});

// should ask for type if y is float
var needType = (state, appState) =>
	isValid(state, appState) && isFloat(appState.columns, state.ycolumn);

var bvDisabled = (state, props) =>
	(props['data-chart'] === 'violin') ===  !!state.violin;

var boxOrViolinPage = ({onMode, onDone, onChart, onX, onY, onClose,
		state, props: {appState}}) =>
	wizard({title: "Compare subgroups", onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(isValid(state, appState) && onDone)},
		div({className: styles.modes},
			div(dropdown({label: 'Show data from:', onChange: onY,
				value: state.ycolumn, source: boxOrViolinYDatasets(appState)})),
			div(dropdown({label: 'Subgroup samples by', onChange: onX,
				value: state.xcolumn,
				source: boxOrViolinXDatasets(appState)
					.concat(noX(appState, state.ycolumn))})),
			needType(state, appState) ?
				div(label('I want a'),
					...boxOrViolinModes.map(props =>
						button({onClick: onChart, disabled: bvDisabled(state, props),
							...props}))) :
				null));

//
// histogram/distribution selection
// can also draw boxplot, for multi-valued columns
//

var histDatasets = appState => suitableColumns(appState, true);
var histInit = ({chartState: {ycolumn, setColumn}}) => ({
	ycolumn: setColumn || v(ycolumn),
	xcolumn: undefined
});
var histCanDraw = appState => suitableColumns(appState, true).length > 0;

var histOrDistPage = ({onY, onMode, onDone, onClose, state, props: {appState}}) =>
	wizard({title: 'See a Column Distribution', onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(yIsSet(state) && onDone)},
		div({className: styles.modes},
			dropdown({label: 'Show data from', onChange: onY,
			value: state.ycolumn, source: histDatasets(appState)})));

//
// scatter plot selection
//

var optNotBigMulti = ({columns}) => ({value}) => columns[value].fields.length <= 10;
var and = (a, b) => x => y => a(x)(y) && b(x)(y); // getting crazy with the point-free

// limit subcolumns in Y to something reasonable
var scatterYDatasets = appState => suitableColumns(appState, true)
	.filter(and(optIsFloat, optNotBigMulti)(appState));

var scatterXDatasets = appState => suitableColumns(appState, false)
	.filter(optIsFloat(appState));

var scatterInit = ({columns, chartState: {ycolumn, xcolumn, setColumn}}) => ({
	ycolumn: setColumn && isFloat(columns, setColumn) ? setColumn :
		v(ycolumn) && isFloat(columns, ycolumn) ? ycolumn : undefined,
		xcolumn: v(xcolumn) && isFloat(columns, xcolumn) ? xcolumn : undefined
});

var scatterCanDraw = appState => {
	var y = _.pluck(scatterYDatasets(appState), 'value'),
		x = _.pluck(scatterXDatasets(appState), 'value');
	return x.length && y.length && _.uniq(y.concat(x)).length > 1;
};

var scatterPage = ({onY, onX, onMode, onDone, onClose, state, props: {appState}}) =>
	wizard({title: "Scatter plot", onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(xyIsSet(state) && onDone)},
		div({className: styles.mode},
			dropdown({onChange: onX, value: state.xcolumn, label: 'Pick the X axis',
				source: scatterXDatasets(appState)})),
			dropdown({onChange: onY, value: state.ycolumn, label: 'Pick the Y axis',
				source: scatterYDatasets(appState)}));

var noop = () => {};
var init = {
	start: noop,
	boxOrViolin: boxOrViolinInit,
	histOrDist: histInit,
	scatter: scatterInit,
};

var canDraw = {
	boxOrViolin: boxOrViolinCanDraw,
	histOrDist: histCanDraw,
	scatter: scatterCanDraw
};

var modeLabel = text => span({className: styles.label}, text);

var startModes = [
	{'data-mode': 'boxOrViolin', label: modeLabel('Compare subgroups')},
	{'data-mode': 'histOrDist', label: modeLabel('See a column distribution')},
	{'data-mode': 'scatter', label: modeLabel('Make a scatter plot')}
];

var iconList = (...icons) => span({className: styles.icons}, ...(icons.map(icon =>
				i({className: 'icon icon-' + icon}))));

var icons = {
	boxOrViolin: iconList('box', 'violin'),
	histOrDist: iconList('bar'),
	scatter: iconList('scatter')
};

var modeButton = (appState, onMode) => props =>
	button({onClick: onMode, icon: icons[props['data-mode']],
		disabled: !canDraw[props['data-mode']](appState), ...props});

var startPage = ({onMode, onClose, props: {appState}}) =>
	wizard({title: 'What do you want to do?', onClose,
		left: button({onClick: onClose, label: 'Back', className: styles.back})},
		div({className: styles.modes},
			...startModes.map(modeButton(appState, onMode))));

var page = {
	start: startPage,
	boxOrViolin: boxOrViolinPage,
	histOrDist: histOrDistPage,
	scatter: scatterPage,
	chart: ({props}) => chart(props)
};

export default class ChartWizard extends PureComponent {
	constructor(props) {
	    super(props);
		var {chartState: {ycolumn, xcolumn, violin} = {}} = this.props.appState;
	    this.state = {
			mode: showWizard(this.props.appState) ? 'start' : 'chart',
			ycolumn,
			xcolumn,
			violin
		};
	}

	// Most actions are blocked in this mode, but we could have datasets
	// or column data arrive. In that case more columns could be available
	// to this wizard. We shouldn't see changes to y & x except from ourselves.
	componentWillReceiveProps(props) {
		var {appState} = props;
		// maybe set xcolumn & ycolumn too
		if (!showWizard(appState)) {
			this.setState({mode: 'chart'});
		} else if (this.state.mode !== 'start') {
			this.setState({mode: 'start'});
		}
	}

	onMode = ev => {
		var {appState} = this.props,
			mode = ev.currentTarget.dataset.mode;
		this.setState({mode, ...init[mode](appState)});
	}
	onClose = () => {
		var {callback, appState: {chartState = {}}} = this.props;
		callback(['chart-set-state',
				_.assoc(chartState,
					'setColumn', undefined,
					'another', false)]);
		callback([chartState.another ? 'chart' : 'heatmap']);
	}
	onChart = ev => {
		this.setState({violin: ev.currentTarget.dataset.chart === 'violin'});
	}
	onDone = () => {
		var {callback, appState} = this.props,
			{chartState: {colorColumn} = {}} = appState,
			{ycolumn, xcolumn, violin, mode} = this.state;
		callback(['chart-set-state',
			_.assoc(appState.chartState,
				'ycolumn', ycolumn,
				'xcolumn', xcolumn,
				'colorColumn', mode === 'scatter' ? colorColumn : undefined,
				'violin', violin,
				'setColumn', undefined,
				'another', false)]);
	}
	onX = xcolumn => {
		var {ycolumn} = this.state;
		this.setState({xcolumn});
		if (ycolumn === xcolumn) { // disallow x = y
			this.setState({ycolumn: undefined});
		}
	}
	onY = ycolumn => {
		var {xcolumn} = this.state;
		this.setState({ycolumn});
		if (ycolumn === xcolumn) { // disallow x = y
			this.setState({xcolumn: undefined});
		}
	}
	render() {
		return page[this.state.mode](this);
	}
}
<commit_msg>Drop violin icon from wizard start page<commit_after>import PureComponent from '../PureComponent';
import {Card} from 'react-toolbox/lib/card';
import {Button} from 'react-toolbox/lib/button';
import {Dropdown} from 'react-toolbox/lib/dropdown';
import Chart from './chart';
var _ = require('../underscore_ext').default;
import {v, showWizard, suitableColumns} from './utils';
import './icons.css';
import {div, label, h2, i, a, span, el} from './react-hyper';

var button = el(Button);
var card = el(Card);
var chart = el(Chart);
var dropdown = el(Dropdown);

var styles = require('./ChartWizard.module.css');

var closeButton = onClose =>
	a(i({className: 'material-icons ' + styles.close, onClick: onClose}, 'close'));

var doneButton = onDone =>
	button({onClick: onDone, disabled: !onDone, label: 'Done', className: styles.done});

var wizard = ({onClose, title, left = null, right = null}, ...children) =>
	card({className: styles.wizard},
		closeButton(onClose),
		h2(title),
		div(...children),
		div({className: styles.actions}, left, right));

//
// compare subgroups selections
//

var boxOrViolinModes = [
	{'data-chart': 'boxplot', label: 'Box plot',
		icon: i({className: 'icon icon-box'})},
	{'data-chart': 'violin', label: 'Violin plot',
		icon: i({className: 'icon icon-violin'})}
];

var isFloat = (columns, id) => !columns[id].codes;
var optIsFloat = ({columns}) => ({value}) => isFloat(columns, value);
var optNotFloat = x => y => !optIsFloat(x)(y);
var isMulti = _.curry(({columns}, {value}) =>
		isFloat(columns, value) && columns[value].fields.length > 1);

var yIsSet = ({ycolumn}) => v(ycolumn);
var xyIsSet = ({ycolumn, xcolumn}) => v(ycolumn) && v(xcolumn);

// if y is multi, allow 'none' for x to do field boxplot
var noX = ({columns}, id) => v(id) && columns[id].fields.length > 1 ?
	[{value: 'none', label: 'Column fields'}] : [];

var boxOrViolinYDatasets = appState => suitableColumns(appState, true);

var boxOrViolinXDatasets = appState => suitableColumns(appState, false)
	.filter(optNotFloat(appState));

var boxOrViolinDatasets = appState => {
	var x = boxOrViolinXDatasets(appState),
		y = boxOrViolinYDatasets(appState);
	// If x is empty, only allow multi columns
	return {x, y: x.length ? y : y.filter(isMulti(appState))};
};

// If x is 'none' and y is multi, use 'none'.
// If x is set, and isn't same as y, and isn't float, use it.
var getX = (columns, y, id) => id === 'none' && v(y) && isMulti({columns}, {value: y}) ||
	v(id) && id !== y && !isFloat(columns, id) ? id : undefined;

var boxOrViolinInit = appState => {
	var {columns, chartState: {xcolumn, ycolumn, setColumn}} = appState,
		y = v(setColumn) || v(ycolumn), // column selection, or previous view
		x = getX(columns, y, xcolumn);
	return {
		ycolumn: y,
		xcolumn: x
	};
};

var boxOrViolinCanDraw = appState =>
	boxOrViolinDatasets(appState).y.length > 0;

var isValid = ({ycolumn, xcolumn}, appState) =>
	v(ycolumn) && v(xcolumn) || v(ycolumn) && isMulti(appState, {value: ycolumn});

// should ask for type if y is float
var needType = (state, appState) =>
	isValid(state, appState) && isFloat(appState.columns, state.ycolumn);

var bvDisabled = (state, props) =>
	(props['data-chart'] === 'violin') ===  !!state.violin;

var boxOrViolinPage = ({onMode, onDone, onChart, onX, onY, onClose,
		state, props: {appState}}) =>
	wizard({title: "Compare subgroups", onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(isValid(state, appState) && onDone)},
		div({className: styles.modes},
			div(dropdown({label: 'Show data from:', onChange: onY,
				value: state.ycolumn, source: boxOrViolinYDatasets(appState)})),
			div(dropdown({label: 'Subgroup samples by', onChange: onX,
				value: state.xcolumn,
				source: boxOrViolinXDatasets(appState)
					.concat(noX(appState, state.ycolumn))})),
			needType(state, appState) ?
				div(label('I want a'),
					...boxOrViolinModes.map(props =>
						button({onClick: onChart, disabled: bvDisabled(state, props),
							...props}))) :
				null));

//
// histogram/distribution selection
// can also draw boxplot, for multi-valued columns
//

var histDatasets = appState => suitableColumns(appState, true);
var histInit = ({chartState: {ycolumn, setColumn}}) => ({
	ycolumn: setColumn || v(ycolumn),
	xcolumn: undefined
});
var histCanDraw = appState => suitableColumns(appState, true).length > 0;

var histOrDistPage = ({onY, onMode, onDone, onClose, state, props: {appState}}) =>
	wizard({title: 'See a Column Distribution', onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(yIsSet(state) && onDone)},
		div({className: styles.modes},
			dropdown({label: 'Show data from', onChange: onY,
			value: state.ycolumn, source: histDatasets(appState)})));

//
// scatter plot selection
//

var optNotBigMulti = ({columns}) => ({value}) => columns[value].fields.length <= 10;
var and = (a, b) => x => y => a(x)(y) && b(x)(y); // getting crazy with the point-free

// limit subcolumns in Y to something reasonable
var scatterYDatasets = appState => suitableColumns(appState, true)
	.filter(and(optIsFloat, optNotBigMulti)(appState));

var scatterXDatasets = appState => suitableColumns(appState, false)
	.filter(optIsFloat(appState));

var scatterInit = ({columns, chartState: {ycolumn, xcolumn, setColumn}}) => ({
	ycolumn: setColumn && isFloat(columns, setColumn) ? setColumn :
		v(ycolumn) && isFloat(columns, ycolumn) ? ycolumn : undefined,
		xcolumn: v(xcolumn) && isFloat(columns, xcolumn) ? xcolumn : undefined
});

var scatterCanDraw = appState => {
	var y = _.pluck(scatterYDatasets(appState), 'value'),
		x = _.pluck(scatterXDatasets(appState), 'value');
	return x.length && y.length && _.uniq(y.concat(x)).length > 1;
};

var scatterPage = ({onY, onX, onMode, onDone, onClose, state, props: {appState}}) =>
	wizard({title: "Scatter plot", onClose,
			left: button({onClick: onMode, 'data-mode': 'start', label: 'Back',
				className: styles.back}),
			right: doneButton(xyIsSet(state) && onDone)},
		div({className: styles.mode},
			dropdown({onChange: onX, value: state.xcolumn, label: 'Pick the X axis',
				source: scatterXDatasets(appState)})),
			dropdown({onChange: onY, value: state.ycolumn, label: 'Pick the Y axis',
				source: scatterYDatasets(appState)}));

var noop = () => {};
var init = {
	start: noop,
	boxOrViolin: boxOrViolinInit,
	histOrDist: histInit,
	scatter: scatterInit,
};

var canDraw = {
	boxOrViolin: boxOrViolinCanDraw,
	histOrDist: histCanDraw,
	scatter: scatterCanDraw
};

var modeLabel = text => span({className: styles.label}, text);

var startModes = [
	{'data-mode': 'boxOrViolin', label: modeLabel('Compare subgroups')},
	{'data-mode': 'histOrDist', label: modeLabel('See a column distribution')},
	{'data-mode': 'scatter', label: modeLabel('Make a scatter plot')}
];

var iconList = (...icons) => span({className: styles.icons}, ...(icons.map(icon =>
				i({className: 'icon icon-' + icon}))));

var icons = {
	boxOrViolin: iconList('box'),
	histOrDist: iconList('bar'),
	scatter: iconList('scatter')
};

var modeButton = (appState, onMode) => props =>
	button({onClick: onMode, icon: icons[props['data-mode']],
		disabled: !canDraw[props['data-mode']](appState), ...props});

var startPage = ({onMode, onClose, props: {appState}}) =>
	wizard({title: 'What do you want to do?', onClose,
		left: button({onClick: onClose, label: 'Back', className: styles.back})},
		div({className: styles.modes},
			...startModes.map(modeButton(appState, onMode))));

var page = {
	start: startPage,
	boxOrViolin: boxOrViolinPage,
	histOrDist: histOrDistPage,
	scatter: scatterPage,
	chart: ({props}) => chart(props)
};

export default class ChartWizard extends PureComponent {
	constructor(props) {
	    super(props);
		var {chartState: {ycolumn, xcolumn, violin} = {}} = this.props.appState;
	    this.state = {
			mode: showWizard(this.props.appState) ? 'start' : 'chart',
			ycolumn,
			xcolumn,
			violin
		};
	}

	// Most actions are blocked in this mode, but we could have datasets
	// or column data arrive. In that case more columns could be available
	// to this wizard. We shouldn't see changes to y & x except from ourselves.
	componentWillReceiveProps(props) {
		var {appState} = props;
		// maybe set xcolumn & ycolumn too
		if (!showWizard(appState)) {
			this.setState({mode: 'chart'});
		} else if (this.state.mode !== 'start') {
			this.setState({mode: 'start'});
		}
	}

	onMode = ev => {
		var {appState} = this.props,
			mode = ev.currentTarget.dataset.mode;
		this.setState({mode, ...init[mode](appState)});
	}
	onClose = () => {
		var {callback, appState: {chartState = {}}} = this.props;
		callback(['chart-set-state',
				_.assoc(chartState,
					'setColumn', undefined,
					'another', false)]);
		callback([chartState.another ? 'chart' : 'heatmap']);
	}
	onChart = ev => {
		this.setState({violin: ev.currentTarget.dataset.chart === 'violin'});
	}
	onDone = () => {
		var {callback, appState} = this.props,
			{chartState: {colorColumn} = {}} = appState,
			{ycolumn, xcolumn, violin, mode} = this.state;
		callback(['chart-set-state',
			_.assoc(appState.chartState,
				'ycolumn', ycolumn,
				'xcolumn', xcolumn,
				'colorColumn', mode === 'scatter' ? colorColumn : undefined,
				'violin', violin,
				'setColumn', undefined,
				'another', false)]);
	}
	onX = xcolumn => {
		var {ycolumn} = this.state;
		this.setState({xcolumn});
		if (ycolumn === xcolumn) { // disallow x = y
			this.setState({ycolumn: undefined});
		}
	}
	onY = ycolumn => {
		var {xcolumn} = this.state;
		this.setState({ycolumn});
		if (ycolumn === xcolumn) { // disallow x = y
			this.setState({xcolumn: undefined});
		}
	}
	render() {
		return page[this.state.mode](this);
	}
}
<|endoftext|>


<commit_before>/**
 * Pattern for Redactor
 * Copyright 2013-2014 Simplon B.V. - Wichert Akkerman
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([
            "jquery",
            "underscore",
            "pat-registry",
            "pat-utils",
            "pat-parser",
            "pat-pluggable",
            "redactor",
            ], function ($, _, registry, utils, Parser, pluggablePattern, Redactor) {
                return factory.apply(this, arguments);
        });
    } else {
        factory(root.jQuery, _, root.patterns, utils, root.patterns.Parser, pluggablePattern, Redactor);
    }
}(this, function($, _, registry, utils, Parser, pluggablePattern, Redactor) {
    var parser = new Parser('redactor');

    parser.add_argument('toolbar-type', 'standard', ['standard', 'fixed', 'air']);
    parser.add_argument('toolbar-external', null);
    parser.add_argument('toolbar-fixed-target', null);
    parser.add_argument('buttons',
        ['html', 'formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'outdent', 'indent','alignment', 'image', 'video', 'link', 'horizontal-rule', 'table'],
        ['formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'image', 'video', 'link', 'horizontal-rule'],
        true);
    parser.add_argument('air-buttons', [],
        ['formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'image', 'video', 'link', 'horizontal-rule'],
        true);
    parser.add_argument('formatting',
        ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5'],
        ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5'],
        true);
    parser.add_argument('allowed-tags', [], [], true);
    parser.add_argument('denied-tags', [], [], true);
    parser.add_argument('min-height', 0);
    parser.add_argument('file-upload', undefined);
    parser.add_argument('image-upload', undefined);
    parser.add_argument('image-get-json', undefined);

    // XXX: Deprecated
    parser.add_argument('fileupload', undefined);
    parser.add_argument('imageupload', undefined);
    parser.add_argument('imagegetjson', undefined);

    var redactor = pluggablePattern.extend({
        name: 'redactor',
        trigger: '.pat-redactor',
        plugins: {},

        init: function($el, opts) {
            var i, poptions = parser.parse($el, opts), options = {};
            if ($.browser.msie && parseInt($.browser.version, 10) === 8) {
                options.rangy = true;
            }

            switch (poptions.toolbar.type) {
                case 'air':
                    options.air = true;
                    if (poptions.airButtons.length !==0) {
                        options.airButtons = poptions.airButtons;
                    }
                    break;
                case 'fixed':
                    options.toolbarFixed = true;
                    if (poptions.toolbar['fixed-target']) {
                        options.toolbarFixedTarget = poptions.toolbar['fixed-target'];
                    }
                    break;
                default:
                    break;
            }
            if (poptions.toolbar.external) {
                options.toolbarExternal = poptions.toolbar.external;
            }
            // Remove dashes from button names, per redactor convention
            for (i=0; i< poptions.buttons.length; i++) {
                poptions.buttons[i] = poptions.buttons[i].replace('-', '');
            }
            options.buttons = poptions.buttons;

            _.extend(options,
                _.pick(poptions,
                    ['minHeight', 'fileUpload', 'imageGetJson', 'deniedTags', 'allowedTags', 'formatting']
                )
            );
            // XXX Deprecated (see above where parser's arguments are added)
            if (poptions.imageupload) {
                options.imageUpload = poptions.imageupload;
            }
            if (poptions.imagegetjson) {
                options.imageGetJson = poptions.imagegetjson;
            }
            // Until here
            $el.redactor(this.initializePlugins(options)[0]);
        }
    });
    registry.register(redactor);
    return redactor;
}));
<commit_msg>For the buttons, make all default values also available as choices<commit_after>/**
 * Pattern for Redactor
 * Copyright 2013-2014 Simplon B.V. - Wichert Akkerman
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([
            "jquery",
            "underscore",
            "pat-registry",
            "pat-utils",
            "pat-parser",
            "pat-pluggable",
            "redactor",
            ], function ($, _, registry, utils, Parser, pluggablePattern, Redactor) {
                return factory.apply(this, arguments);
        });
    } else {
        factory(root.jQuery, _, root.patterns, utils, root.patterns.Parser, pluggablePattern, Redactor);
    }
}(this, function($, _, registry, utils, Parser, pluggablePattern, Redactor) {
    var parser = new Parser('redactor');

    parser.add_argument('toolbar-type', 'standard', ['standard', 'fixed', 'air']);
    parser.add_argument('toolbar-external', null);
    parser.add_argument('toolbar-fixed-target', null);
    parser.add_argument('buttons',
        ['html', 'formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'outdent', 'indent', 'alignment', 'image', 'video', 'link', 'horizontal-rule', 'table'],
        ['html', 'formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'outdent', 'indent', 'alignment', 'image', 'video', 'link', 'horizontal-rule', 'table'],
        true);
    parser.add_argument('air-buttons', [],
        ['formatting', 'bold', 'italic', 'unordered-list', 'ordered-list', 'image', 'video', 'link', 'horizontal-rule'],
        true);
    parser.add_argument('formatting',
        ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5'],
        ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5'],
        true);
    parser.add_argument('allowed-tags', [], [], true);
    parser.add_argument('denied-tags', [], [], true);
    parser.add_argument('min-height', 0);
    parser.add_argument('file-upload', undefined);
    parser.add_argument('image-upload', undefined);
    parser.add_argument('image-get-json', undefined);

    // XXX: Deprecated
    parser.add_argument('fileupload', undefined);
    parser.add_argument('imageupload', undefined);
    parser.add_argument('imagegetjson', undefined);

    var redactor = pluggablePattern.extend({
        name: 'redactor',
        trigger: '.pat-redactor',
        plugins: {},

        init: function($el, opts) {
            var i, poptions = parser.parse($el, opts), options = {};
            if ($.browser.msie && parseInt($.browser.version, 10) === 8) {
                options.rangy = true;
            }

            switch (poptions.toolbar.type) {
                case 'air':
                    options.air = true;
                    if (poptions.airButtons.length !==0) {
                        options.airButtons = poptions.airButtons;
                    }
                    break;
                case 'fixed':
                    options.toolbarFixed = true;
                    if (poptions.toolbar['fixed-target']) {
                        options.toolbarFixedTarget = poptions.toolbar['fixed-target'];
                    }
                    break;
                default:
                    break;
            }
            if (poptions.toolbar.external) {
                options.toolbarExternal = poptions.toolbar.external;
            }
            // Remove dashes from button names, per redactor convention
            for (i=0; i< poptions.buttons.length; i++) {
                poptions.buttons[i] = poptions.buttons[i].replace('-', '');
            }
            options.buttons = poptions.buttons;

            _.extend(options,
                _.pick(poptions,
                    ['minHeight', 'fileUpload', 'imageGetJson', 'deniedTags', 'allowedTags', 'formatting']
                )
            );
            // XXX Deprecated (see above where parser's arguments are added)
            if (poptions.imageupload) {
                options.imageUpload = poptions.imageupload;
            }
            if (poptions.imagegetjson) {
                options.imageGetJson = poptions.imagegetjson;
            }
            // Until here
            $el.redactor(this.initializePlugins(options)[0]);
        }
    });
    registry.register(redactor);
    return redactor;
}));
<|endoftext|>


<commit_before>#!/usr/bin/env node
var http = require('http');
var spawn = require('child_process').spawn;
var fs = require('fs');
var qs = require('querystring');

var bouncy = require('bouncy');
var ent = require('ent');
var parseCommand = require('shell-quote').parse;
var copy = require('shallow-copy');

var concat = require('concat-stream');
var finished = require('tap-finished');
var launcher = require('browser-launcher');

var argv = require('optimist').boolean('u').argv;
if (argv.h || argv.help) {
    return fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
}
if (argv.show === undefined) argv.show = true;

var unglob = require('../lib/unglob.js');

var path = require('path');
var prelude = fs.readFileSync(__dirname + '/../bundle/prelude.js', 'utf8');

var bundle, launch;
var scripts = [];
var htmlQueue = [];
var pending = 4;
var dir = path.resolve(argv._[0] === '-' ? false : argv._[0] || process.cwd());
var ecstatic = require('ecstatic')(dir);
var resolve = require('resolve').sync;
var pkg = { testling: {} };

if ((process.stdin.isTTY || argv._.length) && argv._[0] !== '-') {
    try {
        pkg = require(path.join(dir, 'package.json'));
    }
    catch (err) {
        if (err.code === 'MODULE_NOT_FOUND') {
            console.error(
                'No package.json in ' + dir + ' found.\n'
                + 'Consult the quick start guide for how to create one:\n'
                + 'https://ci.testling.com/guide/quick_start'
            );
        }
        else {
            console.error(err.message);
        }
        return;
    }

    if (!pkg.testling) {
        console.error(
            'The "testling" field isn\'t present '
            + 'in ' + path.join(dir, 'package.json') + '.\n'
            + 'This field is required by testling. Please consult:\n'
            + 'https://ci.testling.com/guide/quick_start'
        );
        return;
    }
    var bundleId = Math.floor(Math.pow(16,8)*Math.random()).toString(16);

    if (pkg.testling.preprocess) {
        // todo
    }
    else if (!pkg.testling.html) {
        unglob(dir, pkg.testling, function (err, expanded) {
            if (err) return console.error(err);

            var env = copy(process.env);
            env.PATH = path.resolve(dir, 'node_modules/.bin')
                + ':' + env.PATH + ':'
                + path.resolve(__dirname, '../node_modules/.bin')
            ;
            scripts = expanded.script;

            if (expanded.file.length) {
                var args = expanded.file.concat('--debug');

                var ps = spawn('browserify', args, { cwd: dir, env: env });
                ps.stdout.pipe(concat(function (src) {
                    bundle = src;
                    htmlQueue.forEach(function (f) { getHTML(f) });
                }));
                ps.stderr.pipe(process.stderr);
                ps.on('exit', function (code) {
                    if (code !== 0) {
                        console.error('FAILURE: non-zero exit code');
                    }
                    else ready();
                });
            }
            else if (expanded.script.length) {
                bundle = '';
                ready();
            }
            else {
                console.error(
                    'No test files, no scripts, and no html parameter found'
                    + 'after expanding the globs. At least one file or a custom'
                    + 'html field is needed.'
                );
                process.exit(1);
            }
        });
    }

    if (pkg.testling.html) {
        ready();
    }
}
else {
    process.stdin.pipe(concat(function (src) {
        bundle = src;
        htmlQueue.forEach(function (f) { getHTML(f) });
        ready();
    }));
}

var xws = require('xhr-write-stream')();

if (argv.html) {
    ready();ready();ready();
    return;
}

var server = http.createServer(function (req, res) {
    var u = req.url.split('?')[0];
    res.setHeader('connection', 'close');

    if (u === '/__testling/sock') {
        req.pipe(xws(function (stream) {
            stream.pipe(process.stdout, { end: false });
            stream.pipe(finished(function (results) {
                if (results.ok) {
                    process.exit(0);
                }
                else process.exit(1);
            }));
        }));
        req.on('end', res.end.bind(res));
    }
    else if (u.replace(/\/$/, '') === '/__testling') {
        res.setHeader('content-type', 'text/html');
        getHTML(function (html) { res.end(html) });
    }
    else if (u.split('/')[1] === '__testling') {
        req.url = req.url.replace(/^\/__testling/, '');
        ecstatic(req, res);
    }
    else {
        ecstatic(req, res);
    }
});
server.listen(0, ready);

var customServer = pkg.testling.server && (function () {
    var cmd = pkg.testling.server;
    if (!Array.isArray(cmd)) cmd = parseCommand(cmd);
    if (/\.js$/.test(cmd[0])) cmd.unshift(process.execPath);

    var env = copy(process.env);
    env.PORT = Math.floor((Math.pow(2, 16) - 10000) * Math.random() + 10000);

    var ps = spawn(cmd[0], cmd.slice(1), { cwd: dir, env: env });
    ps.stdout.pipe(process.stdout);
    ps.stderr.pipe(process.stderr);

    ps.on('exit', function (code) {
        console.error('testling.server exited with status: ' + code);
    });

    return { port: env.PORT };
})();

var bouncer = bouncy(function (req, res, bounce) {
    var u = req.url.split('?')[0];
    if (!customServer || u.split('/')[1] === '__testling') {
        bounce(server.address().port);
    }
    else {
        bounce(customServer.port, { headers: { connection: 'close' } });
    }
});
bouncer.listen(0, ready);

if ((argv.x || argv.bcmd) && typeof (argv.x || argv.bcmd) === 'boolean') {
    console.error('-x expects an argument');
    process.exit(1);
}

if (argv.u || argv.cmd || argv.x || argv.bcmd) {
    ready();
}
else {
    launcher(function (err, launch_) {
        if (err) return console.error(err);
        launch = launch_;
        ready();
    });
}

function ready () {
    if (--pending !== 0) return;

    if (argv.html) {
        getHTML(function (html) { console.log(html) });
        return;
    }

    var opts = {
        headless: true,
        browser: launch && launch.browsers && launch.browsers.local.filter(function(b){ return b.headless; })[0].name
    };
    var href = 'http://localhost:'
        + bouncer.address().port
        + '/__testling?'
        + qs.stringify({ show: Boolean(argv.show) })
    ;
    if (argv.u) {
        console.log(href);
    }
    else if (argv.bcmd || argv.x) {
        var cmd = parseCommand(argv.bcmd || argv.x);
        var ps = spawn(cmd[0], cmd.slice(1).concat(href));
        ps.stderr.pipe(process.stderr);
        ps.stdout.pipe(process.stderr);
        ps.on('exit', function (code) {
            if (code !== 0) {
                console.error(
                    'Command ' + JSON.stringify(argv.bcmd)
                    + ' terminated with non-zero exit code'
                );
            }
        });
    }
    else {
        launch(href, opts, function (err, ps) {
            if (err) return console.error(err);
        });
    }
}

function getHTML (cb) {

    if (pkg.testling.html) {
        fs.readFile(path.join(dir, pkg.testling.html), function (err, src) {
            if (err) console.error('while loading testling.html: ' + err);
            else {
                cb('' + src);
            }
        });
        return;
    }

    if (bundle === undefined) return htmlQueue.push(cb);

    var before = '', after = '';
    if (/^mocha(-|$)/.test(pkg.testling.harness)) {
        var mochaFile = path.relative(dir,
            resolve('mocha/mocha.js', { basedir: dir })
        );
        var m = /^mocha-(\w+)/.exec(pkg.testling.harness);
        var ui = m && m[1] || 'bdd';
        before =
            ''
            + ''
        ;
        after = '';
    }

    cb('<!doctype html><meta charset="utf-8">'
        + '

'
        + ''
        + before
        + scripts.map(function (s) {
            return ''
            ;
        }).join('\n')
        + ''
        + after
        + ''
    );
}
<commit_msg>allow the user to specify the test harness via argv<commit_after>#!/usr/bin/env node
var http = require('http');
var spawn = require('child_process').spawn;
var fs = require('fs');
var qs = require('querystring');

var bouncy = require('bouncy');
var ent = require('ent');
var parseCommand = require('shell-quote').parse;
var copy = require('shallow-copy');

var concat = require('concat-stream');
var finished = require('tap-finished');
var launcher = require('browser-launcher');

var argv = require('optimist').boolean('u').argv;
if (argv.h || argv.help) {
    return fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
}
if (argv.show === undefined) argv.show = true;

var unglob = require('../lib/unglob.js');

var path = require('path');
var prelude = fs.readFileSync(__dirname + '/../bundle/prelude.js', 'utf8');

var bundle, launch;
var scripts = [];
var htmlQueue = [];
var pending = 4;
var dir = path.resolve(argv._[0] === '-' ? false : argv._[0] || process.cwd());
var ecstatic = require('ecstatic')(dir);
var resolve = require('resolve').sync;
var pkg = { testling: { harness: argv.harness } };

if ((process.stdin.isTTY || argv._.length) && argv._[0] !== '-') {
    try {
        pkg = require(path.join(dir, 'package.json'));
    }
    catch (err) {
        if (err.code === 'MODULE_NOT_FOUND') {
            console.error(
                'No package.json in ' + dir + ' found.\n'
                + 'Consult the quick start guide for how to create one:\n'
                + 'https://ci.testling.com/guide/quick_start'
            );
        }
        else {
            console.error(err.message);
        }
        return;
    }

    if (!pkg.testling) {
        console.error(
            'The "testling" field isn\'t present '
            + 'in ' + path.join(dir, 'package.json') + '.\n'
            + 'This field is required by testling. Please consult:\n'
            + 'https://ci.testling.com/guide/quick_start'
        );
        return;
    }
    var bundleId = Math.floor(Math.pow(16,8)*Math.random()).toString(16);

    if (pkg.testling.preprocess) {
        // todo
    }
    else if (!pkg.testling.html) {
        unglob(dir, pkg.testling, function (err, expanded) {
            if (err) return console.error(err);

            var env = copy(process.env);
            env.PATH = path.resolve(dir, 'node_modules/.bin')
                + ':' + env.PATH + ':'
                + path.resolve(__dirname, '../node_modules/.bin')
            ;
            scripts = expanded.script;

            if (expanded.file.length) {
                var args = expanded.file.concat('--debug');

                var ps = spawn('browserify', args, { cwd: dir, env: env });
                ps.stdout.pipe(concat(function (src) {
                    bundle = src;
                    htmlQueue.forEach(function (f) { getHTML(f) });
                }));
                ps.stderr.pipe(process.stderr);
                ps.on('exit', function (code) {
                    if (code !== 0) {
                        console.error('FAILURE: non-zero exit code');
                    }
                    else ready();
                });
            }
            else if (expanded.script.length) {
                bundle = '';
                ready();
            }
            else {
                console.error(
                    'No test files, no scripts, and no html parameter found'
                    + 'after expanding the globs. At least one file or a custom'
                    + 'html field is needed.'
                );
                process.exit(1);
            }
        });
    }

    if (pkg.testling.html) {
        ready();
    }
}
else {
    process.stdin.pipe(concat(function (src) {
        bundle = src;
        htmlQueue.forEach(function (f) { getHTML(f) });
        ready();
    }));
}

var xws = require('xhr-write-stream')();

if (argv.html) {
    ready();ready();ready();
    return;
}

var server = http.createServer(function (req, res) {
    var u = req.url.split('?')[0];
    res.setHeader('connection', 'close');

    if (u === '/__testling/sock') {
        req.pipe(xws(function (stream) {
            stream.pipe(process.stdout, { end: false });
            stream.pipe(finished(function (results) {
                if (results.ok) {
                    process.exit(0);
                }
                else process.exit(1);
            }));
        }));
        req.on('end', res.end.bind(res));
    }
    else if (u.replace(/\/$/, '') === '/__testling') {
        res.setHeader('content-type', 'text/html');
        getHTML(function (html) { res.end(html) });
    }
    else if (u.split('/')[1] === '__testling') {
        req.url = req.url.replace(/^\/__testling/, '');
        ecstatic(req, res);
    }
    else {
        ecstatic(req, res);
    }
});
server.listen(0, ready);

var customServer = pkg.testling.server && (function () {
    var cmd = pkg.testling.server;
    if (!Array.isArray(cmd)) cmd = parseCommand(cmd);
    if (/\.js$/.test(cmd[0])) cmd.unshift(process.execPath);

    var env = copy(process.env);
    env.PORT = Math.floor((Math.pow(2, 16) - 10000) * Math.random() + 10000);

    var ps = spawn(cmd[0], cmd.slice(1), { cwd: dir, env: env });
    ps.stdout.pipe(process.stdout);
    ps.stderr.pipe(process.stderr);

    ps.on('exit', function (code) {
        console.error('testling.server exited with status: ' + code);
    });

    return { port: env.PORT };
})();

var bouncer = bouncy(function (req, res, bounce) {
    var u = req.url.split('?')[0];
    if (!customServer || u.split('/')[1] === '__testling') {
        bounce(server.address().port);
    }
    else {
        bounce(customServer.port, { headers: { connection: 'close' } });
    }
});
bouncer.listen(0, ready);

if ((argv.x || argv.bcmd) && typeof (argv.x || argv.bcmd) === 'boolean') {
    console.error('-x expects an argument');
    process.exit(1);
}

if (argv.u || argv.cmd || argv.x || argv.bcmd) {
    ready();
}
else {
    launcher(function (err, launch_) {
        if (err) return console.error(err);
        launch = launch_;
        ready();
    });
}

function ready () {
    if (--pending !== 0) return;

    if (argv.html) {
        getHTML(function (html) { console.log(html) });
        return;
    }

    var opts = {
        headless: true,
        browser: launch && launch.browsers && launch.browsers.local.filter(function(b){ return b.headless; })[0].name
    };
    var href = 'http://localhost:'
        + bouncer.address().port
        + '/__testling?'
        + qs.stringify({ show: Boolean(argv.show) })
    ;
    if (argv.u) {
        console.log(href);
    }
    else if (argv.bcmd || argv.x) {
        var cmd = parseCommand(argv.bcmd || argv.x);
        var ps = spawn(cmd[0], cmd.slice(1).concat(href));
        ps.stderr.pipe(process.stderr);
        ps.stdout.pipe(process.stderr);
        ps.on('exit', function (code) {
            if (code !== 0) {
                console.error(
                    'Command ' + JSON.stringify(argv.bcmd)
                    + ' terminated with non-zero exit code'
                );
            }
        });
    }
    else {
        launch(href, opts, function (err, ps) {
            if (err) return console.error(err);
        });
    }
}

function getHTML (cb) {

    if (pkg.testling.html) {
        fs.readFile(path.join(dir, pkg.testling.html), function (err, src) {
            if (err) console.error('while loading testling.html: ' + err);
            else {
                cb('' + src);
            }
        });
        return;
    }

    if (bundle === undefined) return htmlQueue.push(cb);

    var before = '', after = '';
    if (/^mocha(-|$)/.test(pkg.testling.harness)) {
        var mochaFile = path.relative(dir,
            resolve('mocha/mocha.js', { basedir: dir })
        );
        var m = /^mocha-(\w+)/.exec(pkg.testling.harness);
        var ui = m && m[1] || 'bdd';
        before =
            ''
            + ''
        ;
        after = '';
    }

    cb('<!doctype html><meta charset="utf-8">'
        + '

'
        + ''
        + before
        + scripts.map(function (s) {
            return ''
            ;
        }).join('\n')
        + ''
        + after
        + ''
    );
}
<|endoftext|>


<commit_before>//= require "../chrome/esc"

var $startingpoint = $('#startingpoint').click(function (event) {
  event.preventDefault();
  if (localStorage) {
    analytics.saveTemplate();
    localStorage.setItem('saved-javascript', editors.javascript.getCode());
    localStorage.setItem('saved-html', editors.html.getCode());
    $startingpoint.addClass('saved');
    $('#tip p').html('Default starting point now changed to current code');
    $html.addClass('showtip');
  }
  return false;
});

var $revert = $('#revert').click(function () {
  if ($revert.is(':not(.enable)')) {
    return false;
  }

  var key = '', i = 0;
  for (; i < sessionStorage.length; i++) {
    key = sessionStorage.key(i);
    if (key.indexOf('jsbin.content.') === 0) {
      sessionStorage.removeItem(key);
    }
  }

  for (key in editors) {
    editors[key].populateEditor();
  }

  analytics.revert();

  // editors.javascript.focus();
  $('#library').val('none');

  if (window.gist != undefined) {
    gist.setCode();
  }

  $document.trigger('codeChange', [ { revert: true } ]);

  return false;
});

$('#loginbtn').click(function () {
  analytics.login();
  $('#login').show();
  loginVisible = true;
  $username.focus();
  return false;
});

$('#logout').click(function (event) {
  analytics.logout();
  delete jsbin.settings.home;
  // delete cookie
  var date = new Date();
  date.setYear(1978);
  date.setTime(date.getTime()+(365*24*60*60*1000)); // set for a year
  document.cookie = 'key=""; expires=' + date.toGMTString() + '; path=/';
  document.cookie = 'home=""; expires=' + date.toGMTString() + '; path=/';

  window.location.reload();
  return false;
});

$('.homebtn').click(function () {
  analytics.open();
  jsbin.panels.hideAll();
  return false;
});

var dropdownOpen = false,
    onhover = false,
    menuDown = false;

function opendropdown(el) {
  if (!dropdownOpen) {
    $(el).closest('.menu').addClass('open');
    dropdownOpen = true;
  }
}

function closedropdown() {
  menuDown = false;
  if (dropdownOpen) {
    dropdownButtons.closest('.menu').removeClass('open');
    dropdownOpen = false;
    onhover = false;
  }
}

$body.mouseup(function () {
  closedropdown();
});

var dropdownButtons = $('.button-dropdown').mousedown(function (e) {
  $dropdownLinks.removeClass('hover');

  if (!dropdownOpen) {
    menuDown = true;
    opendropdown(this);
  }
  e.preventDefault();
  return false;
}).mouseup(function () {
  return false;
}).click(function () {
  if (!menuDown) {
    closedropdown();
  }
  menuDown = false;
  return false;
});

$('#actionmenu').click(function () {
  dropdownOpen = true;
});

$body.click(function (event) {
  if (dropdownOpen) {
    if (!$(event.target).closest('.menu').length) {
      closedropdown();
      return false;
    }
  }
});

var $dropdownLinks = $('.dropdownmenu a').mouseup(function () {
  closedropdown();
  $(this).click();
}).mouseover(function () {
  $dropdownLinks.removeClass('hover');
  $(this).addClass('hover');
});

$('#download').click(function () {
  analytics.download();
});

$('#runwithalerts').click(function () {
  renderLivePreview(true);
  return false;
});

$('#runconsole').click(function () {
  editors.console.render();
  return false;
});

$('#createnew').click(function () {
  var i, key;
  analytics.createNew();
  // FIXME this is out and out [cr]lazy....
  jsbin.panels.savecontent = function(){};
  for (i = 0; i < sessionStorage.length; i++) {
    key = sessionStorage.key(i);
    if (key.indexOf('jsbin.content.') === 0) {
      sessionStorage.removeItem(key);
    }
  }

  jsbin.panels.saveOnExit = true;

  // first try to restore their default panels
  jsbin.panels.restore();

  // if nothing was shown, show html & live
  setTimeout(function () {
    if (jsbin.panels.getVisible().length === 0) {
      jsbin.panels.panels.html.show();
      jsbin.panels.panels.live.show();
    }
  }, 0)
});

jsbin.settings.includejs = jsbin.settings.includejs || false;
$('#enablejs').change(function () {
  jsbin.settings.includejs = this.checked;
  analytics.enableLiveJS(jsbin.settings.includejs);
  editors.live.render();
}).attr('checked', jsbin.settings.includejs);

if (jsbin.settings.hideheader) {
  $body.addClass('hideheader');
}

(function () {

var re = {
  head: /<head(.*)\n/i,
  meta: /<meta name="description".*?>/i,
  metaContent: /content=".*?"/i
};

$('#addmeta').click(function () {
  // if not - insert
  // <meta name="description" content="" />
  // if meta description is in the HTML, highlight it
  var editor = jsbin.panels.panels.html,
      cm = editor.editor,
      html = editor.getCode();

  if (!re.meta.test(html)) {
    if (re.head.test(html)) {
      html = html.replace(re.head, '<head$1\n<meta name="description" content="" />\n');
    } else {
      // slap in the top
      html = '<meta name="description" content="" />\n' + html;
    }
  }

  editor.setCode(html);

  // now select the text
  // editor.editor is the CM object...yeah, sorry about that...
  var cursor = cm.getSearchCursor(re.meta);
  cursor.findNext();
  var mark = cm.markText(cursor.pos.from, cursor.pos.to, 'highlight');

  var contentCursor = cm.getSearchCursor(re.metaContent);
  contentCursor.findNext();

  cm.setCursor({ line: cursor.pos.from.line, ch: cursor.pos.from.ch + '<meta name="description" content="'.length });
  cm.setSelection({ line: cursor.pos.from.line, ch: cursor.pos.from.ch + '<meta name="description" content="'.length }, { line: contentCursor.pos.to.line, ch: contentCursor.pos.to.ch - 1 });
  cm.setOption('onCursorActivity', function () {
    cm.setOption('onCursorActivity', null);
    mark.clear();
  });
  cm.focus();

  return false;
});

// add navigation to insert meta data

}());

<commit_msg>Fixed double saving bug.<commit_after>//= require "../chrome/esc"

var $startingpoint = $('#startingpoint').click(function (event) {
  event.preventDefault();
  if (localStorage) {
    analytics.saveTemplate();
    localStorage.setItem('saved-javascript', editors.javascript.getCode());
    localStorage.setItem('saved-html', editors.html.getCode());
    $startingpoint.addClass('saved');
    $('#tip p').html('Default starting point now changed to current code');
    $html.addClass('showtip');
  }
  return false;
});

var $revert = $('#revert').click(function () {
  if ($revert.is(':not(.enable)')) {
    return false;
  }

  var key = '', i = 0;
  for (; i < sessionStorage.length; i++) {
    key = sessionStorage.key(i);
    if (key.indexOf('jsbin.content.') === 0) {
      sessionStorage.removeItem(key);
    }
  }

  for (key in editors) {
    editors[key].populateEditor();
  }

  analytics.revert();

  // editors.javascript.focus();
  $('#library').val('none');

  if (window.gist != undefined) {
    gist.setCode();
  }

  $document.trigger('codeChange', [ { revert: true } ]);

  return false;
});

$('#loginbtn').click(function () {
  analytics.login();
  $('#login').show();
  loginVisible = true;
  $username.focus();
  return false;
});

$('#logout').click(function (event) {
  analytics.logout();
  delete jsbin.settings.home;
  // delete cookie
  var date = new Date();
  date.setYear(1978);
  date.setTime(date.getTime()+(365*24*60*60*1000)); // set for a year
  document.cookie = 'key=""; expires=' + date.toGMTString() + '; path=/';
  document.cookie = 'home=""; expires=' + date.toGMTString() + '; path=/';

  window.location.reload();
  return false;
});

$('.homebtn').click(function () {
  analytics.open();
  jsbin.panels.hideAll();
  return false;
});

var dropdownOpen = false,
    onhover = false,
    menuDown = false;

function opendropdown(el) {
  if (!dropdownOpen) {
    $(el).closest('.menu').addClass('open');
    dropdownOpen = true;
  }
}

function closedropdown() {
  menuDown = false;
  if (dropdownOpen) {
    dropdownButtons.closest('.menu').removeClass('open');
    dropdownOpen = false;
    onhover = false;
  }
}

$body.mouseup(function () {
  closedropdown();
});

var dropdownButtons = $('.button-dropdown').mousedown(function (e) {
  $dropdownLinks.removeClass('hover');

  if (!dropdownOpen) {
    menuDown = true;
    opendropdown(this);
  }
  e.preventDefault();
  return false;
}).mouseup(function () {
  return false;
}).click(function () {
  if (!menuDown) {
    closedropdown();
  }
  menuDown = false;
  return false;
});

$('#actionmenu').click(function () {
  dropdownOpen = true;
});

$body.click(function (event) {
  if (dropdownOpen) {
    if (!$(event.target).closest('.menu').length) {
      closedropdown();
      return false;
    }
  }
});

var fromClick = false;
var $dropdownLinks = $('.dropdownmenu a').mouseup(function () {
  closedropdown();
  if (!fromClick) {
    $(this).click();
  }
  fromClick = false;
}).mouseover(function () {
  $dropdownLinks.removeClass('hover');
  $(this).addClass('hover');
}).mousedown(function () {
  fromClick = true;
});

$('#download').click(function () {
  analytics.download();
});

$('#runwithalerts').click(function () {
  renderLivePreview(true);
  return false;
});

$('#runconsole').click(function () {
  editors.console.render();
  return false;
});

$('#createnew').click(function () {
  var i, key;
  analytics.createNew();
  // FIXME this is out and out [cr]lazy....
  jsbin.panels.savecontent = function(){};
  for (i = 0; i < sessionStorage.length; i++) {
    key = sessionStorage.key(i);
    if (key.indexOf('jsbin.content.') === 0) {
      sessionStorage.removeItem(key);
    }
  }

  jsbin.panels.saveOnExit = true;

  // first try to restore their default panels
  jsbin.panels.restore();

  // if nothing was shown, show html & live
  setTimeout(function () {
    if (jsbin.panels.getVisible().length === 0) {
      jsbin.panels.panels.html.show();
      jsbin.panels.panels.live.show();
    }
  }, 0)
});

jsbin.settings.includejs = jsbin.settings.includejs || false;
$('#enablejs').change(function () {
  jsbin.settings.includejs = this.checked;
  analytics.enableLiveJS(jsbin.settings.includejs);
  editors.live.render();
}).attr('checked', jsbin.settings.includejs);

if (jsbin.settings.hideheader) {
  $body.addClass('hideheader');
}

(function () {

var re = {
  head: /<head(.*)\n/i,
  meta: /<meta name="description".*?>/i,
  metaContent: /content=".*?"/i
};

var metatag = '<meta name="description" content="[add your bin description]" />\n';

$('#addmeta').click(function () {
  // if not - insert
  // <meta name="description" content="" />
  // if meta description is in the HTML, highlight it
  var editor = jsbin.panels.panels.html,
      cm = editor.editor,
      html = editor.getCode();

  if (!re.meta.test(html)) {
    if (re.head.test(html)) {
      html = html.replace(re.head, '<head$1\n' + metatag);
    } else {
      // slap in the top
      html = metatag + html;
    }
  }

  editor.setCode(html);

  // now select the text
  // editor.editor is the CM object...yeah, sorry about that...
  var cursor = cm.getSearchCursor(re.meta);
  cursor.findNext();

  var contentCursor = cm.getSearchCursor(re.metaContent);
  contentCursor.findNext();

  var from = { line: cursor.pos.from.line, ch: cursor.pos.from.ch + '<meta name="description" content="'.length },
      to = { line: contentCursor.pos.to.line, ch: contentCursor.pos.to.ch - 1 };

  cm.setCursor(from);
  cm.setSelection(from, to);
  cm.setOption('onCursorActivity', function () {
    cm.setOption('onCursorActivity', null);
    mark.clear();
  });

  var mark = cm.markText(from, to, 'highlight');

  cm.focus();

  return false;
});

// add navigation to insert meta data

}());

<|endoftext|>


<commit_before>"use strict";

var Inflector = require('inflected');
var Cape = require('./utilities');

// Cape.CollectionAgent
//
// public properties:
//   resourceName: the name of resource
//   options: the object that holds option values given to the constructor
//   objects: the array of objects that represent the collection of resources
//   headers: the HTTP headers for Ajax requests
// options:
//   adapter: the name of adapter (e.g., 'rails'). Default is undefined.
//     Default value can be changed by setting Cape.defaultAgentAdapter property.
//   autoRefresh: a boolean value that controls unsafe Ajax requests trigger
//     this.refresh(). Default is true.
// private properties:
//   _: the object that holds internal methods and properties of this class.
var CollectionAgent = function CollectionAgent(resourceName, options) {
  var adapterName, adapter;

  this.resourceName = resourceName;
  this.options = options || {};
  if (this.options.autoRefresh === undefined) this.options.autoRefresh = true;
  this.objects = [];
  this.headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };
  this._ = new _Internal(this);

  adapterName = this.options.adapter || Cape.defaultAgentAdapter;
  if (typeof adapterName === 'string') {
    adapter = Cape.AgentAdapters[Inflector.camelize(adapterName) + 'Adapter'];
    if (typeof adapter === 'function') adapter.apply(this, arguments);
  }
};

CollectionAgent.create = function(resourceName, options) {
  this.instances = this.instances || {};
  var x = new this(resourceName, options)
  if (!this.instances[resourceName])
    this.instances[resourceName] = new this(resourceName, options);
  return this.instances[resourceName];
}

Cape.extend(CollectionAgent.prototype, {
  attach: function(component) {
    var target = component;
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) return;
    }
    this._.components.push(component);
  },

  detach: function(component) {
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) {
        this._.components.splice(i, 1);
        break;
      }
    }
  },

  propagate: function() {
    for (var i = this._.components.length; i--;)
      this._.components[i].refresh();
  },

  // Usually, this method should be overridden by child classes.
  refresh: function() {
    var self = this,
        paramName = Inflector.tableize(this.resourceName);

    this.index({}, function(data) {
      self.objects.length = 0;
      if (Array.isArray(data[paramName])) {
        for (var i = 0; i < data[paramName].length; i++) {
         self.objects.push(data[paramName][i]);
        }
      }
      self.propagate();
    })
  },

  index: function(params, callback, errorHandler) {
    this.get('', null, params, callback, errorHandler);
  },

  show: function(id, callback, errorHandler) {
    this.get('', id, {}, callback, errorHandler);
  },

  create: function(params, callback, errorHandler) {
    this.post('', null, params, callback, errorHandler);
  },

  update: function(id, params, callback, errorHandler) {
    this.patch('', id, params, callback, errorHandler);
  },

  destroy: function(id, callback, errorHandler) {
    this.delete('', id, {}, callback, errorHandler);
  },

  get: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('GET', path, params, callback, errorHandler);
  },

  post: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('POST', path, params, callback, errorHandler);
  },

  patch: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('PATCH', path, params, callback, errorHandler);
  },

  put: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('PUT', path, params, callback, errorHandler);
  },

  delete: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('DELETE', path, params, callback, errorHandler);
  },

  ajax: function(httpMethod, path, params, callback, errorHandler) {
    params = params || {};
    errorHandler = errorHandler || this.defaultErrorHandler;

    var self = this;
    var isSafeMethod = (httpMethod === 'GET' || httpMethod === 'HEAD');
    var fetchOptions = {
      method: httpMethod,
      headers: this.headers,
      credentials: 'same-origin'
    }

    if (isSafeMethod) {
      var pairs = [];
      for (var key in params) {
        pairs.push(encodeURIComponent(key) + "=" +
          encodeURIComponent(params[key]));
      }
      if (pairs.length) path = path + '?' + pairs.join('&');
    }
    else {
      fetchOptions.body = JSON.stringify(params)
    }
    fetch(path, fetchOptions)
      .then(function(response) {
        return response.json()
      })
      .then(function(data) {
        if (typeof callback === 'function') callback.call(self.client, data);
        if (self.options.autoRefresh && !isSafeMethod) self.refresh();
      })
      .catch(errorHandler);

    return false;
  },

  collectionPath: function() {
    var resources = Inflector.pluralize(Inflector.underscore(this.resourceName));
    return this.pathPrefix() + resources;
  },

  memberPath: function(id) {
    var resources = Inflector.pluralize(Inflector.underscore(this.resourceName));
    return this.pathPrefix() + resources + '/' + id;
  },

  pathPrefix: function() {
    return this.options.pathPrefix || '/';
  },

  defaultErrorHandler: function(ex) {
    console.log(ex)
  }
});

// Internal properties of Cape.CollectionAgent
var _Internal = function _Internal(main) {
  this.main = main;
  this.components = [];
}

module.exports = CollectionAgent;
<commit_msg>Add CollectionAgent#refreshObjects<commit_after>"use strict";

var Inflector = require('inflected');
var Cape = require('./utilities');

// Cape.CollectionAgent
//
// public properties:
//   resourceName: the name of resource
//   options: the object that holds option values given to the constructor
//   objects: the array of objects that represent the collection of resources
//   headers: the HTTP headers for Ajax requests
// options:
//   adapter: the name of adapter (e.g., 'rails'). Default is undefined.
//     Default value can be changed by setting Cape.defaultAgentAdapter property.
//   autoRefresh: a boolean value that controls unsafe Ajax requests trigger
//     this.refresh(). Default is true.
// private properties:
//   _: the object that holds internal methods and properties of this class.
var CollectionAgent = function CollectionAgent(resourceName, options) {
  var adapterName, adapter;

  this.resourceName = resourceName;
  this.options = options || {};
  if (this.options.autoRefresh === undefined) this.options.autoRefresh = true;
  this.objects = [];
  this.headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };
  this._ = new _Internal(this);

  adapterName = this.options.adapter || Cape.defaultAgentAdapter;
  if (typeof adapterName === 'string') {
    adapter = Cape.AgentAdapters[Inflector.camelize(adapterName) + 'Adapter'];
    if (typeof adapter === 'function') adapter.apply(this, arguments);
  }
};

CollectionAgent.create = function(resourceName, options) {
  this.instances = this.instances || {};
  var x = new this(resourceName, options)
  if (!this.instances[resourceName])
    this.instances[resourceName] = new this(resourceName, options);
  return this.instances[resourceName];
}

Cape.extend(CollectionAgent.prototype, {
  attach: function(component) {
    var target = component;
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) return;
    }
    this._.components.push(component);
  },

  detach: function(component) {
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) {
        this._.components.splice(i, 1);
        break;
      }
    }
  },

  propagate: function() {
    for (var i = this._.components.length; i--;)
      this._.components[i].refresh();
  },

  // Fetch current data through the API and refresh this.objects.
  //
  // The default implementation assumes that the request URI has no parameters and
  // the API returns a hash like this:
  //   { users: [ { id: 1, name: 'John' }, { id: 2, name: 'Kate' } ]}
  //
  // Otherwise, this method should be overridden in child classes. For example,
  //   refresh: function() {
  //     var self = this;
  //     var params = { page: this.currentPage, per_page: this.perPage };
  //     this.index(params, function(data) {
  //       self.refreshObjects(data, 'user_list');
  //       self.totalPage = data.total_page;
  //       self.propagate();
  //     })
  //   }
  refresh: function() {
    var self = this;
    this.index({}, function(data) {
      self.refreshObjects(data);
      self.propagate();
    })
  },

  refreshObjects: function(data, paramName) {
    paramName = paramName || Inflector.tableize(this.resourceName);

    this.objects.length = 0;
    if (Array.isArray(data[paramName])) {
      for (var i = 0; i < data[paramName].length; i++) {
       this.objects.push(data[paramName][i]);
      }
    }
  },

  index: function(params, callback, errorHandler) {
    this.get('', null, params, callback, errorHandler);
  },

  show: function(id, callback, errorHandler) {
    this.get('', id, {}, callback, errorHandler);
  },

  create: function(params, callback, errorHandler) {
    this.post('', null, params, callback, errorHandler);
  },

  update: function(id, params, callback, errorHandler) {
    this.patch('', id, params, callback, errorHandler);
  },

  destroy: function(id, callback, errorHandler) {
    this.delete('', id, {}, callback, errorHandler);
  },

  get: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('GET', path, params, callback, errorHandler);
  },

  post: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('POST', path, params, callback, errorHandler);
  },

  patch: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('PATCH', path, params, callback, errorHandler);
  },

  put: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('PUT', path, params, callback, errorHandler);
  },

  delete: function(actionName, id, params, callback, errorHandler) {
    var path = id ? this.memberPath(id) : this.collectionPath();
    if (actionName !== '') path = path + '/' + actionName;
    this.ajax('DELETE', path, params, callback, errorHandler);
  },

  ajax: function(httpMethod, path, params, callback, errorHandler) {
    params = params || {};
    errorHandler = errorHandler || this.defaultErrorHandler;

    var self = this;
    var isSafeMethod = (httpMethod === 'GET' || httpMethod === 'HEAD');
    var fetchOptions = {
      method: httpMethod,
      headers: this.headers,
      credentials: 'same-origin'
    }

    if (isSafeMethod) {
      var pairs = [];
      for (var key in params) {
        pairs.push(encodeURIComponent(key) + "=" +
          encodeURIComponent(params[key]));
      }
      if (pairs.length) path = path + '?' + pairs.join('&');
    }
    else {
      fetchOptions.body = JSON.stringify(params)
    }
    fetch(path, fetchOptions)
      .then(function(response) {
        return response.json()
      })
      .then(function(data) {
        if (typeof callback === 'function') callback.call(self.client, data);
        if (self.options.autoRefresh && !isSafeMethod) self.refresh();
      })
      .catch(errorHandler);

    return false;
  },

  collectionPath: function() {
    var resources = Inflector.pluralize(Inflector.underscore(this.resourceName));
    return this.pathPrefix() + resources;
  },

  memberPath: function(id) {
    var resources = Inflector.pluralize(Inflector.underscore(this.resourceName));
    return this.pathPrefix() + resources + '/' + id;
  },

  pathPrefix: function() {
    return this.options.pathPrefix || '/';
  },

  defaultErrorHandler: function(ex) {
    console.log(ex)
  }
});

// Internal properties of Cape.CollectionAgent
var _Internal = function _Internal(main) {
  this.main = main;
  this.components = [];
}

module.exports = CollectionAgent;
<|endoftext|>