<commit_before>var EventEmitter = require('emitter');
var inherits = require('inherit');
var EventManager = require('mage-event-manager.js');
var HttpServer = require('mage-http-server.js');
var MsgServer = require('mage-message-server.js');
var loader = require('mage-loader.js');

function Mage() {
	EventEmitter.call(this);

	this.eventManager = new EventManager();
	this.msgServer = new MsgServer(this.eventManager);
	this.httpServer = new HttpServer(this.eventManager);

	if (window.mageConfig) {
		this.configure(window.mageConfig);
	}

	var that = this;

	loader.on('density', function (density) {
		that.emit('densityChanged', density);
		that.density = density;
	});

	loader.on('language', function (language) {
		that.emit('languageChanged', language);
		that.language = language;
	});

	return this;
}

inherits(Mage, EventEmitter);

Mage.prototype.getClientHostBaseUrl = function () {
	return this.clientHostBaseUrl;
};

Mage.prototype.getSavvyBaseUrl = function (protocol) {
	var baseUrl = this.savvyBaseUrl;
	if (!baseUrl) {
		baseUrl = '/savvy';
	}

	if (baseUrl[0] === '/') {
		// location.origin is perfect for this, but badly supported

		baseUrl = this.savvyBaseUrl = window.location.protocol + '//' + window.location.host + baseUrl;

		console.warn('No savvy base URL configured, defaulting to:', baseUrl, '(which may not work)');
	}

	if (protocol) {
		// drop any trailing colons and slashes

		protocol = protocol.replace(/:?\/*$/, '');

		return baseUrl.replace(/^.*:\/\//, protocol + '://');
	}

	return baseUrl;
};

Mage.prototype.densities = function () {
	return loader.densities;
};

Mage.prototype.getDensity = function () {
	return loader.clientConfig.density;
};

Mage.prototype.setDensity = function (value) {
	loader.setDensity(value);
};

Mage.prototype.getLanguage = function () {
	return loader.clientConfig.language;
};

Mage.prototype.setLanguage = function (value) {
	loader.setLanguage(value);
};

Mage.prototype.getClientConfig = function () {
	return loader.clientConfig;
};

// expose configuration set up
// mage.configure registers the configuration and emits 'configure'

Mage.prototype.configure = function (config) {
	if (!config) {
		throw new Error('Mage requires a config to be instantiated.');
	}

	var that = this;

	this.config = config;

	this.appName = config.appName;
	this.appConfig = config.appConfig || {};
	this.appVersion = config.appVersion;
	this.appVariants = config.appVariants;
	this.clientHostBaseUrl = config.clientHostBaseUrl;
	this.savvyBaseUrl = config.savvyBaseUrl;
	this.language = loader.clientConfig.language;
	this.density = loader.clientConfig.density;

	// set up httpServer

	var httpWithCredentials = config.cors && config.cors.credentials ? true : false;

	this.httpServer.setupCommandSystem({
		url: config.clientHostBaseUrl + '/' + config.appName,
		httpOptions: {
			timeout: config.timeout || 15000,
			withCredentials: httpWithCredentials,
			noCache: true
		}
	});

	// set up msgServer
	// When a session key is available, start the message stream.
	// If the key changes, make the event system aware (by simply calling setupMessageStream again)

	if (!config.msgStreamUrl) {
		return;
	}

	var msgStreamConfig = {
		url: config.msgStreamUrl,
		httpOptions: {
			withCredentials: httpWithCredentials,
			noCache: true
		}
	};

	this.once('created.session', function () {
		that.eventManager.on('session.set', function (path, session) {
			that.msgServer.setupMessageStream(msgStreamConfig, session.key);
			that.msgServer.start();
		});

		that.eventManager.on('session.unset', function () {
			that.msgServer.abort();
		});
	});
};

Mage.prototype.isDevelopmentMode = function () {
	return this.config.developmentMode;
};

// And here comes the module system.

var setupQueue = [];
var modules = {};

function setupModule(mage, modName, cb) {
	var mod = modules[modName];

	if (!mod) {
		return cb();
	}

	if (!mod.hasOwnProperty('setup')) {
		mage.emit('setup.' + modName, mod);
		return cb();
	}

	mod.setup.call(mod, function (error) {
		if (error) {
			return cb(error);
		}

		mage.emit('setup.' + modName, mod);
		return cb();
	});
}

function setupModules(mage, modNames, cb) {
	var done = 0;
	var len = modNames.length;

	var lastError;

	function finalCb() {
		mage.emit('setupComplete');

		if (cb) {
			cb(lastError);
			cb = null;
		}
	}

	function stepCb(error) {
		lastError = error || lastError;
		done++;

		if (done === len) {
			finalCb();
		}
	}

	if (len === 0) {
		return finalCb();
	}

	for (var i = 0; i < len; i++) {
		setupModule(mage, modNames[i], stepCb);
	}
}

function createUserCommand(params, execPath) {
	// function arguments

	var args = params.concat('cb').join(', ');

	// function body

	var body = [];

	body.push('var httpServer = require(\'mage.js\').httpServer;');
	body.push('var params = {');

	for (var i = 0; i < params.length; i += 1) {
		body.push('\t' + params[i] + ': ' + params[i] + (i < params.length - 1 ? ',' : ''));
	}

	body.push('};');
	body.push('httpServer.sendCommand(' + JSON.stringify(execPath) + ', params, cb);\n');

	var functionBody = '\t' + body.join('\n\t');

	// instantiate and return the function

	/*jshint evil:true */
	return new Function(args, functionBody);
}

Mage.prototype.useModules = function () {
	var appRequire = arguments[0];

	if (typeof appRequire !== 'function') {
		throw new TypeError('useModules: the first argument must be require.');
	}

	var userCommands = this.config.userCommands;
	var execPaths = Object.keys(userCommands);

	for (var i = 1; i < arguments.length; i += 1) {
		var name = arguments[i];

		if (modules.hasOwnProperty(name)) {
			continue;
		}

		if (this[name]) {
			throw new Error('Failed to register module "' + name + '". This is a reserved name.');
		}

		// check if this module should exist
		// if not, we provide an empty object for user commands to be registered on

		var hasImplementation = false;

		var resolved = appRequire.resolve(name);
		if (resolved) {
			hasImplementation = !!window.require.resolve(resolved);
		}

		var mod = hasImplementation ? appRequire(name) : {};

		modules[name] = this[name] = mod;

		for (var j = 0; j < execPaths.length; j += 1) {
			var execPath = execPaths[j];
			var uc = userCommands[execPath];

			if (uc.gameModule === name) {
				hasImplementation = true;

				mod[uc.cmdName] = createUserCommand(uc.mod.params || [], execPath);
			}
		}

		if (!hasImplementation) {
			console.warn('Module "' + name + '" has no implementation.');
		}

		this.emit('created.' + name, mod);

		setupQueue.push(name);
	}

	return this;
};

Mage.prototype.setupModules = function (modNames, cb) {
	// remove all given module names from the current setupQueue

	var newSetupQueue = [];	// replacement array for setupQueue
	var toSetup = [];	// the modNames that we'll end up setting up

	for (var i = 0; i < setupQueue.length; i += 1) {
		var queuedModName = setupQueue[i];

		if (modNames.indexOf(queuedModName) === -1) {
			newSetupQueue.push(queuedModName);
		} else {
			toSetup.push(queuedModName);
		}
	}

	setupQueue = newSetupQueue;

	setupModules(this, toSetup, cb);
};

// expose the setup method, to be called after configure()
// mage.setup sets up all modules yet to be set up,
// after which it emits the event 'setup'

Mage.prototype.setup = function (cb) {
	this.setupModules(setupQueue, cb);
};

module.exports = new Mage();
<commit_msg>v0.1.0 - Initial Release<commit_after>var EventEmitter = require('emitter');
var inherits = require('inherit');
var EventManager = require('mage-event-manager.js');
var HttpServer = require('mage-http-server.js');
var MsgServer = require('mage-message-server.js');
var loader = require('mage-loader.js');

function Mage() {
	EventEmitter.call(this);

	this.eventManager = new EventManager();
	this.msgServer = new MsgServer(this.eventManager);
	this.httpServer = new HttpServer(this.eventManager);

	if (window.mageConfig) {
		this.configure(window.mageConfig);
	}

	var that = this;

	loader.on('density', function (density) {
		that.emit('densityChanged', density);
		that.density = density;
	});

	loader.on('language', function (language) {
		that.emit('languageChanged', language);
		that.language = language;
	});

	return this;
}

inherits(Mage, EventEmitter);

Mage.prototype.getClientHostBaseUrl = function () {
	return this.clientHostBaseUrl;
};

Mage.prototype.getSavvyBaseUrl = function (protocol) {
	var baseUrl = this.savvyBaseUrl;
	if (!baseUrl) {
		baseUrl = '/savvy';
	}

	if (baseUrl[0] === '/') {
		// location.origin is perfect for this, but badly supported

		baseUrl = this.savvyBaseUrl = window.location.protocol + '//' + window.location.host + baseUrl;

		console.warn('No savvy base URL configured, defaulting to:', baseUrl, '(which may not work)');
	}

	if (protocol) {
		// drop any trailing colons and slashes

		protocol = protocol.replace(/:?\/*$/, '');

		return baseUrl.replace(/^.*:\/\//, protocol + '://');
	}

	return baseUrl;
};

Mage.prototype.densities = function () {
	return loader.densities;
};

Mage.prototype.getDensity = function () {
	return loader.clientConfig.density;
};

Mage.prototype.setDensity = function (value) {
	loader.setDensity(value);
};

Mage.prototype.getLanguage = function () {
	return loader.clientConfig.language;
};

Mage.prototype.setLanguage = function (value) {
	loader.setLanguage(value);
};

Mage.prototype.getClientConfig = function () {
	return loader.clientConfig;
};

// expose configuration set up
// mage.configure registers the configuration and emits 'configure'

Mage.prototype.configure = function (config) {
	if (!config) {
		throw new Error('Mage requires a config to be instantiated.');
	}

	var that = this;

	this.config = config;

	this.appName = config.appName;
	this.appConfig = config.appConfig || {};
	this.appVersion = config.appVersion;
	this.appVariants = config.appVariants;
	this.clientHostBaseUrl = config.clientHostBaseUrl;
	this.savvyBaseUrl = config.savvyBaseUrl;
	this.language = loader.clientConfig.language;
	this.density = loader.clientConfig.density;

	// set up httpServer

	var httpWithCredentials = config.cors && config.cors.credentials ? true : false;

	this.httpServer.setupCommandSystem({
		url: config.clientHostBaseUrl + '/' + config.appName,
		httpOptions: {
			timeout: config.timeout || 15000,
			withCredentials: httpWithCredentials,
			noCache: true
		}
	});

	// set up msgServer
	// When a session key is available, start the message stream.
	// If the key changes, make the event system aware (by simply calling setupMessageStream again)

	if (!config.msgStreamUrl) {
		return;
	}

	var msgStreamConfig = {
		url: config.msgStreamUrl,
		httpOptions: {
			withCredentials: httpWithCredentials,
			noCache: true
		}
	};

	this.once('created.session', function () {
		that.eventManager.on('session.set', function (path, session) {
			that.msgServer.setupMessageStream(msgStreamConfig, session.key);
			that.msgServer.start();
		});

		that.eventManager.on('session.unset', function () {
			that.msgServer.abort();
		});
	});
};

Mage.prototype.isDevelopmentMode = function () {
	return this.config.developmentMode;
};

// And here comes the module system.

var setupQueue = [];
var modules = {};

function setupModule(mage, modName, cb) {
	var mod = modules[modName];

	if (!mod) {
		return cb();
	}

	if (!mod.hasOwnProperty('setup')) {
		mage.emit('setup.' + modName, mod);
		return cb();
	}

	mod.setup.call(mod, function (error) {
		if (error) {
			return cb(error);
		}

		mage.emit('setup.' + modName, mod);
		return cb();
	});
}

function setupModules(mage, modNames, cb) {
	var done = 0;
	var len = modNames.length;

	var lastError;

	function finalCb() {
		mage.emit('setupComplete');

		if (cb) {
			cb(lastError);
			cb = null;
		}
	}

	function stepCb(error) {
		lastError = error || lastError;
		done++;

		if (done === len) {
			finalCb();
		}
	}

	if (len === 0) {
		return finalCb();
	}

	for (var i = 0; i < len; i++) {
		setupModule(mage, modNames[i], stepCb);
	}
}

function createUserCommand(httpServer, modName, cmdName, params) {
	// function name (camelCase)

	var fnName = modName + cmdName[0].toUpperCase() + cmdName.slice(1);

	// function arguments

	params = params.concat('cb');

	var args = params.join(', ');

	// expected use

	var expected = modName + '.' + cmdName + '(' + args + ')';

	// real use

	/*jshint unused:false*/
	function serializeActualUse(args) {
		var result = [];

		for (var i = 0; i < args.length; i += 1) {
			var arg = args[i];

			if (typeof arg === 'function') {
				arg = 'Function';
			} else {
				arg = JSON.stringify(arg);
			}

			result.push(arg);
		}

		return modName + '.' + cmdName + '(' + result.join(', ') + ')';
	}

	// function body

	var body = [];

	body.push('fn = function ' + fnName + '(' + args + ') {');
	body.push('\tvar params = {');

	for (var i = 0; i < params.length; i += 1) {
		body.push('\t\t' + params[i] + ': ' + params[i] + (i < params.length - 1 ? ',' : ''));
	}

	body.push('\t};');
	body.push('');
	body.push('\ttry {');
	body.push('\t\thttpServer.sendCommand(' + JSON.stringify(modName + '.' + cmdName) + ', params, cb);');
	body.push('\t} catch (error) {');
	body.push('\t\tconsole.warn(' + JSON.stringify('Expected use: ' + expected) + ');');
	body.push('\t\tconsole.warn("Actual use: " + serializeActualUse(arguments));');
	body.push('\t\tthrow error;');
	body.push('\t};');
	body.push('};');

	body = body.join('\n');

	/*jshint evil:true */
	var fn;

	try {
		eval(body);
	} catch (e) {
		console.error('Error generating usercommand:', modName + '.' + cmdName);
		throw e;
	}

	return fn;
}

Mage.prototype.useModules = function () {
	var appRequire = arguments[0];

	if (typeof appRequire !== 'function') {
		throw new TypeError('useModules: the first argument must be require.');
	}

	var userCommands = this.config.userCommands;
	var commands = {};

	for (var name in userCommands) {
		var userCommand = userCommands[name];

		if (!commands[userCommand.gameModule]) {
			commands[userCommand.gameModule] = []
		}

		commands[userCommand.gameModule].push({ name: userCommand.cmdName, params: userCommand.mod.params });
	}

	for (var i = 1; i < arguments.length; i += 1) {
		var name = arguments[i];

		if (modules.hasOwnProperty(name)) {
			continue;
		}

		if (this[name]) {
			throw new Error('Failed to register module "' + name + '". This is a reserved name.');
		}

		// check if this module should exist
		// if not, we provide an empty object for user commands to be registered on

		var hasImplementation = false;

		var resolved = appRequire.resolve(name);
		if (resolved) {
			hasImplementation = !!window.require.resolve(resolved);
		}

		var mod = hasImplementation ? appRequire(name) : {};

		modules[name] = this[name] = mod;

		var modCommands = commands[name];

		if (modCommands && modCommands.length > 0) {
			hasImplementation = true;

			for (var j = 0; j < modCommands.length; j += 1) {
				var cmd = modCommands[j];

				mod[cmd.name] = createUserCommand(this.httpServer, name, cmd.name, cmd.params || []);
			}
		}

		if (!hasImplementation) {
			console.warn('Module "' + name + '" has no implementation.');
		}

		this.emit('created.' + name, mod);

		setupQueue.push(name);
	}

	return this;
};

Mage.prototype.setupModules = function (modNames, cb) {
	// remove all given module names from the current setupQueue

	var newSetupQueue = [];	// replacement array for setupQueue
	var toSetup = [];	// the modNames that we'll end up setting up

	for (var i = 0; i < setupQueue.length; i += 1) {
		var queuedModName = setupQueue[i];

		if (modNames.indexOf(queuedModName) === -1) {
			newSetupQueue.push(queuedModName);
		} else {
			toSetup.push(queuedModName);
		}
	}

	setupQueue = newSetupQueue;

	setupModules(this, toSetup, cb);
};

// expose the setup method, to be called after configure()
// mage.setup sets up all modules yet to be set up,
// after which it emits the event 'setup'

Mage.prototype.setup = function (cb) {
	this.setupModules(setupQueue, cb);
};

module.exports = new Mage();
<|endoftext|>


<commit_before>var d3 = require('d3');
var $ = require('jquery');
var gff = require('./gff3.js')

// margin is space between genomes and container
var margin = {top: 30, right: 30, bottom: 30, left: 30},
    width = 960 - margin.left - margin.right,
    height = 660 - margin.top - margin.bottom,
    genome_offset = 0,
    genome_height = 10,
    lcb_overflow = 10,
    longest = 0;

var set_genome_offset = function(num_genomes) {
    genome_offset = height/num_genomes;
};

var convert = function(length) {
    return length/longest * width;
};

var zoom = d3.zoom()
    .scaleExtent([1, 100])
    .on("zoom", zoomed);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("display", "block")
  .append("g")
    //.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);

// background
var rect = svg.append("rect")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("fill", "pink")
    .style("opacity", 0.4)
    .style("pointer-events", "all");

container = svg.append("g");

function zoomed() {
    tx = d3.event.transform;
    txf = "translate(" + tx.x + ") scale(" + tx.k + ",1"+ ")";
    container.attr("transform", txf);
}

// draw genomes as lines
var draw_genomes = function(data) {
    var genomes = container.selectAll("genomes")
                    .data(data)
                    .enter()
                        .append("rect")
                            .attr("width", function(d) {return d.length;})
                            .attr("height", genome_height)
                            .attr("x", margin.left)
                            .attr("y", function(d,i) {return margin.top + i*genome_offset})
                            .style("fill", "green");
};

// draw genome features for each genome
var draw_features = function(gff3, genomes, rows) {
    var compute_height = function(index) {
        for(var row in rows) {
            if (rows[row].indexOf(index) > -1) {
                return row*10;
            }
        }
    };

    function find_index(name) {
        for (var genome in genomes) {
            if (name == genomes[genome].name) {
                return genome;
            }
        }
    };
    var index = find_index(gff3[0].seqid);

    var genes = container.selectAll('gene' + index)
                    .data(gff3)
                    .enter()
                        .append("rect")
                            .attr("width", function(d, i) {return convert(d.end - d.start);})
                            .attr("height", 5)
                            .attr("x", function(d, i) {return margin.left + convert(d.start);})
                            .attr("y", function(d, i) {
                                return 45 + compute_height(i) + index*genome_offset;
                            })
                            .style("fill", "black");
};

function draw_lcbs(lcb, index, color) {
    var lcbs = container.selectAll('lcb' + index)
                    .data(lcb)
                    .enter()
                        .append("rect")
                            .attr("width", function(d, i) {return convert(d.end - d.start);})
                            .attr("height", genome_height+lcb_overflow)
                            .attr("x", function(d, i) {return margin.left + convert(d.start);})
                            .attr("y", function(d, i) {
                                return margin.top-(lcb_overflow/2) + (d.id - 1)*genome_offset;
                            })
                            .style("fill", color)
                            .style("opacity", 0.5);

    for (var i = 0; i < lcb.length-1; i++) {
        var l11x = (margin.left + lcb[i].start/longest*width).toString();
        var l11y = (margin.top+genome_height+(lcb_overflow/2) + (lcb[i].id - 1)*genome_offset).toString();
        var l12x = (margin.left + lcb[i].end/longest*width).toString();
        var l12y = (margin.top+genome_height+(lcb_overflow/2) + (lcb[i].id - 1)*genome_offset).toString();
        var l22x = (margin.left + lcb[i+1].end/longest*width).toString();
        var l22y = (margin.top-(lcb_overflow/2) + (lcb[i+1].id - 1)*genome_offset).toString();
        var l21x = (margin.left + lcb[i+1].start/longest*width).toString();
        var l21y = (margin.top-(lcb_overflow/2) + (lcb[i+1].id - 1)*genome_offset).toString();
        var l11 = l11x + ',' + l11y + ' ';
        var l12 = l12x + ',' + l12y + ' ';
        var l22 = l22x + ',' + l22y + ' ';
        var l21 = l21x + ',' + l21y;
        container.append("polygon")
                    .attr("points", l11+l12+l22+l21)
                    .style("fill", color)
                    .style("opacity", 0.5)
    }
};

//var bars = container.selectAll("rect")
            //.data(data)
            //.enter()
                //.append("rect")
                //.attr("width", 10)
                //.attr("height", 10)
                //.attr("x", function(d, i) {return i*12;})
                //.style("fill", function(nuc) {
                    //switch(nuc) {
                        //case "A":
                            //return "blue";
                        //case "T":
                            //return "red";
                        //case "G":
                            //return "yellow";
                        //case "C":
                            //return "green";
                    //}
                //});

// find genome with longest length
var find_longest = function(fasta) {
    return Math.max.apply(null, fasta.map(function(data) {
        return data.length;
    }));
}

// adjust pixels to genome length
var adjust_genomes = function(data) {
    adjusted_genomes = []
    $.each(data, function(key, fasta) {
        adjusted_genomes.push({name: fasta.name, length: convert(fasta.length)});
    });
    return adjusted_genomes;
};

// parse url
var parseQueryString = function(url) {
  var urlParams = {};
  url.replace(
    new RegExp("([^?=&]+)(=([^&]*))?", "g"),
    function($0, $1, $2, $3) {
      urlParams[$1] = $3;
    }
  );
  return urlParams;
}

// space genes out by putting them on different rows
var assign_rows = function(gff3) {
    last_placed = [null];
    var rows = {0:[]}
    gff3.map(function(gene, i) {
        for (locs in last_placed) {
            if (last_placed[locs] == null || convert(gene.start) > 1+last_placed[locs]) {
                if (last_placed[locs] == null) {
                    last_placed.push(null);
                    rows[parseInt(locs)+1] = [];
                }
                last_placed[locs] = convert(gene.end);
                rows[locs].push(i);
                return;
            }
        }
    });
    return rows;
};

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}

//get fasta, gff3, and xmfa data
$.getJSON(parseQueryString(location.search).url, function(json) {
    longest = find_longest(json.fasta);
    set_genome_offset(json.fasta.length);
    adjusted_genomes = adjust_genomes(json.fasta);
    draw_genomes(adjusted_genomes);

    var colors = ['red', 'blue', 'green', 'black'];
    $.getJSON(json.xmfa, function(xmfa) {
        xmfa.map(function(lcb, i) {
            draw_lcbs(lcb, i, colors[i]);
        });
    });

    for (var j in json.gff3) {
        $.get(json.gff3[j], function(gff3_data) {
            var gff3  = gff.process(gff3_data, ['CDS']);
            draw_features(gff3, adjusted_genomes, assign_rows(sortByKey(gff3, 'start')));
        });
    }
});
<commit_msg>genes height<commit_after>var d3 = require('d3');
var $ = require('jquery');
var gff = require('./gff3.js')

// margin is space between genomes and container
var margin = {top: 30, right: 30, bottom: 30, left: 30},
    width = 960 - margin.left - margin.right,
    height = 660 - margin.top - margin.bottom,
    genome_offset = 0,
    genes_offset = 5, // from lcb
    genome_height = 10,
    lcb_overflow = 10,
    longest = 0;

var set_genome_offset = function(num_genomes) {
    genome_offset = height/num_genomes;
};

var convert = function(length) {
    return length/longest * width;
};

var zoom = d3.zoom()
    .scaleExtent([1, 100])
    .on("zoom", zoomed);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("display", "block")
  .append("g")
    //.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);

// background
var rect = svg.append("rect")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("fill", "pink")
    .style("opacity", 0.4)
    .style("pointer-events", "all");

container = svg.append("g");

function zoomed() {
    tx = d3.event.transform;
    txf = "translate(" + tx.x + ") scale(" + tx.k + ",1"+ ")";
    container.attr("transform", txf);
}

// draw genomes as lines
var draw_genomes = function(data) {
    var genomes = container.selectAll("genomes")
                    .data(data)
                    .enter()
                        .append("rect")
                            .attr("width", function(d) {return d.length;})
                            .attr("height", genome_height)
                            .attr("x", margin.left)
                            .attr("y", function(d,i) {return margin.top + i*genome_offset})
                            .style("fill", "green");
};

// draw genome features for each genome
var draw_features = function(gff3, genomes, rows) {
    var compute_height = function(index) {
        for(var row in rows) {
            if (rows[row].indexOf(index) > -1) {
                return row*10;
            }
        }
    };

    function find_index(name) {
        for (var genome in genomes) {
            if (name == genomes[genome].name) {
                return genome;
            }
        }
    };
    var index = find_index(gff3[0].seqid);

    var genes = container.selectAll('gene' + index)
                    .data(gff3)
                    .enter()
                        .append("rect")
                            .attr("width", function(d, i) {return convert(d.end - d.start);})
                            .attr("height", 5)
                            .attr("x", function(d, i) {return margin.left + convert(d.start);})
                            .attr("y", function(d, i) {
                                return genes_offset + margin.top + genome_height + lcb_overflow/2 + compute_height(i) + index*genome_offset;
                            })
                            .style("fill", "black");
};

function draw_lcbs(lcb, index, color) {
    var lcbs = container.selectAll('lcb' + index)
                    .data(lcb)
                    .enter()
                        .append("rect")
                            .attr("width", function(d, i) {return convert(d.end - d.start);})
                            .attr("height", genome_height+lcb_overflow)
                            .attr("x", function(d, i) {return margin.left + convert(d.start);})
                            .attr("y", function(d, i) {
                                return margin.top-(lcb_overflow/2) + (d.id - 1)*genome_offset;
                            })
                            .style("fill", color)
                            .style("opacity", 0.5);

    for (var i = 0; i < lcb.length-1; i++) {
        var l11x = (margin.left + lcb[i].start/longest*width).toString();
        var l11y = (margin.top+genome_height+(lcb_overflow/2) + (lcb[i].id - 1)*genome_offset).toString();
        var l12x = (margin.left + lcb[i].end/longest*width).toString();
        var l12y = (margin.top+genome_height+(lcb_overflow/2) + (lcb[i].id - 1)*genome_offset).toString();
        var l22x = (margin.left + lcb[i+1].end/longest*width).toString();
        var l22y = (margin.top-(lcb_overflow/2) + (lcb[i+1].id - 1)*genome_offset).toString();
        var l21x = (margin.left + lcb[i+1].start/longest*width).toString();
        var l21y = (margin.top-(lcb_overflow/2) + (lcb[i+1].id - 1)*genome_offset).toString();
        var l11 = l11x + ',' + l11y + ' ';
        var l12 = l12x + ',' + l12y + ' ';
        var l22 = l22x + ',' + l22y + ' ';
        var l21 = l21x + ',' + l21y;
        container.append("polygon")
                    .attr("points", l11+l12+l22+l21)
                    .style("fill", color)
                    .style("opacity", 0.5)
    }
};

//var bars = container.selectAll("rect")
            //.data(data)
            //.enter()
                //.append("rect")
                //.attr("width", 10)
                //.attr("height", 10)
                //.attr("x", function(d, i) {return i*12;})
                //.style("fill", function(nuc) {
                    //switch(nuc) {
                        //case "A":
                            //return "blue";
                        //case "T":
                            //return "red";
                        //case "G":
                            //return "yellow";
                        //case "C":
                            //return "green";
                    //}
                //});

// find genome with longest length
var find_longest = function(fasta) {
    return Math.max.apply(null, fasta.map(function(data) {
        return data.length;
    }));
}

// adjust pixels to genome length
var adjust_genomes = function(data) {
    adjusted_genomes = []
    $.each(data, function(key, fasta) {
        adjusted_genomes.push({name: fasta.name, length: convert(fasta.length)});
    });
    return adjusted_genomes;
};

// parse url
var parseQueryString = function(url) {
  var urlParams = {};
  url.replace(
    new RegExp("([^?=&]+)(=([^&]*))?", "g"),
    function($0, $1, $2, $3) {
      urlParams[$1] = $3;
    }
  );
  return urlParams;
}

// space genes out by putting them on different rows
var assign_rows = function(gff3) {
    last_placed = [null];
    var rows = {0:[]}
    gff3.map(function(gene, i) {
        for (locs in last_placed) {
            if (last_placed[locs] == null || convert(gene.start) > 1+last_placed[locs]) {
                if (last_placed[locs] == null) {
                    last_placed.push(null);
                    rows[parseInt(locs)+1] = [];
                }
                last_placed[locs] = convert(gene.end);
                rows[locs].push(i);
                return;
            }
        }
    });
    return rows;
};

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}

//get fasta, gff3, and xmfa data
$.getJSON(parseQueryString(location.search).url, function(json) {
    longest = find_longest(json.fasta);
    set_genome_offset(json.fasta.length);
    adjusted_genomes = adjust_genomes(json.fasta);
    draw_genomes(adjusted_genomes);

    var colors = ['red', 'blue', 'green', 'black'];
    $.getJSON(json.xmfa, function(xmfa) {
        xmfa.map(function(lcb, i) {
            draw_lcbs(lcb, i, colors[i]);
        });
    });

    for (var j in json.gff3) {
        $.get(json.gff3[j], function(gff3_data) {
            var gff3  = gff.process(gff3_data, ['CDS']);
            draw_features(gff3, adjusted_genomes, assign_rows(sortByKey(gff3, 'start')));
        });
    }
});
<|endoftext|>


<commit_before>var HAProxy = require('haproxy');
var producer = require('godot-producer');

var RedisProducer = module.exports = producer(
  function constructor(options) {
    var self = this;
    self.haproxy = new HAProxy(options.haproxy);
  },
  function produce() {
    var self = this;

    self.haproxy.stat('-1', '-1', '-1', function (err, info) {
      info.forEach(function (section) {
        if (section.pxname === 'stats') {
          return;
        }

        var service = ['haproxy', section.pxname, section.svname].join('/');

        if (section.qcur) {
          self.emit('data', {
            service: service + '/queued-requests',
            description: 'Queued requests',
            metric: parseInt(section.qcur, 10)
          });
        }

        if (section.bin) {
          self.emit('data', {
            service: service + '/bytes-in',
            description: 'Bytes in',
            metric: parseInt(section.bin, 10)
          });
        }

        if (section.bout) {
          self.emit('data', {
            service: service + '/bytes-out',
            description: 'Bytes out',
            metric: parseInt(section.bout, 10)
          });
        }

        if (section.rate) {
          self.emit('data', {
            service: service + '/rate',
            description: 'Request rate',
            metric: parseInt(section.rate, 10)
          });
        }

        if (section.ereq) {
          self.emit('data', {
            service: service + '/request-errors',
            description: 'Request errors',
            metric: parseInt(section.ereq, 10)
          });
        }

        if (section.econ) {
          self.emit('data', {
            service: service + '/connection-errors',
            description: 'Connection errors',
            metric: parseInt(section.econ, 10)
          });
        }

        if (section.eresp) {
          self.emit('data', {
            service: service + '/response-errors',
            description: 'Response errors',
            metric: parseInt(section.eresp, 10)
          });
        }

        if (section.hrsp_1xx) {
          self.emit('data', {
            service: service + '/http-1xx',
            description: '1xx HTTP responses',
            metric: parseInt(section.hrsp_1xx, 10)
          });
        }

        if (section.hrsp_2xx) {
          self.emit('data', {
            service: service + '/http-2xx',
            description: '2xx HTTP responses',
            metric: parseInt(section.hrsp_2xx, 10)
          });
        }

        if (section.hrsp_3xx) {
          self.emit('data', {
            service: service + '/http-3xx',
            description: '3xx HTTP responses',
            metric: parseInt(section.hrsp_3xx, 10)
          });
        }

        if (section.hrsp_4xx) {
          self.emit('data', {
            service: service + '/http-4xx',
            description: '4xx HTTP responses',
            metric: parseInt(section.hrsp_4xx, 10)
          });
        }

        if (section.hrsp_5xx) {
          self.emit('data', {
            service: service + '/http-5xx',
            description: '5xx HTTP responses',
            metric: parseInt(section.hrsp_5xx, 10)
          });
        }
      });
    });
  }
);
<commit_msg>renamed RedisProducer to HAProxyProducer<commit_after>var HAProxy = require('haproxy');
var producer = require('godot-producer');

var HAProxyProducer = module.exports = producer(
  function constructor(options) {
    var self = this;
    self.haproxy = new HAProxy(options.haproxy);
  },
  function produce() {
    var self = this;

    self.haproxy.stat('-1', '-1', '-1', function (err, info) {
      info.forEach(function (section) {
        if (section.pxname === 'stats') {
          return;
        }

        var service = ['haproxy', section.pxname, section.svname].join('/');

        if (section.qcur) {
          self.emit('data', {
            service: service + '/queued-requests',
            description: 'Queued requests',
            metric: parseInt(section.qcur, 10)
          });
        }

        if (section.bin) {
          self.emit('data', {
            service: service + '/bytes-in',
            description: 'Bytes in',
            metric: parseInt(section.bin, 10)
          });
        }

        if (section.bout) {
          self.emit('data', {
            service: service + '/bytes-out',
            description: 'Bytes out',
            metric: parseInt(section.bout, 10)
          });
        }

        if (section.rate) {
          self.emit('data', {
            service: service + '/rate',
            description: 'Request rate',
            metric: parseInt(section.rate, 10)
          });
        }

        if (section.ereq) {
          self.emit('data', {
            service: service + '/request-errors',
            description: 'Request errors',
            metric: parseInt(section.ereq, 10)
          });
        }

        if (section.econ) {
          self.emit('data', {
            service: service + '/connection-errors',
            description: 'Connection errors',
            metric: parseInt(section.econ, 10)
          });
        }

        if (section.eresp) {
          self.emit('data', {
            service: service + '/response-errors',
            description: 'Response errors',
            metric: parseInt(section.eresp, 10)
          });
        }

        if (section.hrsp_1xx) {
          self.emit('data', {
            service: service + '/http-1xx',
            description: '1xx HTTP responses',
            metric: parseInt(section.hrsp_1xx, 10)
          });
        }

        if (section.hrsp_2xx) {
          self.emit('data', {
            service: service + '/http-2xx',
            description: '2xx HTTP responses',
            metric: parseInt(section.hrsp_2xx, 10)
          });
        }

        if (section.hrsp_3xx) {
          self.emit('data', {
            service: service + '/http-3xx',
            description: '3xx HTTP responses',
            metric: parseInt(section.hrsp_3xx, 10)
          });
        }

        if (section.hrsp_4xx) {
          self.emit('data', {
            service: service + '/http-4xx',
            description: '4xx HTTP responses',
            metric: parseInt(section.hrsp_4xx, 10)
          });
        }

        if (section.hrsp_5xx) {
          self.emit('data', {
            service: service + '/http-5xx',
            description: '5xx HTTP responses',
            metric: parseInt(section.hrsp_5xx, 10)
          });
        }
      });
    });
  }
);
<|endoftext|>


<commit_before>/*
  Copyright 2014, Marten de Vries

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*global XMLHttpRequest */

"use strict";

var Promise = require("pouchdb-promise");
var PouchPluginError = require("pouchdb-plugin-error");
var normalizeHeaderCase = require("header-case-normalizer");

if (typeof global.XMLHttpRequest === "undefined") {
  global.XMLHttpRequest = require("xhr2");
}

module.exports = function httpQuery(db, req) {
  return new Promise(function (resolve, reject) {
    function callback() {
      if (xhr.readyState !== 4) {
        return;
      }
      if (xhr.status < 200 || xhr.status >= 300) {
        var err = JSON.parse(xhr.responseText);
        reject(new PouchPluginError({
          "name": err.error,
          "message": err.reason,
          "status": xhr.status
        }));
        return;
      }

      var headers = {};
      xhr.getAllResponseHeaders().split("\r\n").forEach(function (line) {
        if (line) {
          var splittedHeader = line.split(":");
          headers[normalizeHeaderCase(splittedHeader[0]).trim()] = splittedHeader[1].trim();
        }
      });
      var result = {
        body: xhr.responseText,
        headers: headers,
        code: xhr.status
      };
      if (headers["content-type"] === "application/json") {
        result.json = JSON.parse(result.body);
      }
      resolve(result);
    }

    //strips the database from the requested_path
    var url = db.getUrl().split("/").slice(0, -2).join("/") + req.raw_path;

    var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;
    xhr.onreadystatechange = callback;
    xhr.open(req.method, url, true);
    for (var name in req.headers) {
      if (req.headers.hasOwnProperty(name)) {
        xhr.setRequestHeader(name, req.headers[name]);
      }
    }
    xhr.send(req.body === "undefined" ? null : req.body);
  });
};
<commit_msg>Improvements to replicator + auth; documentation translations<commit_after>/*
  Copyright 2014, Marten de Vries

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*global XMLHttpRequest */

"use strict";

var Promise = require("pouchdb-promise");
var PouchPluginError = require("pouchdb-plugin-error");
var normalizeHeaderCase = require("header-case-normalizer");

if (typeof global.XMLHttpRequest === "undefined") {
  global.XMLHttpRequest = require("xhr2"); //coverage: ignore
}

module.exports = function httpQuery(db, req) {
  return new Promise(function (resolve, reject) {
    function callback() {
      if (xhr.readyState !== 4) {
        return;
      }
      if (xhr.status < 200 || xhr.status >= 300) {
        var err = JSON.parse(xhr.responseText);
        reject(new PouchPluginError({
          "name": err.error,
          "message": err.reason,
          "status": xhr.status
        }));
        return;
      }

      var headers = {};
      xhr.getAllResponseHeaders().split("\r\n").forEach(function (line) {
        if (line) {
          var splittedHeader = line.split(":");
          headers[normalizeHeaderCase(splittedHeader[0]).trim()] = splittedHeader[1].trim();
        }
      });
      var result = {
        body: xhr.responseText,
        headers: headers,
        code: xhr.status
      };
      if (headers["content-type"] === "application/json") {
        result.json = JSON.parse(result.body);
      }
      resolve(result);
    }

    //strips the database from the requested_path
    var url = db.getUrl().split("/").slice(0, -2).join("/") + req.raw_path;

    var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;
    xhr.onreadystatechange = callback;
    xhr.open(req.method, url, true);
    for (var name in req.headers) {
      if (req.headers.hasOwnProperty(name)) {
        xhr.setRequestHeader(name, req.headers[name]);
      }
    }
    xhr.send(req.body === "undefined" ? null : req.body);
  });
};
<|endoftext|>


<commit_before>/*jslint node: true */
/* global -Promise */
"use strict";

var _ = require('lodash');
var Promise = require('bluebird');

var eventTree = function () {
    return {
        hash: {}
        , funcs: []
    };
};

var chainExecutions = function () {
    var ps = _.toArray(arguments);

    var execution = Promise.reduce(ps, function (called, p) {
        var result = p();
        if (result.isPending()) {
            return result.then(function (fcalled) {
                return called || fcalled;
            });
        }
        else {
            if (result.isRejected()) {
                return result;
            }
            else {
                return Promise.resolve(called || result.value());
            }
        }
    }, false);
    return execution;
};

var addCallback = function (route, tree, cb) {
    var head = _.head(route);
    if (!tree.hash.hasOwnProperty(head)) {
        tree.hash[head] = eventTree();
    }

    if (route.length > 1) {
        return addCallback(_.rest(route), tree.hash[head], cb);
    }
    else if (route.length === 1) {
        tree.hash[head].funcs.push(cb);
    }
};

var execTree = function (tree, msg) {
    if (!tree || (tree.funcs.length === 0)) {
        return Promise.resolve(false);
    }
    var funcs = tree.funcs;
    var execution = Promise.reduce(funcs, function (called, f) {
        return f(msg);
    }, false);
    if (execution.isPending()) {
        return execution.then(true);
    }
    else {
        if (execution.isRejected()) {
            return execution;
        }
        else {
            return Promise.resolve(true);
        }
    }
};

var applySubTrees = function (tree, method) {
    return Promise.map(_.pairs(tree.hash)
                       , function (kv) {
                           if (kv[0] === '**') {
                               return false;
                           }
                           else {
                               return method(kv[1]);
                           }
                       }, {concurrency: 1});
};

var execAll = function (tree, msg) {
    return chainExecutions(
        function () {
            return execTree(tree, msg);
        }
        , function () {
            return applySubTrees(tree, function (subtree) {
                return execAll(subtree, msg);
            });
        }
    );
};

var execMatch = function (target, tree, msg) {
    if (!tree) {
        return Promise.resolve(false);
    }
    var targetTree = tree.hash.hasOwnProperty(target) && tree.hash[target];
    if (!targetTree) {
        return Promise.resolve(false);
    }
    var doubleStarTree = targetTree.hash['**'];
    return Promise.join(execTree(targetTree, msg)
                        , execTree(doubleStarTree, msg))
        .then(_.any);
};

var noExecution = function () {
    return Promise.resolve(false);
};

var execCallbacks = function (route, tree, msg) {
    if (!tree) {
        return noExecution();
    }
    var head = _.head(route);
    if (head === '**') {
        return execAll(tree, msg);
    }
    else if (route.length > 1) {
        var rest = _.rest(route);
        if (head === '*') {
            return applySubTrees(tree, function (subtree) {
                return Promise.join(execTree(subtree.hash['**'], msg)
                                    , execCallbacks(rest, subtree, msg))
                    .then(_.any);
            });
        }
        else {
            var matchTree = tree.hash.hasOwnProperty(head) && tree.hash[head];
            return chainExecutions(function () {
                return execTree(tree.hash['*'] && tree.hash['*'].hash['**'], msg);
            }, function () {
                return execTree(matchTree && matchTree.hash['**'], msg);
            }, function () {
                return execCallbacks(rest, tree.hash['*'], msg);
            }, function () {
                return execCallbacks(rest, matchTree, msg);
            });
        }
    }
    else if (route.length === 1) {
        if (head === '*') {
            return applySubTrees(tree, function (subtree) {
                return execTree(subtree, msg);
            })
                .then(_.any);
        }
        else {
            return chainExecutions(function () {
                return execMatch('*', tree, msg);
            }, function () {
                return execMatch(head, tree, msg);
            });
        }
    }
    else {
        return noExecution();
    }
};

var filterFuncs = function (funcs, f) {
    if (f) {
        return _.filter(funcs, function (func) {
            return func.listener !== f;
        });
    }
    else {
        return [];
    }
};

var emptyTree = function (tree) {
    return tree.funcs.length === 0
        && _.isEmpty(tree.hash);
};

var deleteIfEmpty = function (target, hash) {
    if (emptyTree(hash[target])) {
        delete hash[target];
    }
};

var removeFunc = function (tree, f) {
    tree.funcs = filterFuncs(tree.funcs, f);
};

var removeCallback = function (route, tree, f) {
    var head = _.head(route);
    if (route.length > 1) {
        var rest = _.rest(route);
        if (head === '*') {
            return _.each(tree.hash, function (subtree, subhead) {
                if (subhead !== '**') {
                    removeCallback(rest, subtree, f);
                    deleteIfEmpty(subhead, tree.hash);
                }
            });
        }
        else if (tree.hash.hasOwnProperty(head)) {
            removeCallback(_.rest(route), tree.hash[head], f);
            deleteIfEmpty(head, tree.hash);
        }
    }
    else if (route.length === 1) {
        if (head === '**')  {
            removeFunc(tree, f);
            _.each(tree.hash, function (subtree, subhead) {
                removeCallback(route, subtree, f);
                deleteIfEmpty(subhead, tree.hash);
            });
        }
        if (head === '*') {
            _.each(tree.hash, function (subtree, subhead) {
                removeFunc(subtree, f);
                deleteIfEmpty(subhead, tree.hash);
            });
        }
        else if (tree.hash.hasOwnProperty(head)) {
            removeFunc(tree.hash[head], f);
            deleteIfEmpty(head, tree.hash);
        }
    }
};

var adaptCallback = function (cb) {
    var f;
    if (cb.length === 2) {
        f = function (msg) {
            return new Promise(function (resolve, reject) {
                return cb(msg, function (abort) {
                    if (abort) {
                        reject({
                            message: abort
                        });
                    }
                    else {
                        resolve(true);
                    }
                });
            });
        };
    }
    else {
        f = function (msg) {
            cb(msg);
            return Promise.resolve(true);
        };
    }
    f.listener = cb.listener || cb;
    return f;
};

var allSubListeners = function (eventTree) {
    var hash = eventTree.hash;
    var starListeners = [];
    var funcs = _.map(eventTree.hash, function (subtree, key) {
        if (key === '**') {
            starListeners = subtree.funcs.concat(starListeners);
            return [];
        }
        else if (key === '*') {
            starListeners = starListeners.concat(allSubListeners(subtree));
            return [];
        } else {
            return subtree.funcs.concat(allSubListeners(subtree));
        }
    });
    return [].concat.apply(starListeners, funcs);
};

var listenerFuncs = function (funcs) {
    return _.map(funcs, function (f) {
        return f.listener || f;
    });
};

var listeners = function (route, eventTree) {
    var head = _.head(route);
    if (head === '**') {
        return allSubListeners(eventTree);
    } else {
        if (route.length > 1) {
            var hash = eventTree.hash;
            var rest = _.rest(route);
            if (head === '*') {
                var starListeners = [];
                var funcs = [].concat.apply([], _.map(hash, function (subtree, key) {
                    if (key === '*') {
                        starListeners = listeners(rest, subtree).concat(starListeners);
                        return [];
                    } if (key == '**') {
                        starListeners = subtree.funcs.concat(starListeners);
                        return [];
                    } else {
                        return listeners(rest, subtree);
                    }
                }));
                return [].concat.apply(starListeners, funcs);
            } else {
                console.log('route two ', head, ' in ', route);
                var starListeners = [];
                if (hash.hasOwnProperty('**')) {
                    starListeners = hash['**'].funcs;
                }
                if (hash.hasOwnProperty('*')) {
                    starListeners = starListeners.concat(listeners(rest, hash['*']));
                }
                if (hash.hasOwnProperty(head)) {
                    console.log('matching subroute match of ', head, listeners(rest, hash[head]), hash[head]);
                    return starListeners.concat(listeners(rest, hash[head]));
                }
                else {
                    console.log('no exact match ', starListeners);
                    return starListeners;
                }
            }
        } else {
            var hash = eventTree.hash;
            if (head === '*') {
                var starListeners = [];
                var funcs = [].concat.apply([], _.map(hash, function (subtree, key) {
                    if (key === '*') {
                        starListeners = subtree.funcs.concat(starListeners);
                        return [];
                    } if (key == '**') {
                        starListeners = starListeners.concat(subtree.funcs);
                        return [];
                    } else {
                        return subtree.funcs;
                    }
                }));
                return [].concat.apply(starListeners, funcs);
            } else {
                var hash = eventTree.hash;
                var starListeners = [];
                if (hash.hasOwnProperty('**')) {
                    starListeners = hash['**'].funcs;
                }
                if (hash.hasOwnProperty('*')) {
                    starListeners = starListeners.concat(hash['*'].funcs);
                }
                if (hash.hasOwnProperty(head)) {
                    return starListeners.concat(hash[head].funcs);
                } else {
                    return starListeners;
                }
            }
        }
    }
};

var emit = function (eventTree, route, msg) {
    return chainExecutions(
        function () {
            return execTree(eventTree.hash['**'], msg);
        }
        , function () {
            return execCallbacks(route, eventTree, msg);
        });
};

var list = function (eventTree, parent) {
    var l = [];
    if (eventTree.funcs.length > 0) {
        l = [parent.join('/')];
    }
    return [].concat.apply(l, _.map(eventTree.hash, function (subtree, name) {
        return list(subtree, parent.concat(name));
    }));
};

var EventEmitter = function (options) {
    options = _.defaults({}, options, {
        delimiter: '/'
    });
    this._eventTree = eventTree();
    this._newListenerTree = eventTree();
    this._errorTree = eventTree();
    this.delimiter = options.delimiter;
};

_.extend(EventEmitter.prototype, {
    parseRoute: function (route) {
        if (_.isString(route))  {
            route = route.split(this.delimiter);
        }
        return route;
    }
    , on: function (route, cb) {
        route = this.parseRoute(route);
        if (route.length === 1
            && (route[0] === 'newListener'
                || route[0] === 'error')) {
            route = route.concat('**');
        }
        emit(this._newListenerTree, route, {
            event: route
            , listener: cb
        });
        if (route[0] === 'newListener') {
            addCallback(route.slice(1), this._newListenerTree, cb);
        }
        else if (route[0] === 'error') {
            addCallback(route.slice(1), this._errorTree, cb);
        }
        else {
            addCallback(route, this._eventTree, cb);
        }
    }
    , emit: function (route, msg) {
        var _this = this;
        route = this.parseRoute(route);
        if (route[0] === 'newListener') {
            return emit(_this.newListenerTree, route.slice(1), msg);
        }
        else if (route[0] === 'error') {
            return emit(_this._errorTree, route.slice(1), msg)
            .then(function (called) {
                if (!called) {
                    if (msg instanceof Error) {
                        throw msg; // Unhandled 'error' event
                    }
                    else {
                        throw new Error('Uncaught unspecified error event.');
                    }
                }
                return true;
            });
        }
        else {
            return emit(_this._eventTree, route, msg);
        }
    }
    , removeListener: function (route, f) {
        route = this.parseRoute(route);
        removeCallback(route, this._eventTree, f);
    }
    , once: function (route, cb) {
        route = this.parseRoute(route);
        var _this = this;
        var f = adaptCallback(cb);
        var g = function (msg) {
            _this.removeListener(route, cb);
            return f(msg);
        };
        g.listener = cb;
        emit(this._newListenerTree, route, {
            event: route
            , listener: cb
        });
        return addCallback(route, this._eventTree, g);
    }
    , removeAllListeners: function (route) {
        route = this.parseRoute(route);
        if (route[0] === '**') {
            this._eventTree = eventTree();
        }
        else {
            removeCallback(route, this._eventTree);
        }
    }
    , listeners: function (route) {
        route = this.parseRoute(route);
        return listeners(route, this._eventTree);
    }
    , list: function () {
        return list(this._eventTree, []);
    }
});

module.exports = {
    EventEmitter: EventEmitter
};
<commit_msg>Fix sublisteners on *.<commit_after>/*jslint node: true */
/* global -Promise */
"use strict";

var _ = require('lodash');
var Promise = require('bluebird');

var eventTree = function () {
    return {
        hash: {}
        , funcs: []
    };
};

var chainExecutions = function () {
    var ps = _.toArray(arguments);

    var execution = Promise.reduce(ps, function (called, p) {
        var result = p();
        if (result.isPending()) {
            return result.then(function (fcalled) {
                return called || fcalled;
            });
        }
        else {
            if (result.isRejected()) {
                return result;
            }
            else {
                return Promise.resolve(called || result.value());
            }
        }
    }, false);
    return execution;
};

var addCallback = function (route, tree, cb) {
    var head = _.head(route);
    if (!tree.hash.hasOwnProperty(head)) {
        tree.hash[head] = eventTree();
    }

    if (route.length > 1) {
        return addCallback(_.rest(route), tree.hash[head], cb);
    }
    else if (route.length === 1) {
        tree.hash[head].funcs.push(cb);
    }
};

var execTree = function (tree, msg) {
    if (!tree || (tree.funcs.length === 0)) {
        return Promise.resolve(false);
    }
    var funcs = tree.funcs;
    var execution = Promise.reduce(funcs, function (called, f) {
        return f(msg);
    }, false);
    if (execution.isPending()) {
        return execution.then(true);
    }
    else {
        if (execution.isRejected()) {
            return execution;
        }
        else {
            return Promise.resolve(true);
        }
    }
};

var applySubTrees = function (tree, method) {
    return Promise.map(_.pairs(tree.hash)
                       , function (kv) {
                           if (kv[0] === '**') {
                               return false;
                           }
                           else {
                               return method(kv[1]);
                           }
                       }, {concurrency: 1});
};

var execAll = function (tree, msg) {
    return chainExecutions(
        function () {
            return execTree(tree, msg);
        }
        , function () {
            return applySubTrees(tree, function (subtree) {
                return execAll(subtree, msg);
            });
        }
    );
};

var execMatch = function (target, tree, msg) {
    if (!tree) {
        return Promise.resolve(false);
    }
    var targetTree = tree.hash.hasOwnProperty(target) && tree.hash[target];
    if (!targetTree) {
        return Promise.resolve(false);
    }
    var doubleStarTree = targetTree.hash['**'];
    return Promise.join(execTree(targetTree, msg)
                        , execTree(doubleStarTree, msg))
        .then(_.any);
};

var noExecution = function () {
    return Promise.resolve(false);
};

var execCallbacks = function (route, tree, msg) {
    if (!tree) {
        return noExecution();
    }
    var head = _.head(route);
    if (head === '**') {
        return execAll(tree, msg);
    }
    else if (route.length > 1) {
        var rest = _.rest(route);
        if (head === '*') {
            return applySubTrees(tree, function (subtree) {
                return Promise.join(execTree(subtree.hash['**'], msg)
                                    , execCallbacks(rest, subtree, msg))
                    .then(_.any);
            });
        }
        else {
            var matchTree = tree.hash.hasOwnProperty(head) && tree.hash[head];
            return chainExecutions(function () {
                return execTree(tree.hash['*'] && tree.hash['*'].hash['**'], msg);
            }, function () {
                return execTree(matchTree && matchTree.hash['**'], msg);
            }, function () {
                return execCallbacks(rest, tree.hash['*'], msg);
            }, function () {
                return execCallbacks(rest, matchTree, msg);
            });
        }
    }
    else if (route.length === 1) {
        if (head === '*') {
            return applySubTrees(tree, function (subtree) {
                return execTree(subtree, msg);
            })
                .then(_.any);
        }
        else {
            return chainExecutions(function () {
                return execMatch('*', tree, msg);
            }, function () {
                return execMatch(head, tree, msg);
            });
        }
    }
    else {
        return noExecution();
    }
};

var filterFuncs = function (funcs, f) {
    if (f) {
        return _.filter(funcs, function (func) {
            return func.listener !== f;
        });
    }
    else {
        return [];
    }
};

var emptyTree = function (tree) {
    return tree.funcs.length === 0
        && _.isEmpty(tree.hash);
};

var deleteIfEmpty = function (target, hash) {
    if (emptyTree(hash[target])) {
        delete hash[target];
    }
};

var removeFunc = function (tree, f) {
    tree.funcs = filterFuncs(tree.funcs, f);
};

var removeCallback = function (route, tree, f) {
    var head = _.head(route);
    if (route.length > 1) {
        var rest = _.rest(route);
        if (head === '*') {
            return _.each(tree.hash, function (subtree, subhead) {
                if (subhead !== '**') {
                    removeCallback(rest, subtree, f);
                    deleteIfEmpty(subhead, tree.hash);
                }
            });
        }
        else if (tree.hash.hasOwnProperty(head)) {
            removeCallback(_.rest(route), tree.hash[head], f);
            deleteIfEmpty(head, tree.hash);
        }
    }
    else if (route.length === 1) {
        if (head === '**')  {
            removeFunc(tree, f);
            _.each(tree.hash, function (subtree, subhead) {
                removeCallback(route, subtree, f);
                deleteIfEmpty(subhead, tree.hash);
            });
        }
        if (head === '*') {
            _.each(tree.hash, function (subtree, subhead) {
                removeFunc(subtree, f);
                deleteIfEmpty(subhead, tree.hash);
            });
        }
        else if (tree.hash.hasOwnProperty(head)) {
            removeFunc(tree.hash[head], f);
            deleteIfEmpty(head, tree.hash);
        }
    }
};

var adaptCallback = function (cb) {
    var f;
    if (cb.length === 2) {
        f = function (msg) {
            return new Promise(function (resolve, reject) {
                return cb(msg, function (abort) {
                    if (abort) {
                        reject({
                            message: abort
                        });
                    }
                    else {
                        resolve(true);
                    }
                });
            });
        };
    }
    else {
        f = function (msg) {
            cb(msg);
            return Promise.resolve(true);
        };
    }
    f.listener = cb.listener || cb;
    return f;
};

var allSubListeners = function (eventTree) {
    var hash = eventTree.hash;
    var starListeners = [];
    var funcs = _.map(eventTree.hash, function (subtree, key) {
        if (key === '**') {
            starListeners = subtree.funcs.concat(starListeners);
            return [];
        }
        else if (key === '*') {
            starListeners = starListeners.concat(subtree.funcs.concat(allSubListeners(subtree)));
            return [];
        } else {
            return subtree.funcs.concat(allSubListeners(subtree));
        }
    });
    return [].concat.apply(starListeners, funcs);
};

var listenerFuncs = function (funcs) {
    return _.map(funcs, function (f) {
        return f.listener || f;
    });
};

var listeners = function (route, eventTree) {
    var head = _.head(route);
    if (head === '**') {
        return allSubListeners(eventTree);
    } else {
        if (route.length > 1) {
            var hash = eventTree.hash;
            var rest = _.rest(route);
            if (head === '*') {
                var starListeners = [];
                var funcs = [].concat.apply([], _.map(hash, function (subtree, key) {
                    if (key === '*') {
                        starListeners = listeners(rest, subtree).concat(starListeners);
                        return [];
                    } if (key == '**') {
                        starListeners = subtree.funcs.concat(starListeners);
                        return [];
                    } else {
                        return listeners(rest, subtree);
                    }
                }));
                return [].concat.apply(starListeners, funcs);
            } else {
                var starListeners = [];
                if (hash.hasOwnProperty('**')) {
                    starListeners = hash['**'].funcs;
                }
                if (hash.hasOwnProperty('*')) {
                    starListeners = starListeners.concat(listeners(rest, hash['*']));
                }
                if (hash.hasOwnProperty(head)) {
                    return starListeners.concat(listeners(rest, hash[head]));
                }
                else {
                    return starListeners;
                }
            }
        } else {
            var hash = eventTree.hash;
            if (head === '*') {
                var starListeners = [];
                var funcs = [].concat.apply([], _.map(hash, function (subtree, key) {
                    if (key === '*') {
                        starListeners = subtree.funcs.concat(starListeners);
                        return [];
                    } if (key == '**') {
                        starListeners = starListeners.concat(subtree.funcs);
                        return [];
                    } else {
                        return subtree.funcs;
                    }
                }));
                return [].concat.apply(starListeners, funcs);
            } else {
                var hash = eventTree.hash;
                var starListeners = [];
                if (hash.hasOwnProperty('**')) {
                    starListeners = hash['**'].funcs;
                }
                if (hash.hasOwnProperty('*')) {
                    starListeners = starListeners.concat(hash['*'].funcs);
                }
                if (hash.hasOwnProperty(head)) {
                    return starListeners.concat(hash[head].funcs);
                } else {
                    return starListeners;
                }
            }
        }
    }
};

var emit = function (eventTree, route, msg) {
    return chainExecutions(
        function () {
            return execTree(eventTree.hash['**'], msg);
        }
        , function () {
            return execCallbacks(route, eventTree, msg);
        });
};

var list = function (eventTree, parent) {
    var l = [];
    if (eventTree.funcs.length > 0) {
        l = [parent.join('/')];
    }
    return [].concat.apply(l, _.map(eventTree.hash, function (subtree, name) {
        return list(subtree, parent.concat(name));
    }));
};

var EventEmitter = function (options) {
    options = _.defaults({}, options, {
        delimiter: '/'
    });
    this._eventTree = eventTree();
    this._newListenerTree = eventTree();
    this._errorTree = eventTree();
    this.delimiter = options.delimiter;
};

_.extend(EventEmitter.prototype, {
    parseRoute: function (route) {
        if (_.isString(route))  {
            route = route.split(this.delimiter);
        }
        return route;
    }
    , on: function (route, cb) {
        route = this.parseRoute(route);
        if (route.length === 1
            && (route[0] === 'newListener'
                || route[0] === 'error')) {
            route = route.concat('**');
        }
        emit(this._newListenerTree, route, {
            event: route
            , listener: cb
        });
        if (route[0] === 'newListener') {
            addCallback(route.slice(1), this._newListenerTree, cb);
        }
        else if (route[0] === 'error') {
            addCallback(route.slice(1), this._errorTree, cb);
        }
        else {
            addCallback(route, this._eventTree, cb);
        }
    }
    , emit: function (route, msg) {
        var _this = this;
        route = this.parseRoute(route);
        if (route[0] === 'newListener') {
            return emit(_this.newListenerTree, route.slice(1), msg);
        }
        else if (route[0] === 'error') {
            return emit(_this._errorTree, route.slice(1), msg)
            .then(function (called) {
                if (!called) {
                    if (msg instanceof Error) {
                        throw msg; // Unhandled 'error' event
                    }
                    else {
                        throw new Error('Uncaught unspecified error event.');
                    }
                }
                return true;
            });
        }
        else {
            return emit(_this._eventTree, route, msg);
        }
    }
    , removeListener: function (route, f) {
        route = this.parseRoute(route);
        removeCallback(route, this._eventTree, f);
    }
    , once: function (route, cb) {
        route = this.parseRoute(route);
        var _this = this;
        var f = adaptCallback(cb);
        var g = function (msg) {
            _this.removeListener(route, cb);
            return f(msg);
        };
        g.listener = cb;
        emit(this._newListenerTree, route, {
            event: route
            , listener: cb
        });
        return addCallback(route, this._eventTree, g);
    }
    , removeAllListeners: function (route) {
        route = this.parseRoute(route);
        if (route[0] === '**') {
            this._eventTree = eventTree();
        }
        else {
            removeCallback(route, this._eventTree);
        }
    }
    , listeners: function (route) {
        route = this.parseRoute(route);
        return listeners(route, this._eventTree);
    }
    , list: function () {
        return list(this._eventTree, []);
    }
});

module.exports = {
    EventEmitter: EventEmitter
};
<|endoftext|>


<commit_before>
module.exports = function(css){

  /**
   * Parse stylesheet.
   */

  function stylesheet() {
    return {
      type: 'stylesheet',
      stylesheet: {
        rules: rules()
      }
    };
  }

  /**
   * Opening brace.
   */

  function open() {
    return match(/^{\s*/);
  }

  /**
   * Closing brace.
   */

  function close() {
    return match(/^}\s*/);
  }

  /**
   * Parse ruleset.
   */

  function rules() {
    var node;
    var rules = [];
    whitespace();
    comments(rules);
    while (css[0] != '}' && (node = atrule() || rule())) {
      rules.push(node);
      comments(rules);
    }
    return rules;
  }

  /**
   * Match `re` and return captures.
   */

  function match(re) {
    var m = re.exec(css);
    if (!m) return;
    css = css.slice(m[0].length);
    return m;
  }

  /**
   * Parse whitespace.
   */

  function whitespace() {
    match(/^\s*/);
  }

  /**
   * Parse comments;
   */

  function comments(rules) {
    var c;
    rules = rules || [];
    while (c = comment()) rules.push(c);
    return rules;
  }

  /**
   * Parse comment.
   */

  function comment() {
    if ('/' != css[0] || '*' != css[1]) return;

    var i = 2;
    while (null != css[i] && ('*' != css[i] || '/' != css[i + 1])) ++i;
    i += 2;

    var str = css.slice(2, i - 2);
    css = css.slice(i);
    whitespace();

    return {
      type: 'comment',
      comment: str
    };
  }

  /**
   * Parse selector.
   */

  function selector() {
    var m = match(/^([^{]+)/);
    if (!m) return;
    return m[0].trim().split(/\s*,\s*/);
  }

  /**
   * Parse declaration.
   */

  function declaration() {
    // prop
    var prop = match(/^(\*?[-\w]+)\s*/);
    if (!prop) return;
    prop = prop[0];

    // :
    if (!match(/^:\s*/)) return;

    // val
    var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)\s*/);
    if (!val) return;
    val = val[0].trim();

    // ;
    match(/^[;\s]*/);

    return {
      type: 'declaration',
      property: prop,
      value: val
    };
  }

  /**
   * Parse declarations.
   */

  function declarations() {
    var decls = [];

    if (!open()) return;
    comments(decls);

    // declarations
    var decl;
    while (decl = declaration()) {
      decls.push(decl);
      comments(decls);
    }

    if (!close()) return;
    return decls;
  }

  /**
   * Parse keyframe.
   */

  function keyframe() {
    var m;
    var vals = [];

    while (m = match(/^(from|to|\d+%|\.\d+%|\d+\.\d+%)\s*/)) {
      vals.push(m[1]);
      match(/^,\s*/);
    }

    if (!vals.length) return;

    return {
      type: 'keyframe',
      values: vals,
      declarations: declarations()
    };
  }

  /**
   * Parse keyframes.
   */

  function atkeyframes() {
    var m = match(/^@([-\w]+)?keyframes */);
    if (!m) return;
    var vendor = m[1];

    // identifier
    var m = match(/^([-\w]+)\s*/);
    if (!m) return;
    var name = m[1];

    if (!open()) return;
    comments();

    var frame;
    var frames = [];
    while (frame = keyframe()) {
      frames.push(frame);
      comments();
    }

    if (!close()) return;

    return {
      type: 'keyframes',
      name: name,
      vendor: vendor,
      keyframes: frames
    };
  }

  /**
   * Parse supports.
   */

  function atsupports() {
    var m = match(/^@supports *([^{]+)/);
    if (!m) return;
    var supports = m[1].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return {
      type: 'supports',
      supports: supports,
      rules: style
    };
  }

  /**
   * Parse media.
   */

  function atmedia() {
    var m = match(/^@media *([^{]+)/);
    if (!m) return;
    var media = m[1].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return {
      type: 'media',
      media: media,
      rules: style
    };
  }

  /**
   * Parse paged media.
   */

  function atpage() {
    var m = match(/^@page */);
    if (!m) return;

    var sel = selector() || [];
    var decls = [];

    if (!open()) return;
    comments();

    // declarations
    var decl;
    while (decl = declaration()) {
      decls.push(decl);
      comments();
    }

    if (!close()) return;

    return {
      type: 'page',
      selectors: sel,
      declarations: decls
    };
  }

  /**
   * Parse document.
   */

  function atdocument() {
    var m = match(/^@([-\w]+)?document *([^{]+)/);
    if (!m) return;
    var vendor = m[1].trim();
    var doc = m[2].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return {
      type: 'document',
      document: doc,
      vendor: vendor,
      rules: style
    };
  }

  /**
   * Parse import
   */

  function atimport() {
    return _atrule('import');
  }

  /**
   * Parse charset
   */

  function atcharset() {
    return _atrule('charset');
  }

  /**
   * Parse namespace
   */

  function atnamespace() {
    return _atrule('namespace')
  }

  /**
   * Parse non-block at-rules
   */

  function _atrule(name) {
    var m = match(new RegExp('^@' + name + ' *([^;\\n]+);\\s*'));
    if (!m) return;
    var ret = { type: name };
    ret[name] = m[1].trim();
    return ret;
  }

  /**
   * Parse at rule.
   */

  function atrule() {
    return atkeyframes()
      || atmedia()
      || atsupports()
      || atimport()
      || atcharset()
      || atnamespace()
      || atdocument()
      || atpage();
  }

  /**
   * Parse rule.
   */

  function rule() {
    var sel = selector();
    if (!sel) return;
    comments();
    return {
      type: 'rule',
      selectors: sel,
      declarations: declarations()
    };
  }

  return stylesheet();
};
<commit_msg>add start of positioning<commit_after>
module.exports = function(css, options){
  options = options || {};

  /**
   * Positional.
   */

  var lineno = 1;

  function position() {
    var start = { line: lineno };
    if (!options.position) return positionNoop;
    return function(node){
      node.position = {
        start: start,
        end: { line: lineno }
      };

      return node;
    }
  }

  /**
   * Parse stylesheet.
   */

  function stylesheet() {
    return {
      type: 'stylesheet',
      stylesheet: {
        rules: rules()
      }
    };
  }

  /**
   * Opening brace.
   */

  function open() {
    return match(/^{\s*/);
  }

  /**
   * Closing brace.
   */

  function close() {
    return match(/^}\s*/);
  }

  /**
   * Parse ruleset.
   */

  function rules() {
    var node;
    var rules = [];
    whitespace();
    comments(rules);
    while (css[0] != '}' && (node = atrule() || rule())) {
      rules.push(node);
      comments(rules);
    }
    return rules;
  }

  /**
   * Match `re` and return captures.
   */

  function match(re) {
    var m = re.exec(css);
    if (!m) return;
    var str = m[0];
    lineno += lines(str);
    css = css.slice(str.length);
    return m;
  }

  /**
   * Parse whitespace.
   */

  function whitespace() {
    match(/^\s*/);
  }

  /**
   * Parse comments;
   */

  function comments(rules) {
    var c;
    rules = rules || [];
    while (c = comment()) rules.push(c);
    return rules;
  }

  /**
   * Parse comment.
   */

  function comment() {
    var pos = position();
    if ('/' != css[0] || '*' != css[1]) return;

    var i = 2;
    while (null != css[i] && ('*' != css[i] || '/' != css[i + 1])) ++i;
    i += 2;

    var str = css.slice(2, i - 2);
    css = css.slice(i);
    whitespace();

    lineno += lines(str);

    return pos({
      type: 'comment',
      comment: str
    });
  }

  /**
   * Parse selector.
   */

  function selector() {
    var m = match(/^([^{]+)/);
    if (!m) return;
    return m[0].trim().split(/\s*,\s*/);
  }

  /**
   * Parse declaration.
   */

  function declaration() {
    var pos = position();

    // prop
    var prop = match(/^(\*?[-\w]+)\s*/);
    if (!prop) return;
    prop = prop[0];

    // :
    if (!match(/^:\s*/)) return;

    // val
    var val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)\s*/);
    if (!val) return;
    val = val[0].trim();

    // ;
    match(/^[;\s]*/);

    return pos({
      type: 'declaration',
      property: prop,
      value: val
    });
  }

  /**
   * Parse declarations.
   */

  function declarations() {
    var decls = [];

    if (!open()) return;
    comments(decls);

    // declarations
    var decl;
    while (decl = declaration()) {
      decls.push(decl);
      comments(decls);
    }

    if (!close()) return;
    return decls;
  }

  /**
   * Parse keyframe.
   */

  function keyframe() {
    var m;
    var vals = [];
    var pos = position();

    while (m = match(/^(from|to|\d+%|\.\d+%|\d+\.\d+%)\s*/)) {
      vals.push(m[1]);
      match(/^,\s*/);
    }

    if (!vals.length) return;

    return pos({
      type: 'keyframe',
      values: vals,
      declarations: declarations()
    });
  }

  /**
   * Parse keyframes.
   */

  function atkeyframes() {
    var pos = position();
    var m = match(/^@([-\w]+)?keyframes */);

    if (!m) return;
    var vendor = m[1];

    // identifier
    var m = match(/^([-\w]+)\s*/);
    if (!m) return;
    var name = m[1];

    if (!open()) return;
    comments();

    var frame;
    var frames = [];
    while (frame = keyframe()) {
      frames.push(frame);
      comments();
    }

    if (!close()) return;

    return pos({
      type: 'keyframes',
      name: name,
      vendor: vendor,
      keyframes: frames
    });
  }

  /**
   * Parse supports.
   */

  function atsupports() {
    var pos = position();
    var m = match(/^@supports *([^{]+)/);

    if (!m) return;
    var supports = m[1].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return pos({
      type: 'supports',
      supports: supports,
      rules: style
    });
  }

  /**
   * Parse media.
   */

  function atmedia() {
    var pos = position();
    var m = match(/^@media *([^{]+)/);

    if (!m) return;
    var media = m[1].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return pos({
      type: 'media',
      media: media,
      rules: style
    });
  }

  /**
   * Parse paged media.
   */

  function atpage() {
    var pos = position();
    var m = match(/^@page */);
    if (!m) return;

    var sel = selector() || [];
    var decls = [];

    if (!open()) return;
    comments();

    // declarations
    var decl;
    while (decl = declaration()) {
      decls.push(decl);
      comments();
    }

    if (!close()) return;

    return pos({
      type: 'page',
      selectors: sel,
      declarations: decls
    });
  }

  /**
   * Parse document.
   */

  function atdocument() {
    var pos = position();
    var m = match(/^@([-\w]+)?document *([^{]+)/);
    if (!m) return;

    var vendor = m[1].trim();
    var doc = m[2].trim();

    if (!open()) return;
    comments();

    var style = rules();

    if (!close()) return;

    return pos({
      type: 'document',
      document: doc,
      vendor: vendor,
      rules: style
    });
  }

  /**
   * Parse import
   */

  function atimport() {
    return _atrule('import');
  }

  /**
   * Parse charset
   */

  function atcharset() {
    return _atrule('charset');
  }

  /**
   * Parse namespace
   */

  function atnamespace() {
    return _atrule('namespace')
  }

  /**
   * Parse non-block at-rules
   */

  function _atrule(name) {
    var pos = position();
    var m = match(new RegExp('^@' + name + ' *([^;\\n]+);\\s*'));
    if (!m) return;
    var ret = { type: name };
    ret[name] = m[1].trim();
    return pos(ret);
  }

  /**
   * Parse at rule.
   */

  function atrule() {
    return atkeyframes()
      || atmedia()
      || atsupports()
      || atimport()
      || atcharset()
      || atnamespace()
      || atdocument()
      || atpage();
  }

  /**
   * Parse rule.
   */

  function rule() {
    var pos = position();
    var sel = selector();

    if (!sel) return;
    comments();

    return pos({
      type: 'rule',
      selectors: sel,
      declarations: declarations()
    });
  }

  return stylesheet();
};

/**
 * Lines within `str`.
 */

function lines(str) {
  return str.split('\n').length - 1;
}

/**
 * Return `node`.
 */

function positionNoop(node) {
  return node;
}
<|endoftext|>