<commit_before>/*globals define, WebGMEGlobal*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 1.7.0 from webgme on Tue Sep 27 2016 23:15:32 GMT-0500 (Central Daylight Time).
 */

define([
    './cytoscape.min',
    'cose_bilkent/cytoscape-cose-bilkent',
    'text!./style2.css',
    'handlebars/dist/handlebars',
    'q',
    'css!./styles/CommVizWidget.css'], function (
	cytoscape,
	regCose,
	styleText,
	Handlebars,
	Q) {
	'use strict';

	regCose( cytoscape );

	var CommVizWidget,
            WIDGET_CLASS = 'comm-viz';

	CommVizWidget = function (logger, container) {
            this._logger = logger.fork('Widget');

            this._el = container;

            // set widget class
            this._el.addClass(WIDGET_CLASS);

	    this._el.append('

');
	    this._cy_container = this._el.find('#cy');

	    // add reset and filter buttons
	    this._el.append('<button id="reset" class="btn btn-default"></button>');
	    this._el.append('<button id="filter" class="btn btn-default" data-hasqtip="0"></button>');
	    this._el.append('<button id="re_layout" class="btn btn-default"></button>');

            this._initialize();

            this._logger.debug('ctor finished');
	};

	CommVizWidget.prototype._initialize = function () {
            var width = this._el.width(),
		height = this._el.height(),
		self = this;

            this.nodes = {};
	    this.dependencies = {
		'nodes': {},
		'edges': {}
	    };
	    this.waitingNodes = {};

	    this._cytoscape_options = {
		container: this._cy_container,
		style: styleText,
		// interaction options:
		minZoom: 1e-50,
		maxZoom: 1e50,
		zoomingEnabled: true,
		userZoomingEnabled: true,
		panningEnabled: true,
		userPanningEnabled: true,
		boxSelectionEnabled: false,
		selectionType: 'single',
		touchTapThreshold: 8,
		desktopTapThreshold: 4,
		autolock: false,
		autoungrabify: false,
		autounselectify: false,

		// rendering options:
		headless: false,
		styleEnabled: true,
		hideEdgesOnViewport: false,
		hideLabelsOnViewport: false,
		textureOnViewport: false,
		motionBlur: false,
		motionBlurOpacity: 0.2,
		wheelSensitivity: 1,
		pixelRatio: 'auto'
	    };

	    var self = this;

	    this._layout_options = {
		'name': 'cose-bilkent',
		// Called on `layoutready`
		ready: function () {
		    self._cy.nodes().forEach(function(node) {
			var p = node.position();
			node.data('orgPos',{
			    x: p.x,
			    y: p.y
			});
		    });
		},
		// Called on `layoutstop`
		stop: function () {
		},
		// Whether to fit the network view after when done
		fit: true,
		// Padding on fit
		padding: 10,
		// Whether to enable incremental mode
		randomize: true,
		// Node repulsion (non overlapping) multiplier
		nodeRepulsion: 5500, // 4500
		// Ideal edge (non nested) length
		idealEdgeLength: 100,   // 50
		// Divisor to compute edge forces
		edgeElasticity: 0.45,
		// Nesting factor (multiplier) to compute ideal edge length for nested edges
		nestingFactor: 0.1,
		// Gravity force (constant)
		gravity: 0.1,  // 0.25
		// Maximum number of iterations to perform
		numIter: 2500,
		// For enabling tiling
		tile: false,   // true
		// Type of layout animation. The option set is {'during', 'end', false}
		animate: 'end',
		// Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function)
		tilingPaddingVertical: 10,
		// Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function)
		tilingPaddingHorizontal: 10,
		// Gravity range (constant) for compounds
		gravityRangeCompound: 1.5,
		// Gravity force (constant) for compounds
		gravityCompound: 1.0,
		// Gravity range (constant)
		gravityRange: 3.8
	    };
	    this._cytoscape_options.layout = self._layout_options;
	    this._cy = cytoscape(self._cytoscape_options);

	    // copied from the wine and cheese demo
	    var infoTemplate = Handlebars.compile([
		'
{{name}}
',
		'
 {{NodeTypeFormatted}} {{#if Type}}({{Type}}){{/if}}
',
		'{{#if Milk}}
 {{Milk}}
{{/if}}',
		'{{#if Country}}
 {{Country}}
{{/if}}',
		'
 More information
'
	    ].join(''));

	    var layoutPadding = 50;
	    var layoutDuration = 500;

	    function highlight( node ){
		var nhood = node.closedNeighborhood();

		self._cy.batch(function(){
		    self._cy.elements("edge").not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Component"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Message"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Service"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    nhood.removeClass('faded').addClass('highlighted');

		    var npos = node.position();
		    var w = window.innerWidth;
		    var h = window.innerHeight;

		    self._cy.stop().animate({
			fit: {
			    eles: self._cy.elements(),
			    padding: layoutPadding
			}
		    }, {
			duration: layoutDuration
		    }).delay( layoutDuration, function(){
			nhood.layout({
			    name: 'concentric',
			    padding: layoutPadding,
			    animate: true,
			    animationDuration: layoutDuration,
			    boundingBox: {
				x1: npos.x - w/2,
				x2: npos.x + w/2,
				y1: npos.y - w/2,
				y2: npos.y + w/2
			    },
			    fit: true,
			    concentric: function( n ){
				if( node.id() === n.id() ){
				    return 2;
				} else {
				    return 1;
				}
			    },
			    levelWidth: function(){
				return 1;
			    }
			});
		    } );

		});
	    }

	    function clear(){
		self._cy.batch(function(){
		    self._cy.$('.highlighted').forEach(function(n){
			n.animate({
			    position: n.data('orgPos')
			});
		    });

		    self._cy.elements().removeClass('highlighted').removeClass('faded');
		});
	    }

	    function showNodeInfo( node ){
		$('#info').html( infoTemplate( node.data() ) ).show();
	    }

	    function hideNodeInfo(){
		$('#info').hide();
	    }

	    self._cy.on('free', 'node', function( e ){
		var n = e.cyTarget;
		var p = n.position();

		n.data('orgPos', {
		    x: p.x,
		    y: p.y
		});
	    });

	    self._cy.on('tap', function(){
		$('#search').blur();
	    });

	    self._cy.on('select', 'node', function(e){
		var node = this;

		highlight( node );
		showNodeInfo( node );
	    });

	    self._cy.on('unselect', 'node', function(e){
		var node = this;

		clear();
		hideNodeInfo();
	    });

	    self._el.find('#re_layout').on('click', function(){
		self._cy.layout(self._layout_options);
	    });

	    self._el.find('#reset').on('click', function(){
		self._cy.animate({
		    fit: {
			eles: self._cy.elements(),
			padding: layoutPadding
		    },
		    duration: layoutDuration
		});
	    });

	    self._el.find('#filters').on('click', 'input', function(){

		var soft = $('#soft').is(':checked');
		var semiSoft = $('#semi-soft').is(':checked');
		var na = $('#na').is(':checked');
		var semiHard = $('#semi-hard').is(':checked');
		var hard = $('#hard').is(':checked');

		var red = $('#red').is(':checked');
		var white = $('#white').is(':checked');
		var cider = $('#cider').is(':checked');

		cy.batch(function(){

		    cy.nodes().forEach(function( n ){
			var type = n.data('NodeType');

			n.removeClass('filtered');

			var filter = function(){
			    n.addClass('filtered');
			};

			if( type === 'Cheese' ){

			    var cType = n.data('Type');

			    if(
				(cType === 'Soft' && !soft)
				    || (cType === 'Semi-soft' && !semiSoft)
				    || (cType === undefined && !na)
				    || (cType === 'Semi-hard' && !semiHard)
				    || (cType === 'Hard' && !hard)
			    ){
				filter();
			    }

			} else if( type === 'RedWine' ){

			    if( !red ){ filter(); }

			} else if( type === 'WhiteWine' ){

			    if( !white ){ filter(); }

			} else if( type === 'Cider' ){

			    if( !cider ){ filter(); }

			}

		    });

		});

	    });
	};

	CommVizWidget.prototype.onWidgetContainerResize = function (width, height) {
            this._logger.debug('Widget is resizing...');
	};

	var connectionTypes = [
	    'Publisher',
	    'Subscriber',
	    'Client',
	    'Server'
	];

	CommVizWidget.prototype.checkDependencies = function(desc) {
	    var self = this;
	    // dependencies will always be either parentId (nodes & edges) or connection (edges)
	    var deps = [];
	    if (desc.parentId && !self.nodes[desc.parentId]) {
		deps.push(desc.parentId);
	    }
	    if (desc.connection && !self.nodes[desc.connection]) {
		deps.push(desc.connection);
	    }
	    var depsMet = (deps.length == 0);
	    if (!depsMet) {
		if (connectionTypes.indexOf(desc.type) > -1)
		    self.dependencies.edges[desc.id] = deps;
		else
		    self.dependencies.nodes[desc.id] = deps;
	    }
	    return depsMet;
	};

	CommVizWidget.prototype.updateDependencies = function() {
	    var self = this;
	    var nodePaths = Object.keys(self.dependencies.nodes);
	    var edgePaths = Object.keys(self.dependencies.edges);
	    // create any nodes whose depenencies are fulfilled now
	    nodePaths.map(function(nodePath) {
		var depPaths = self.dependencies.nodes[nodePath];
		if (depPaths && depPaths.length > 0) {
		    depPaths = depPaths.filter(function(objPath) { return self.nodes[objPath] == undefined; });
		    if (!depPaths.length) {
			var desc = self.waitingNodes[nodePath];
			self.waitingNodes[nodePath] = undefined;
			self.dependencies.nodes[nodePath] = undefined;
			self.createNode(desc);
		    }
		    else {
			self.dependencies.nodes[nodePath] = depPaths;
		    }
		}
		else {
		    self.dependencies.nodes[nodePath] = undefined;
		}
	    });
	    // Create any edges whose dependencies are fulfilled now
	    edgePaths.map(function(edgePath) {
		var depPaths = self.dependencies.edges[edgePath];
		if (depPaths && depPaths.length > 0) {
		    depPaths = depPaths.filter(function(objPath) { return self.nodes[objPath] == undefined; });
		    if (!depPaths.length) {
			var connDesc = self.waitingNodes[edgePath];
			self.waitingNodes[edgePath] = undefined;
			self.dependencies.edges[edgePath] = undefined;
			self.createEdge(connDesc);
		    }
		    else {
			self.dependencies.edges[edgePath] = depPaths;
		    }
		}
		else {
		    self.dependencies.edges[edgePath] = undefined;
		}
	    });
	};

	// pub, sub, client, server are all edges
	CommVizWidget.prototype.createEdge = function(desc) {
	    var self = this;
	    var type = desc.type;
	    var from = self.nodes[desc.from];
	    var to   = self.nodes[desc.to];
	    if (from && to) {
		self._cy.add({
		    group: 'edges',
		    data: {
			id: from.id + to.id,
			type: type,
			interaction: type,
			source: from.id,
			target: to.id
		    }
		});
		self._cy.layout(self._layout_options);
		self.nodes[desc.id] = desc;
		self.updateDependencies();
	    }
	};

	// nodes are components, nodes, containers, messages, services
	CommVizWidget.prototype.createNode = function(desc) {
	    var self = this;
	    var node = {
		group: 'nodes',
		data: {
		    id: desc.id,
		    parent: desc.parentId,
		    type: desc.type,
		    NodeType: desc.type,
		    name: desc.name,
		    label: desc.name,
		    orgPos: null
		}
	    };
	    self._cy.add(node);
	    self._cy.layout(self._layout_options);
	    self.nodes[desc.id] = desc;
	    self.updateDependencies();
	};

	// Adding/Removing/Updating items
	CommVizWidget.prototype.addNode = function (desc) {
	    var self = this;
            if (desc && desc.type != 'Deployment') {
		var depsMet = self.checkDependencies(desc);
		// Add node to a table of nodes
		if (connectionTypes.indexOf(desc.type) > -1) {  // if this is actually an edge
		    if (depsMet) { // ready to make edge
			self.createEdge(desc);
		    }
		    else { // missing some dependencies (either parentId or connection)
			self.waitingNodes[desc.id] = desc;
		    }
		}
		else {
		    if (depsMet) { // ready to make node
			self.createNode(desc);
		    }
		    else {
			self.waitingNodes[desc.id] = desc;
		    }
		}
	    }
	};

	CommVizWidget.prototype.removeNode = function (gmeId) {
            var desc = this.nodes[gmeId];
            this._logger.debug('Removing node ' + desc.name);
	    this._cy.remove("[id == " + gmeId + "]");
            delete this.nodes[gmeId];
	};

	CommVizWidget.prototype.updateNode = function (desc) {
            if (desc) {
		this._logger.debug('Updating node:', desc);
            }
	};

	/* * * * * * * * Visualizer event handlers * * * * * * * */

	CommVizWidget.prototype.onBackgroundDblClick = function () {
	};

	/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
	CommVizWidget.prototype.destroy = function () {
	};

	CommVizWidget.prototype.onActivate = function () {
            //console.log('CommVizWidget has been activated');
	};

	CommVizWidget.prototype.onDeactivate = function () {
            //console.log('CommVizWidget has been deactivated');
	};

	return CommVizWidget;
    });
<commit_msg>minor update.<commit_after>/*globals define, WebGMEGlobal*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 1.7.0 from webgme on Tue Sep 27 2016 23:15:32 GMT-0500 (Central Daylight Time).
 */

define([
    './cytoscape.min',
    'cose_bilkent/cytoscape-cose-bilkent',
    'text!./style2.css',
    'handlebars/dist/handlebars',
    'q',
    'css!./styles/CommVizWidget.css'], function (
	cytoscape,
	regCose,
	styleText,
	Handlebars,
	Q) {
	'use strict';

	regCose( cytoscape );

	var CommVizWidget,
            WIDGET_CLASS = 'comm-viz';

	CommVizWidget = function (logger, container) {
            this._logger = logger.fork('Widget');

            this._el = container;

            // set widget class
            this._el.addClass(WIDGET_CLASS);

	    this._el.append('

');
	    this._cy_container = this._el.find('#cy');

	    // add reset and filter buttons
	    this._el.append('<button id="reset" class="btn btn-default"></button>');
	    this._el.append('<button id="filter" class="btn btn-default" data-hasqtip="0"></button>');
	    this._el.append('<button id="re_layout" class="btn btn-default"></button>');

            this._initialize();

            this._logger.debug('ctor finished');
	};

	CommVizWidget.prototype._initialize = function () {
            var width = this._el.width(),
		height = this._el.height(),
		self = this;

            this.nodes = {};
	    this.dependencies = {
		'nodes': {},
		'edges': {}
	    };
	    this.waitingNodes = {};

	    this._cytoscape_options = {
		container: this._cy_container,
		style: styleText,
		// interaction options:
		minZoom: 1e-50,
		maxZoom: 1e50,
		zoomingEnabled: true,
		userZoomingEnabled: true,
		panningEnabled: true,
		userPanningEnabled: true,
		boxSelectionEnabled: false,
		selectionType: 'single',
		touchTapThreshold: 8,
		desktopTapThreshold: 4,
		autolock: false,
		autoungrabify: false,
		autounselectify: false,

		// rendering options:
		headless: false,
		styleEnabled: true,
		hideEdgesOnViewport: false,
		hideLabelsOnViewport: false,
		textureOnViewport: false,
		motionBlur: false,
		motionBlurOpacity: 0.2,
		wheelSensitivity: 1,
		pixelRatio: 'auto'
	    };

	    var self = this;

	    this._layout_options = {
		'name': 'cose-bilkent',
		// Called on `layoutready`
		ready: function () {
		    self._cy.nodes().forEach(function(node) {
			var p = node.position();
			node.data('orgPos',{
			    x: p.x,
			    y: p.y
			});
		    });
		},
		// Called on `layoutstop`
		stop: function () {
		    self._cy.nodes().forEach(function(node) {
			var p = node.position();
			node.data('orgPos',{
			    x: p.x,
			    y: p.y
			});
		    });
		},
		// Whether to fit the network view after when done
		fit: true,
		// Padding on fit
		padding: 10,
		// Whether to enable incremental mode
		randomize: true,
		// Node repulsion (non overlapping) multiplier
		nodeRepulsion: 5500, // 4500
		// Ideal edge (non nested) length
		idealEdgeLength: 100,   // 50
		// Divisor to compute edge forces
		edgeElasticity: 0.45,
		// Nesting factor (multiplier) to compute ideal edge length for nested edges
		nestingFactor: 0.1,
		// Gravity force (constant)
		gravity: 0.1,  // 0.25
		// Maximum number of iterations to perform
		numIter: 2500,
		// For enabling tiling
		tile: false,   // true
		// Type of layout animation. The option set is {'during', 'end', false}
		animate: 'end',
		// Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function)
		tilingPaddingVertical: 10,
		// Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function)
		tilingPaddingHorizontal: 10,
		// Gravity range (constant) for compounds
		gravityRangeCompound: 1.5,
		// Gravity force (constant) for compounds
		gravityCompound: 1.0,
		// Gravity range (constant)
		gravityRange: 3.8
	    };
	    this._cytoscape_options.layout = self._layout_options;
	    this._cy = cytoscape(self._cytoscape_options);

	    // copied from the wine and cheese demo
	    var infoTemplate = Handlebars.compile([
		'
{{name}}
',
		'
 {{NodeTypeFormatted}} {{#if Type}}({{Type}}){{/if}}
',
		'{{#if Milk}}
 {{Milk}}
{{/if}}',
		'{{#if Country}}
 {{Country}}
{{/if}}',
		'
 More information
'
	    ].join(''));

	    var layoutPadding = 50;
	    var layoutDuration = 500;

	    function highlight( node ){
		var nhood = node.closedNeighborhood();

		self._cy.batch(function(){
		    self._cy.elements("edge").not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Component"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Message"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    self._cy.elements('[NodeType="Service"]').not( nhood ).removeClass('highlighted').addClass('faded');
		    nhood.removeClass('faded').addClass('highlighted');

		    var npos = node.position();
		    var w = window.innerWidth;
		    var h = window.innerHeight;

		    self._cy.stop().animate({
			fit: {
			    eles: self._cy.elements(),
			    padding: layoutPadding
			}
		    }, {
			duration: layoutDuration
		    }).delay( layoutDuration, function(){
			nhood.layout({
			    name: 'concentric',
			    padding: layoutPadding,
			    animate: true,
			    animationDuration: layoutDuration,
			    boundingBox: {
				x1: npos.x - w/2,
				x2: npos.x + w/2,
				y1: npos.y - w/2,
				y2: npos.y + w/2
			    },
			    fit: true,
			    concentric: function( n ){
				if( node.id() === n.id() ){
				    return 2;
				} else {
				    return 1;
				}
			    },
			    levelWidth: function(){
				return 1;
			    }
			});
		    } );

		});
	    }

	    function clear(){
		self._cy.batch(function(){
		    self._cy.$('.highlighted').forEach(function(n){
			n.animate({
			    position: n.data('orgPos')
			});
		    });

		    self._cy.elements().removeClass('highlighted').removeClass('faded');
		});
	    }

	    function showNodeInfo( node ){
		$('#info').html( infoTemplate( node.data() ) ).show();
	    }

	    function hideNodeInfo(){
		$('#info').hide();
	    }

	    self._cy.on('free', 'node', function( e ){
		var n = e.cyTarget;
		var p = n.position();

		n.data('orgPos', {
		    x: p.x,
		    y: p.y
		});
	    });

	    self._cy.on('tap', function(){
		$('#search').blur();
	    });

	    self._cy.on('select', 'node', function(e){
		var node = this;

		highlight( node );
		showNodeInfo( node );
	    });

	    self._cy.on('unselect', 'node', function(e){
		var node = this;

		clear();
		hideNodeInfo();
	    });

	    self._el.find('#re_layout').on('click', function(){
		self._cy.layout(self._layout_options);
	    });

	    self._el.find('#reset').on('click', function(){
		self._cy.animate({
		    fit: {
			eles: self._cy.elements(),
			padding: layoutPadding
		    },
		    duration: layoutDuration
		});
	    });

	    self._el.find('#filters').on('click', 'input', function(){

		var soft = $('#soft').is(':checked');
		var semiSoft = $('#semi-soft').is(':checked');
		var na = $('#na').is(':checked');
		var semiHard = $('#semi-hard').is(':checked');
		var hard = $('#hard').is(':checked');

		var red = $('#red').is(':checked');
		var white = $('#white').is(':checked');
		var cider = $('#cider').is(':checked');

		cy.batch(function(){

		    cy.nodes().forEach(function( n ){
			var type = n.data('NodeType');

			n.removeClass('filtered');

			var filter = function(){
			    n.addClass('filtered');
			};

			if( type === 'Cheese' ){

			    var cType = n.data('Type');

			    if(
				(cType === 'Soft' && !soft)
				    || (cType === 'Semi-soft' && !semiSoft)
				    || (cType === undefined && !na)
				    || (cType === 'Semi-hard' && !semiHard)
				    || (cType === 'Hard' && !hard)
			    ){
				filter();
			    }

			} else if( type === 'RedWine' ){

			    if( !red ){ filter(); }

			} else if( type === 'WhiteWine' ){

			    if( !white ){ filter(); }

			} else if( type === 'Cider' ){

			    if( !cider ){ filter(); }

			}

		    });

		});

	    });
	};

	CommVizWidget.prototype.onWidgetContainerResize = function (width, height) {
            this._logger.debug('Widget is resizing...');
	};

	var connectionTypes = [
	    'Publisher',
	    'Subscriber',
	    'Client',
	    'Server'
	];

	CommVizWidget.prototype.checkDependencies = function(desc) {
	    var self = this;
	    // dependencies will always be either parentId (nodes & edges) or connection (edges)
	    var deps = [];
	    if (desc.parentId && !self.nodes[desc.parentId]) {
		deps.push(desc.parentId);
	    }
	    if (desc.connection && !self.nodes[desc.connection]) {
		deps.push(desc.connection);
	    }
	    var depsMet = (deps.length == 0);
	    if (!depsMet) {
		if (connectionTypes.indexOf(desc.type) > -1)
		    self.dependencies.edges[desc.id] = deps;
		else
		    self.dependencies.nodes[desc.id] = deps;
	    }
	    return depsMet;
	};

	CommVizWidget.prototype.updateDependencies = function() {
	    var self = this;
	    var nodePaths = Object.keys(self.dependencies.nodes);
	    var edgePaths = Object.keys(self.dependencies.edges);
	    // create any nodes whose depenencies are fulfilled now
	    nodePaths.map(function(nodePath) {
		var depPaths = self.dependencies.nodes[nodePath];
		if (depPaths && depPaths.length > 0) {
		    depPaths = depPaths.filter(function(objPath) { return self.nodes[objPath] == undefined; });
		    if (!depPaths.length) {
			var desc = self.waitingNodes[nodePath];
			self.waitingNodes[nodePath] = undefined;
			self.dependencies.nodes[nodePath] = undefined;
			self.createNode(desc);
		    }
		    else {
			self.dependencies.nodes[nodePath] = depPaths;
		    }
		}
		else {
		    self.dependencies.nodes[nodePath] = undefined;
		}
	    });
	    // Create any edges whose dependencies are fulfilled now
	    edgePaths.map(function(edgePath) {
		var depPaths = self.dependencies.edges[edgePath];
		if (depPaths && depPaths.length > 0) {
		    depPaths = depPaths.filter(function(objPath) { return self.nodes[objPath] == undefined; });
		    if (!depPaths.length) {
			var connDesc = self.waitingNodes[edgePath];
			self.waitingNodes[edgePath] = undefined;
			self.dependencies.edges[edgePath] = undefined;
			self.createEdge(connDesc);
		    }
		    else {
			self.dependencies.edges[edgePath] = depPaths;
		    }
		}
		else {
		    self.dependencies.edges[edgePath] = undefined;
		}
	    });
	};

	// pub, sub, client, server are all edges
	CommVizWidget.prototype.createEdge = function(desc) {
	    var self = this;
	    var type = desc.type;
	    var from = self.nodes[desc.from];
	    var to   = self.nodes[desc.to];
	    if (from && to) {
		self._cy.add({
		    group: 'edges',
		    data: {
			id: from.id + to.id,
			type: type,
			interaction: type,
			source: from.id,
			target: to.id
		    }
		});
		self._cy.layout(self._layout_options);
		self.nodes[desc.id] = desc;
		self.updateDependencies();
	    }
	};

	// nodes are components, nodes, containers, messages, services
	CommVizWidget.prototype.createNode = function(desc) {
	    var self = this;
	    var node = {
		group: 'nodes',
		data: {
		    id: desc.id,
		    parent: desc.parentId,
		    type: desc.type,
		    NodeType: desc.type,
		    name: desc.name,
		    label: desc.name,
		    orgPos: null
		}
	    };
	    self._cy.add(node);
	    self._cy.layout(self._layout_options);
	    self.nodes[desc.id] = desc;
	    self.updateDependencies();
	};

	// Adding/Removing/Updating items
	CommVizWidget.prototype.addNode = function (desc) {
	    var self = this;
            if (desc && desc.type != 'Deployment') {
		var depsMet = self.checkDependencies(desc);
		// Add node to a table of nodes
		if (connectionTypes.indexOf(desc.type) > -1) {  // if this is actually an edge
		    if (depsMet) { // ready to make edge
			self.createEdge(desc);
		    }
		    else { // missing some dependencies (either parentId or connection)
			self.waitingNodes[desc.id] = desc;
		    }
		}
		else {
		    if (depsMet) { // ready to make node
			self.createNode(desc);
		    }
		    else {
			self.waitingNodes[desc.id] = desc;
		    }
		}
	    }
	};

	CommVizWidget.prototype.removeNode = function (gmeId) {
            var desc = this.nodes[gmeId];
            this._logger.debug('Removing node ' + desc.name);
	    this._cy.remove("[id == " + gmeId + "]");
            delete this.nodes[gmeId];
	};

	CommVizWidget.prototype.updateNode = function (desc) {
            if (desc) {
		this._logger.debug('Updating node:', desc);
            }
	};

	/* * * * * * * * Visualizer event handlers * * * * * * * */

	CommVizWidget.prototype.onBackgroundDblClick = function () {
	};

	/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
	CommVizWidget.prototype.destroy = function () {
	};

	CommVizWidget.prototype.onActivate = function () {
            //console.log('CommVizWidget has been activated');
	};

	CommVizWidget.prototype.onDeactivate = function () {
            //console.log('CommVizWidget has been deactivated');
	};

	return CommVizWidget;
    });
<|endoftext|>


<commit_before>"use strict"

var format = require('python-format')
var request = require('request')

var port = +process.env.npm_package_config_webhookport
if (!port) {
    console.error("Start the bot using 'npm start'.")
    return
}

var secret = process.env.npm_package_config_secret
if (!secret) {
    console.error("Secret not defined, please use 'npm config set psdevbot:secret value'.")
    return
}

var Showdown = require('./showdown')
var parameters = {}
Object.keys(Showdown.keys).forEach(function (key) {
    parameters[key] = process.env['npm_package_config_' + key]
})
var client = new Showdown(parameters)
client.connect()

var github = require('githubhook')({
    port: port,
    secret: secret,
    logger: console
})

function shorten(url, callback) {
    function shortenCallback(error, response, body) {
        var shortenedUrl = url
        if (!error && response.headers.location) {
            shortenedUrl = response.headers.location
        }
        callback(shortenedUrl)
    }
    request.post('https://git.io', {form: {url: url}}, shortenCallback)
}

var escape = require('escape-html')

github.on('push', function push(repo, ref, result) {
    var url = result.compare
    var branch = /[^/]+$/.exec(ref)[0]
    shorten(url, function pushShortened(url) {
        var messages = []
        var message = result.commits.length === 1 ?
            "[{}] {} pushed {} new commit to {}: {4}" :
            "[{}] {} pushed {} new commits to {}: {4}"

        messages.push(format(
            message,
            escape(repo),
            escape(result.pusher.name),
            escape(result.commits.length),
            escape(branch),
            escape(url)
        ))
        result.commits.forEach(function (commit) {
            messages.push(format(
                "{}/{} {} {}: {}",
                escape(repo),
                escape(branch),
                escape(commit.id.substring(0, 8)),
                escape(commit.author.name),
                escape(/.+/.exec(commit.message)[0])
            ))
        })
        client.report('!htmlbox ' + messages.join("
"))
    })
})

github.on('pull_request', function pullRequest(repo, ref, result) {
    var url = result.pull_request.html_url
    shorten(url, function pullRequestShortened(url) {
        client.report(format(
            "!htmlbox [{}] {} {} pull request #{}: {} {}",
            escape(repo),
            escape(result.pull_request.user.login),
            escape(result.action),
            escape(result.pull_request.number),
            escape(result.pull_request.title),
            escape(url)
        ))
    })
})

github.listen()
<commit_msg>Decolor repo name<commit_after>"use strict"

var format = require('python-format')
var request = require('request')

var port = +process.env.npm_package_config_webhookport
if (!port) {
    console.error("Start the bot using 'npm start'.")
    return
}

var secret = process.env.npm_package_config_secret
if (!secret) {
    console.error("Secret not defined, please use 'npm config set psdevbot:secret value'.")
    return
}

var Showdown = require('./showdown')
var parameters = {}
Object.keys(Showdown.keys).forEach(function (key) {
    parameters[key] = process.env['npm_package_config_' + key]
})
var client = new Showdown(parameters)
client.connect()

var github = require('githubhook')({
    port: port,
    secret: secret,
    logger: console
})

function shorten(url, callback) {
    function shortenCallback(error, response, body) {
        var shortenedUrl = url
        if (!error && response.headers.location) {
            shortenedUrl = response.headers.location
        }
        callback(shortenedUrl)
    }
    request.post('https://git.io', {form: {url: url}}, shortenCallback)
}

var escape = require('escape-html')

github.on('push', function push(repo, ref, result) {
    var url = result.compare
    var branch = /[^/]+$/.exec(ref)[0]
    shorten(url, function pushShortened(url) {
        var messages = []
        var message = result.commits.length === 1 ?
            "[{}] {} pushed {} new commit to {}: {4}" :
            "[{}] {} pushed {} new commits to {}: {4}"

        messages.push(format(
            message,
            escape(repo),
            escape(result.pusher.name),
            escape(result.commits.length),
            escape(branch),
            escape(url)
        ))
        result.commits.forEach(function (commit) {
            messages.push(format(
                "{}/{} {} {}: {}",
                escape(repo),
                escape(branch),
                escape(commit.id.substring(0, 8)),
                escape(commit.author.name),
                escape(/.+/.exec(commit.message)[0])
            ))
        })
        client.report('!htmlbox ' + messages.join("
"))
    })
})

github.on('pull_request', function pullRequest(repo, ref, result) {
    var url = result.pull_request.html_url
    shorten(url, function pullRequestShortened(url) {
        client.report(format(
            "!htmlbox [{}] {} {} pull request #{}: {} {}",
            escape(repo),
            escape(result.pull_request.user.login),
            escape(result.action),
            escape(result.pull_request.number),
            escape(result.pull_request.title),
            escape(url)
        ))
    })
})

github.listen()
<|endoftext|>


<commit_before>//= require /angular/angular
//= require /angular/angular-resource
//= require /app.config
//= require_self
//= require_tree services
//= require_tree controllers
//= require_tree directives
//= require_tree domain
//= require_tree templates

(function() {
    "use strict";

    angular.module("@grails.codegen.defaultPackage@", ["siteConfig"]);

})();<commit_msg>Fix asset require for default module<commit_after>//= require /angular/angular
//= require /angular/angular-resource
//= require /siteConfig
//= require_self
//= require_tree services
//= require_tree controllers
//= require_tree directives
//= require_tree domain
//= require_tree templates

(function() {
    "use strict";

    angular.module("@grails.codegen.defaultPackage@", ["siteConfig"]);

})();<|endoftext|>


<commit_before>//Copyright 2013-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//Licensed under the Apache License, Version 2.0 (the "License").
//You may not use this file except in compliance with the License.
//A copy of the License is located at
//
//    http://aws.amazon.com/apache2.0/
//
//or in the "license" file accompanying this file. This file 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.

//Get modules.
var express = require('express');
var http = require('http');
var routes = require('./routes');
var path = require('path');
var fs = require('fs');
var AWS = require('aws-sdk');
var jade = require('jade')
var app = express();

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);

//Read config values from a JSON file.
var config = fs.readFileSync('./app_config.json', 'utf8');
config = JSON.parse(config);

//Create DynamoDB client and pass in region.
var db = new AWS.DynamoDB({
	region: config.AWS_REGION
});

//GET home page.
app.get('/', routes.index);

//GET resolve
app.get('/resolve', function(req, res) {
	var appIdField = req.query.appId;
	console.log('resolving', appIdField);
	resolve(appIdField, function(data) {
		console.log('got data ', data);
		val fn = jade.compile('')
		res.render('template', data)
		//res.send(data)
	});
});

var resolve = function(appId, cb) {
	var params = {
		TableName: 'apps',
		Key: {
			"app_id": {
				"S": appId
			},
		}
	}
	db.getItem(params, function(err, data) {
		console.log('sent', params)
		if (err) {
			console.log('Error getting data from database: ', err);
			cb(err)
		} else {
			console.log('Got data:', data);
			cb(data)
		}
	});
};

//app.get('/add')

http.createServer(app).listen(app.get('port'), function() {
	console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>val?!<commit_after>//Copyright 2013-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//Licensed under the Apache License, Version 2.0 (the "License").
//You may not use this file except in compliance with the License.
//A copy of the License is located at
//
//    http://aws.amazon.com/apache2.0/
//
//or in the "license" file accompanying this file. This file 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.

//Get modules.
var express = require('express');
var http = require('http');
var routes = require('./routes');
var path = require('path');
var fs = require('fs');
var AWS = require('aws-sdk');
var jade = require('jade')
var app = express();

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);

//Read config values from a JSON file.
var config = fs.readFileSync('./app_config.json', 'utf8');
config = JSON.parse(config);

//Create DynamoDB client and pass in region.
var db = new AWS.DynamoDB({
	region: config.AWS_REGION
});

//GET home page.
app.get('/', routes.index);

//GET resolve
app.get('/resolve', function(req, res) {
	var appIdField = req.query.appId;
	console.log('resolving', appIdField);
	resolve(appIdField, function(data) {
		console.log('got data ', data);
		res.render('template', data)
		//res.send(data)
	});
});

var resolve = function(appId, cb) {
	var params = {
		TableName: 'apps',
		Key: {
			"app_id": {
				"S": appId
			},
		}
	}
	db.getItem(params, function(err, data) {
		console.log('sent', params)
		if (err) {
			console.log('Error getting data from database: ', err);
			cb(err)
		} else {
			console.log('Got data:', data);
			cb(data)
		}
	});
};

//app.get('/add')

http.createServer(app).listen(app.get('port'), function() {
	console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>define([
    "./../input",
    "./../gui",
    "./../view/viewport",
    "./../world/worldbuilder",
    "./../rendering/renderer",
    "./../game/debuglayer",
    "./editor"
], function Game(
    Input,
    Gui,
    Viewport,
    WorldBuilder,
    Renderer,
    DebugLayer,
    Editor
) {
    var Game = Object.subclass("Game", {
        initialize: function(canvasId) {
            //TODO: delegate to dedicated builder/factory functions
            this.buildCanvas(canvasId);
            this.buildInput(canvasId);
            this.renderer = new Renderer(this.canvas);
            this.buildViewport();
            this.constrainDebugLayer();
            this.levels = new LevelPointer();
        },
        buildCanvas: function(canvasId) {
            this.canvas = document.getElementById(canvasId);
            this.canvas.style.position = "absolute";
            this.canvas.style.top = "0px";
            this.canvas.style.left = "0px";
            this.canvas.style["z-index"] = -1;
        },
        buildInput: function(canvasId) {
            this.input = new Input(canvasId);

            _.each({
                W: "up",
                A: "left",
                S: "down",
                D: "right",

                UP_ARROW: "up",
                LEFT_ARROW: "left",
                DOWN_ARROW: "down",
                RIGHT_ARROW: "right",

                MOUSE1: "leftclick",
                MOUSE2: "rightclick",
                MWHEEL_UP: "zoomIn",
                MWHEEL_DOWN: "zoomOut",

                O: "debug",
                P: "pause"
            }, function(state, key){
                this.input.bind(Input.KEY[key], state);
            }, this);
        },
        buildViewport: function() {
            var input = this.input,
                // TODO: find correct domain, also adjust debug targeting tiles
                viewport = this.viewport = new Viewport(
                    new Vector2(19, 19 * this.canvas.height/this.canvas.width),
                    new Vector2(19*2, 19*2 * this.canvas.height/this.canvas.width)
                );

            // constraint:
            // - keep input position in world and mouse on screen in sync
            // old, fast version
            bbb.always({
                solver: new DBPlanner(),
                ctx: {
                    input: input,
                    viewport: viewport
                },
                methods: function() {
                    input.position.formula([input.mouse, input.mouse.x, input.mouse.y], function(mouse, mouseX, mouseY) {
                        return viewport.screenToWorldCoordinates(mouse);
                    });
                }
            }, function() {
                return input.position.equals(viewport.screenToWorldCoordinates(input.mouse));
            });

/*
            // new clean but slow version using automatic inference of formulas
            always: {
                solver: new DBPlanner()
                input.position.equals(viewport.screenToWorldCoordinates(input.mouse))
            }
*/
        },
        constrainDebugLayer: function() {
            var input = this.input;

            // constraint: debugdraw velocities if debug mode is switched on
            DebugLayer.activeOn({
                ctx: {
                    input: input
                }
            }, function() {
                return input.switchedOn("debug");
            });

            GameLayer.activeOn({
                ctx: {
                    input: input
                }
            }, function() {
                return input.switchedOff("pause");
            });
        },
        prepare: function() {
            this.resetLevel();
        },
        resetLevel: function() {
            this.createLevel(this.levels.get());
        },
        nextLevel: function() {
            this.createLevel(this.levels.next());
        },
        createLevel: function(level) {
            this.cleanUp();
            var builder = new WorldBuilder(this);
            this.world = builder.buildWorld(level);

            this.gui = new Gui(this.world, this.input, player, this.viewport);
            this.editor = this.editor || new Editor(this);
        },
        cleanUp: function() {
            // TODO
        },
        update: function(dt) {
            this.updatePhysics(dt);
            this.gui.update(dt);
            this.draw();

            this.input.clearPressed();
        },
        draw: function() {
            this.renderer.clear();
            this.renderer.withViewport(this.viewport, (function() {
                this.world.draw(this.renderer);
            }).bind(this));
            this.gui.draw(this.renderer);
        }
    });

    GameLayer = new Layer()
        .refineClass(Game, {
            updatePhysics: function(dt) {
                this.world.update(dt);
            }
        });

    EditorLayer = new Layer()
        .refineClass(Game, {
            updatePhysics: function(dt) {
                this.world.getGameObjects()
                    .filter(function(gameObject) {
                        return gameObject.controls && gameObject.controls.getTargetTiles;
                    })
                    .each(function(gameObject) {
                        gameObject.controls.getTargetTiles();
                    });
                this.editor.update(dt);
            },
            draw: function() {
                // draw world transparently
                this.renderer.configuration.setGlobalAlpha(0.7);
                cop.proceed();
                this.renderer.configuration.setGlobalAlpha(1);

                this.renderer.drawLine({x:0, y:0}, this.input.mouse, "red", 1, 300);
                this.renderer.withViewport(this.viewport, (function() {
                    this.editor.draw(this.renderer);
                }).bind(this));
            }
        });

    return Game;
});
<commit_msg>removed debug line<commit_after>define([
    "./../input",
    "./../gui",
    "./../view/viewport",
    "./../world/worldbuilder",
    "./../rendering/renderer",
    "./../game/debuglayer",
    "./editor"
], function Game(
    Input,
    Gui,
    Viewport,
    WorldBuilder,
    Renderer,
    DebugLayer,
    Editor
) {
    var Game = Object.subclass("Game", {
        initialize: function(canvasId) {
            //TODO: delegate to dedicated builder/factory functions
            this.buildCanvas(canvasId);
            this.buildInput(canvasId);
            this.renderer = new Renderer(this.canvas);
            this.buildViewport();
            this.constrainDebugLayer();
            this.levels = new LevelPointer();
        },
        buildCanvas: function(canvasId) {
            this.canvas = document.getElementById(canvasId);
            this.canvas.style.position = "absolute";
            this.canvas.style.top = "0px";
            this.canvas.style.left = "0px";
            this.canvas.style["z-index"] = -1;
        },
        buildInput: function(canvasId) {
            this.input = new Input(canvasId);

            _.each({
                W: "up",
                A: "left",
                S: "down",
                D: "right",

                UP_ARROW: "up",
                LEFT_ARROW: "left",
                DOWN_ARROW: "down",
                RIGHT_ARROW: "right",

                MOUSE1: "leftclick",
                MOUSE2: "rightclick",
                MWHEEL_UP: "zoomIn",
                MWHEEL_DOWN: "zoomOut",

                O: "debug",
                P: "pause"
            }, function(state, key){
                this.input.bind(Input.KEY[key], state);
            }, this);
        },
        buildViewport: function() {
            var input = this.input,
                // TODO: find correct domain, also adjust debug targeting tiles
                viewport = this.viewport = new Viewport(
                    new Vector2(19, 19 * this.canvas.height/this.canvas.width),
                    new Vector2(19*2, 19*2 * this.canvas.height/this.canvas.width)
                );

            // constraint:
            // - keep input position in world and mouse on screen in sync
            // old, fast version
            bbb.always({
                solver: new DBPlanner(),
                ctx: {
                    input: input,
                    viewport: viewport
                },
                methods: function() {
                    input.position.formula([input.mouse, input.mouse.x, input.mouse.y], function(mouse, mouseX, mouseY) {
                        return viewport.screenToWorldCoordinates(mouse);
                    });
                }
            }, function() {
                return input.position.equals(viewport.screenToWorldCoordinates(input.mouse));
            });

/*
            // new clean but slow version using automatic inference of formulas
            always: {
                solver: new DBPlanner()
                input.position.equals(viewport.screenToWorldCoordinates(input.mouse))
            }
*/
        },
        constrainDebugLayer: function() {
            var input = this.input;

            // constraint: debugdraw velocities if debug mode is switched on
            DebugLayer.activeOn({
                ctx: {
                    input: input
                }
            }, function() {
                return input.switchedOn("debug");
            });

            GameLayer.activeOn({
                ctx: {
                    input: input
                }
            }, function() {
                return input.switchedOff("pause");
            });
        },
        prepare: function() {
            this.resetLevel();
        },
        resetLevel: function() {
            this.createLevel(this.levels.get());
        },
        nextLevel: function() {
            this.createLevel(this.levels.next());
        },
        createLevel: function(level) {
            this.cleanUp();
            var builder = new WorldBuilder(this);
            this.world = builder.buildWorld(level);

            this.gui = new Gui(this.world, this.input, player, this.viewport);
            this.editor = this.editor || new Editor(this);
        },
        cleanUp: function() {
            // TODO
        },
        update: function(dt) {
            this.updatePhysics(dt);
            this.gui.update(dt);
            this.draw();

            this.input.clearPressed();
        },
        draw: function() {
            this.renderer.clear();
            this.renderer.withViewport(this.viewport, (function() {
                this.world.draw(this.renderer);
            }).bind(this));
            this.gui.draw(this.renderer);
        }
    });

    GameLayer = new Layer()
        .refineClass(Game, {
            updatePhysics: function(dt) {
                this.world.update(dt);
            }
        });

    EditorLayer = new Layer()
        .refineClass(Game, {
            updatePhysics: function(dt) {
                this.world.getGameObjects()
                    .filter(function(gameObject) {
                        return gameObject.controls && gameObject.controls.getTargetTiles;
                    })
                    .each(function(gameObject) {
                        gameObject.controls.getTargetTiles();
                    });
                this.editor.update(dt);
            },
            draw: function() {
                // draw world transparently
                this.renderer.configuration.setGlobalAlpha(0.7);
                cop.proceed();
                this.renderer.configuration.setGlobalAlpha(1);

                this.renderer.withViewport(this.viewport, (function() {
                    this.editor.draw(this.renderer);
                }).bind(this));
            }
        });

    return Game;
});
<|endoftext|>


<commit_before>const path = require('path')
const {ifAnyDep, fromRoot} = require('../utils')

const here = p => path.join(__dirname, p)

const ignores = [
  '/node_modules/',
  '/fixtures/',
  '/__tests__/helpers/',
  '__mocks__',
]

module.exports = {
  roots: [fromRoot('src')],
  testEnvironment: ifAnyDep(['webpack', 'rollup', 'react'], 'jsdom', 'node'),
  collectCoverageFrom: ['src/**/*.js'],
  testMatch: ['**/__tests__/**/*.js'],
  testPathIgnorePatterns: ignores,
  coveragePathIgnorePatterns: ignores,
  transform: {
    '^.+\\.js$': here('./babel-transform'),
  },
  transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'],
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },
}
<commit_msg>fix(jest): make jest transform apply only when no babel config<commit_after>const path = require('path')
const {ifAnyDep, hasFile, hasPkgProp, fromRoot} = require('../utils')

const here = p => path.join(__dirname, p)

const useBuiltInBabelConfig = !hasFile('.babelrc') && !hasPkgProp('babel')

const ignores = [
  '/node_modules/',
  '/fixtures/',
  '/__tests__/helpers/',
  '__mocks__',
]

const jestConfig = {
  roots: [fromRoot('src')],
  testEnvironment: ifAnyDep(['webpack', 'rollup', 'react'], 'jsdom', 'node'),
  collectCoverageFrom: ['src/**/*.js'],
  testMatch: ['**/__tests__/**/*.js'],
  testPathIgnorePatterns: ignores,
  coveragePathIgnorePatterns: ignores,
  transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'],
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },
}

if (useBuiltInBabelConfig) {
  jestConfig.transform = {'^.+\\.js$': here('./babel-transform')}
}

module.exports = jestConfig
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { click, fillIn, find, visit, currentURL, triggerEvent, focus } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import Fixtures from '@cardstack/test-support/fixtures';
import {
  addField,
  setCardId,
  createCards,
  saveCard,
  dragAndDropNewField,
  removeField,
} from '@cardstack/test-support/card-ui-helpers';
import { setupMockUser, login } from '../helpers/login';
import { percySnapshot } from 'ember-percy';
import { animationsSettled } from 'ember-animated/test-support';

const card1Id = 'millenial-puppies';
const qualifiedCard1Id = `local-hub::${card1Id}`;

const scenario = new Fixtures({
  create(factory) {
    setupMockUser(factory);
  },
  destroy() {
    return [{ type: 'cards', id: qualifiedCard1Id }];
  },
});

module('Acceptance | card create', function(hooks) {
  setupApplicationTest(hooks);
  scenario.setupTest(hooks);
  hooks.beforeEach(function() {
    this.owner.lookup('service:data')._clearCache();
  });

  test('new cards get a default id', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    await saveCard('creator');

    assert.ok(currentURL().match(/\/cards\/new-card-[0-9]+\/schema/));
  });

  test('card element is selected on initial render', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    assert.dom('[data-test-card-renderer-isolated]').hasClass('selected');
  });

  test('right edge shows base card as adopted from card', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    assert.dom('[data-test-right-edge] [data-test-adopted-card-name').hasText('Base Card');
    assert.dom('[data-test-right-edge] [data-test-adopted-card-adopted-card-name').doesNotExist();
  });

  test("changing a card's id does not clear the card fields", async function(assert) {
    await login();
    await visit('/cards/new');

    await addField('title', 'string', true);
    await setCardId(card1Id);
    assert.deepEqual(
      [...document.querySelectorAll(`[data-test-isolated-card="${card1Id}"] [data-test-field]`)].map(i =>
        i.getAttribute('data-test-field')
      ),
      ['title']
    );
  });

  test('creating a card', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');
    await percySnapshot(assert + '-new');

    assert.dom('.card-renderer-isolated--header').hasTextContaining('new-card-');
    assert.dom('[data-test-internal-card-id]').hasTextContaining('local-hub::new-card-');

    await createCards({
      [card1Id]: [
        ['title', 'string', true],
        ['body', 'string', false],
        ['author', 'related card', true],
        ['reviewers', 'related cards', true],
      ],
    });

    assert.equal(currentURL(), `/cards/${card1Id}`);
    await visit(`/cards/${card1Id}/schema`);
    assert.dom('.card-renderer-isolated--header').hasText('millenial-puppies');
    assert.dom('[data-test-internal-card-id]').hasText('local-hub::millenial-puppies');

    await click('[data-test-field="title"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="title"]').hasClass('selected');
    assert.dom('[data-test-field="title"] [data-test-field-renderer-type]').hasText('title (Text)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await click('[data-test-field="body"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="body"]').hasClass('selected');
    assert.dom('[data-test-field="body"] [data-test-field-renderer-type]').hasText('body (Text)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isNotChecked();

    await click('[data-test-field="author"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="author"]').hasClass('selected');
    assert.dom('[data-test-field="author"] [data-test-field-renderer-type]').hasText('author (Single-select)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await click('[data-test-field="reviewers"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="reviewers"]').hasClass('selected');
    assert.dom('[data-test-field="reviewers"] [data-test-field-renderer-type]').hasText('reviewers (Multi-select)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await focus('[data-test-card-renderer-isolated]');
    await animationsSettled();
    assert.dom('.card-renderer-isolated--header').hasText('millenial-puppies');
    assert.dom('[data-test-internal-card-id]').hasText('local-hub::millenial-puppies');
    // TODO: figure out why having the following assertions before the line above ^^^ causes a test failure
    assert.dom('[data-test-card-renderer-isolated]').hasClass('selected');
    assert.dom('.field-renderer').doesNotHaveClass('selected');

    let cardJson = find('[data-test-code-block]').getAttribute('data-test-code-block');
    let card = JSON.parse(cardJson);
    assert.equal(card.data.attributes.title, undefined);
    assert.equal(card.data.attributes.body, undefined);
    assert.equal(card.data.relationships.author, undefined);
    assert.deepEqual(card.data.relationships.reviewers, undefined);
    await percySnapshot(assert + '-data-entered');
  });

  test(`selecting a field`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);
    await addField('body', 'string', false);
    await animationsSettled();

    await click('[data-test-field="title"]');
    await animationsSettled();
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('title');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="name"] input', 'subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="name"] input`, 'keyup');
    await animationsSettled();
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="label"] input', 'Subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="label"] input`, 'keyup');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('Subtitle');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea', 'This is the subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="instructions"] textarea`, 'keyup');
    assert
      .dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea')
      .hasValue('This is the subtitle');

    await click('[data-test-field="body"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="body"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('body');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('body');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea').hasValue('');

    await click('[data-test-field="subtitle"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="subtitle"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('Subtitle');
    assert
      .dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea')
      .hasValue('This is the subtitle');

    await dragAndDropNewField('string');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="new-field-2"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('new-field-2');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('new-field-2');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea').hasValue('');
    await percySnapshot(assert);
  });

  test(`renaming a card's field`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('title');
    await fillIn('[data-test-schema-attr="name"] input', 'subtitle');
    await triggerEvent('[data-test-schema-attr="name"] input', 'keyup');

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('subtitle');

    await saveCard('creator', card1Id);

    assert.equal(currentURL(), `/cards/${card1Id}/schema`);

    await visit(`/cards/${card1Id}`);
    assert.dom('[data-test-field="subtitle"] [data-test-string-field-viewer-label]').hasText('subtitle');
    assert.dom('[data-test-field="title"]').doesNotExist();

    await visit(`/cards/${card1Id}/edit`);
    assert.dom('[data-test-field="subtitle"] [data-test-cs-component-label="text-field"]').hasText('subtitle');
    assert.dom('[data-test-field="title"]').doesNotExist();

    await visit(`/cards/${card1Id}/schema`);
    assert.dom('[data-test-field="subtitle"] [data-test-field-renderer-label]').hasText('subtitle');
    await click('[data-test-field="subtitle"]');

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('subtitle');
  });

  test(`removing a field from a card`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);

    await removeField('title');

    assert.dom('.cardhost-right-edge-panel [data-test-field]').doesNotExist();
    await percySnapshot(assert);
  });

  test(`removing a field from a card that has an empty name`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('', 'string', true);
    assert.dom('[data-test-isolated-card] [data-test-field').exists({ count: 1 });

    await click(`[data-test-isolated-card] [data-test-field-renderer-remove-btn]`);
    assert.dom('[data-test-isolated-card] [data-test-field').doesNotExist();
  });

  test('can add a field at a particular position', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);
    await addField('body', 'string', false, 1);
    await addField('author', 'string', false, 1);

    assert.deepEqual(
      [...document.querySelectorAll(`[data-test-isolated-card="${card1Id}"] [data-test-field]`)].map(i =>
        i.getAttribute('data-test-field')
      ),
      ['title', 'author', 'body']
    );

    await saveCard('creator', card1Id);

    await visit(`/cards/${card1Id}`);
    assert.deepEqual(
      [...document.querySelectorAll('[data-test-field]')].map(i => i.getAttribute('data-test-field')),
      ['title', 'author', 'body']
    );
    let cardJson = find('[data-test-code-block]').getAttribute('data-test-code-block');
    let card = JSON.parse(cardJson);
    assert.deepEqual(card.data.relationships.fields.data, [
      { type: 'fields', id: 'title' },
      { type: 'fields', id: 'author' },
      { type: 'fields', id: 'body' },
    ]);
  });
});
<commit_msg>better names for percy snapshots<commit_after>import { module, test } from 'qunit';
import { click, fillIn, find, visit, currentURL, triggerEvent, focus } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import Fixtures from '@cardstack/test-support/fixtures';
import {
  addField,
  setCardId,
  createCards,
  saveCard,
  dragAndDropNewField,
  removeField,
} from '@cardstack/test-support/card-ui-helpers';
import { setupMockUser, login } from '../helpers/login';
import { percySnapshot } from 'ember-percy';
import { animationsSettled } from 'ember-animated/test-support';

const card1Id = 'millenial-puppies';
const qualifiedCard1Id = `local-hub::${card1Id}`;

const scenario = new Fixtures({
  create(factory) {
    setupMockUser(factory);
  },
  destroy() {
    return [{ type: 'cards', id: qualifiedCard1Id }];
  },
});

module('Acceptance | card create', function(hooks) {
  setupApplicationTest(hooks);
  scenario.setupTest(hooks);
  hooks.beforeEach(function() {
    this.owner.lookup('service:data')._clearCache();
  });

  test('new cards get a default id', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    await saveCard('creator');

    assert.ok(currentURL().match(/\/cards\/new-card-[0-9]+\/schema/));
  });

  test('card element is selected on initial render', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    assert.dom('[data-test-card-renderer-isolated]').hasClass('selected');
  });

  test('right edge shows base card as adopted from card', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    assert.dom('[data-test-right-edge] [data-test-adopted-card-name').hasText('Base Card');
    assert.dom('[data-test-right-edge] [data-test-adopted-card-adopted-card-name').doesNotExist();
  });

  test("changing a card's id does not clear the card fields", async function(assert) {
    await login();
    await visit('/cards/new');

    await addField('title', 'string', true);
    await setCardId(card1Id);
    assert.deepEqual(
      [...document.querySelectorAll(`[data-test-isolated-card="${card1Id}"] [data-test-field]`)].map(i =>
        i.getAttribute('data-test-field')
      ),
      ['title']
    );
  });

  test('creating a card', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');
    await percySnapshot([assert.test.module.name, assert.test.testName, 'new'].join(' | '));

    assert.dom('.card-renderer-isolated--header').hasTextContaining('new-card-');
    assert.dom('[data-test-internal-card-id]').hasTextContaining('local-hub::new-card-');

    await createCards({
      [card1Id]: [
        ['title', 'string', true],
        ['body', 'string', false],
        ['author', 'related card', true],
        ['reviewers', 'related cards', true],
      ],
    });

    assert.equal(currentURL(), `/cards/${card1Id}`);
    await visit(`/cards/${card1Id}/schema`);
    assert.dom('.card-renderer-isolated--header').hasText('millenial-puppies');
    assert.dom('[data-test-internal-card-id]').hasText('local-hub::millenial-puppies');

    await click('[data-test-field="title"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="title"]').hasClass('selected');
    assert.dom('[data-test-field="title"] [data-test-field-renderer-type]').hasText('title (Text)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await click('[data-test-field="body"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="body"]').hasClass('selected');
    assert.dom('[data-test-field="body"] [data-test-field-renderer-type]').hasText('body (Text)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isNotChecked();

    await click('[data-test-field="author"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="author"]').hasClass('selected');
    assert.dom('[data-test-field="author"] [data-test-field-renderer-type]').hasText('author (Single-select)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await click('[data-test-field="reviewers"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="reviewers"]').hasClass('selected');
    assert.dom('[data-test-field="reviewers"] [data-test-field-renderer-type]').hasText('reviewers (Multi-select)');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="embedded"] input').isChecked();

    await focus('[data-test-card-renderer-isolated]');
    await animationsSettled();
    assert.dom('.card-renderer-isolated--header').hasText('millenial-puppies');
    assert.dom('[data-test-internal-card-id]').hasText('local-hub::millenial-puppies');
    // TODO: figure out why having the following assertions before the line above ^^^ causes a test failure
    assert.dom('[data-test-card-renderer-isolated]').hasClass('selected');
    assert.dom('.field-renderer').doesNotHaveClass('selected');

    let cardJson = find('[data-test-code-block]').getAttribute('data-test-code-block');
    let card = JSON.parse(cardJson);
    assert.equal(card.data.attributes.title, undefined);
    assert.equal(card.data.attributes.body, undefined);
    assert.equal(card.data.relationships.author, undefined);
    assert.deepEqual(card.data.relationships.reviewers, undefined);
    await percySnapshot([assert.test.module.name, assert.test.testName, 'data-entered'].join(' | '));
  });

  test(`selecting a field`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);
    await addField('body', 'string', false);
    await animationsSettled();

    await click('[data-test-field="title"]');
    await animationsSettled();
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('title');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="name"] input', 'subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="name"] input`, 'keyup');
    await animationsSettled();
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="label"] input', 'Subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="label"] input`, 'keyup');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('Subtitle');

    await fillIn('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea', 'This is the subtitle');
    await triggerEvent(`[data-test-right-edge] [data-test-schema-attr="instructions"] textarea`, 'keyup');
    assert
      .dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea')
      .hasValue('This is the subtitle');

    await click('[data-test-field="body"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="body"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('body');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('body');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea').hasValue('');

    await click('[data-test-field="subtitle"] [data-test-field-schema-renderer]');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="subtitle"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('Subtitle');
    assert
      .dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea')
      .hasValue('This is the subtitle');

    await dragAndDropNewField('string');
    assert.dom('[data-test-isolated-card="millenial-puppies"] [data-test-field="new-field-2"]').hasClass('selected');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('new-field-2');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('new-field-2');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="instructions"] textarea').hasValue('');
    await percySnapshot(assert);
  });

  test(`renaming a card's field`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('title');
    await fillIn('[data-test-schema-attr="name"] input', 'subtitle');
    await triggerEvent('[data-test-schema-attr="name"] input', 'keyup');

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('subtitle');

    await saveCard('creator', card1Id);

    assert.equal(currentURL(), `/cards/${card1Id}/schema`);

    await visit(`/cards/${card1Id}`);
    assert.dom('[data-test-field="subtitle"] [data-test-string-field-viewer-label]').hasText('subtitle');
    assert.dom('[data-test-field="title"]').doesNotExist();

    await visit(`/cards/${card1Id}/edit`);
    assert.dom('[data-test-field="subtitle"] [data-test-cs-component-label="text-field"]').hasText('subtitle');
    assert.dom('[data-test-field="title"]').doesNotExist();

    await visit(`/cards/${card1Id}/schema`);
    assert.dom('[data-test-field="subtitle"] [data-test-field-renderer-label]').hasText('subtitle');
    await click('[data-test-field="subtitle"]');

    assert.dom('[data-test-right-edge] [data-test-schema-attr="name"] input').hasValue('subtitle');
    assert.dom('[data-test-right-edge] [data-test-schema-attr="label"] input').hasValue('subtitle');
  });

  test(`removing a field from a card`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);

    await removeField('title');

    assert.dom('.cardhost-right-edge-panel [data-test-field]').doesNotExist();
    await percySnapshot(assert);
  });

  test(`removing a field from a card that has an empty name`, async function(assert) {
    await login();
    await visit('/cards/new');

    await setCardId(card1Id);
    await addField('', 'string', true);
    assert.dom('[data-test-isolated-card] [data-test-field').exists({ count: 1 });

    await click(`[data-test-isolated-card] [data-test-field-renderer-remove-btn]`);
    assert.dom('[data-test-isolated-card] [data-test-field').doesNotExist();
  });

  test('can add a field at a particular position', async function(assert) {
    await login();
    await visit('/cards/new');

    assert.equal(currentURL(), '/cards/new');

    await setCardId(card1Id);
    await addField('title', 'string', true);
    await addField('body', 'string', false, 1);
    await addField('author', 'string', false, 1);

    assert.deepEqual(
      [...document.querySelectorAll(`[data-test-isolated-card="${card1Id}"] [data-test-field]`)].map(i =>
        i.getAttribute('data-test-field')
      ),
      ['title', 'author', 'body']
    );

    await saveCard('creator', card1Id);

    await visit(`/cards/${card1Id}`);
    assert.deepEqual(
      [...document.querySelectorAll('[data-test-field]')].map(i => i.getAttribute('data-test-field')),
      ['title', 'author', 'body']
    );
    let cardJson = find('[data-test-code-block]').getAttribute('data-test-code-block');
    let card = JSON.parse(cardJson);
    assert.deepEqual(card.data.relationships.fields.data, [
      { type: 'fields', id: 'title' },
      { type: 'fields', id: 'author' },
      { type: 'fields', id: 'body' },
    ]);
  });
});
<|endoftext|>


<commit_before>(function () {
    dc.choroplethChart = function (parent, chartGroup) {
        var _chart = dc.colorMixin(dc.baseMixin({}));

        // PROPERTIES
        var _layers = {},
            _graticule = d3.geo.graticule(),
            _projection = d3.geo.mercator(),
            _previousProjection = d3.geo.mercator(),
            _path = d3.geo.path().projection(_projection),
            _projectionZoom = function (path, features, height, width, scale) {
                // Reset scale & translate
                path.projection().scale(1).translate([0, 0]);
                // Calculate new position
                var b = path.bounds(features),
                    s = (scale || 0.95) / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
                    t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
                return path.projection().scale(s).translate(t);
            },
            _title = function (layerName, data, titleFn) {
                return function (d) {
                    var key = getKey(layerName, d),
                        value = data[key];
                    return titleFn({key: key, value: value});
                };
            },
            _layeredData = function (data) {
                return data.reduce(function (previous, current) {
                    previous[_chart.keyAccessor()(current)] = _chart.valueAccessor()(current);
                    return previous;
                }, {});
            },
            _interpolatedProjection = function (a, b) {
                var projection = d3.geo.projection(function (λ, φ) {
                        var pa = a([λ *= 180 / Math.PI, φ *= 180 / Math.PI]), pb = b([λ, φ]);
                        return [(1 - α) * pa[0] + α * pb[0], (α - 1) * pa[1] - α * pb[1]];
                    }).scale(1),
                    center = projection.center,
                    translate = projection.translate,
                    α;

                projection.alpha = function (_) {
                    if (!arguments.length) {
                        return α;
                    }
                    α = +_;
                    var ca = a.center(), cb = b.center(),
                        ta = a.translate(), tb = b.translate();
                    center([(1 - α) * ca[0] + α * cb[0], (1 - α) * ca[1] + α * cb[1]]);
                    translate([(1 - α) * ta[0] + α * tb[0], (1 - α) * ta[1] + α * tb[1]]);
                    return projection;
                };

                delete projection.scale;
                delete projection.translate;
                delete projection.center;
                return projection.alpha(0);
            };

        // DEFAULTS
        _chart.colorAccessor(function (d) {
            return d || 0;
        });

        function projectionTween(projection0, projection1) {

        }

        // LAYER ACCESSORS
        function layerClass(layerName) {
            return "layer-" + layerName;
        }

        function layerSelector(layerName) {
            return "g.layer-" + layerName;
        }

        function isSelected(layerName, d) {
            return _chart.hasFilter() && _chart.hasFilter(getKey(layerName, d));
        }

        function isDeselected(layerName, d) {
            return _chart.hasFilter() && !_chart.hasFilter(getKey(layerName, d));
        }

        function isDataLayer(layerName) {
            return getLayer(layerName).keyAccessor;
        }

        function getKey(layerName, d) {
            return getLayer(layerName).keyAccessor(d);
        }

        function getFeatures(layerName) {
            return getLayer(layerName).features;
        }

        function getLayer(layerName) {
            return _layers[layerName];
        }

        _chart.layers = function () {
            return _layers;
        }

        _chart.addLayer = function (features, name, keyAccessor) {
            _layers[name] = {
                features: features,
                name: name,
                keyAccessor: keyAccessor
            };
            return _chart;
        };

        _chart.removeLayer = function (name) {
            delete _layers[name];
        };

        // PROJECTION & PATH
        _chart.path = function () {
            return _path;
        }

        _chart.projection = function (_) {
            if (!arguments.length) {
                return _projection;
            }
            _previousProjection = _projection;
            _projection = _;
            _path.projection(_projection);
            // TODO ADD BACK
            // _path.projection(_interpolatedProjection(_previousProjection, _projection));
            return _chart;
        };

        _chart.projectionZoom = function (_) {
            if (!arguments.length) {
                return _projectionZoom;
            }
            _projectionZoom = _;
            return _chart;
        }

        // PLOT
        _chart._doRedraw = function () {
            var data = _layeredData(_chart.data());

            _chart.svg().select('.graticule').datum(_graticule).attr("d", _path);

            for (var layerName in _layers) {
                // Select layer
                var layerG = _chart.svg().selectAll(layerSelector(layerName));

                // Select path
                var pathG = layerG.selectAll("path")
                    .data(getLayer(layerName).features);

                // Add enter items
                pathG.enter()
                    .append("path")
                    .attr("fill", "white")
                    .attr("d", _path)
                    .on("click", function (d) {
                        return _chart.onClick(d, layerName);
                    }).append("title");

                // Set selected color function
                var hasData = isDataLayer(layerName);
                pathG.classed("selected", hasData ? function (d) { return isSelected(layerName, d); } :
                    function () { return false; })
                    .classed("deselected", hasData ? function (d) { return isDeselected(layerName, d); } :
                    function () { return false; });

                // Update color
                dc.transition(pathG, _chart.transitionDuration()).attr("fill", function (d, i) {
                    return _chart.getColor(data[getKey(layerName, d)], i);
                });

                // Update path
                //pathG.attr("d", _path);
                // dc.transition(pathG, _chart.transitionDuration()).attr("d", function (d, i) {
                //     return _chart.getColor(data[getKey(layerName, d)], i);
                // });

                // TODO Transition projection

                layerG.selectAll("path title").text(_chart.renderTitle() ?
                    _title(layerName, data, _chart.title()) : function () { return ""; });
            }
        }

        _chart._doRender = function () {
            _chart.resetSvg();
            _chart.svg().append("path").attr("class", "graticule")
            for (var layerName in _layers) {
                _chart.svg().append("g").attr("class", layerClass(layerName));
            }
            _chart._doRedraw();
        };

        _chart.onClick = function (d, layerIndex) {
            var selectedRegion = getLayer(layerIndex).keyAccessor(d);
            dc.events.trigger(function () {
                _chart.filter(selectedRegion);
                _chart.redrawGroup();
            });
        };

        return _chart.anchor(parent, chartGroup);
    };
})();<commit_msg>updates to choropleth<commit_after>(function () {
    dc.choroplethChart = function (parent, chartGroup) {
        var _chart = dc.colorMixin(dc.baseMixin({}));

        function interpolatedProjection(a, b) {
            var α = 0,
                projection = d3.geo.projection(function (λ, φ) {
                    λ *= 180 / Math.PI;
                    φ *= 180 / Math.PI;
                    var pa = a([λ, φ]),
                        pb = b([λ, φ]);
                    return [(1 - α) * pa[0] + α * pb[0], (α - 1) * pa[1] - α * pb[1]];
                }).scale(1),
                center = projection.center,
                translate = projection.translate;

            projection.alpha = function (_) {
                if (!arguments.length) {
                    return α;
                }
                α = +_;
                var ca = a.center(),
                    cb = b.center(),
                    ta = a.translate(),
                    tb = b.translate();
                center([(1 - α) * ca[0] + α * cb[0], (1 - α) * ca[1] + α * cb[1]]);
                translate([(1 - α) * ta[0] + α * tb[0], (1 - α) * ta[1] + α * tb[1]]);
                return projection;
            };

            delete projection.scale;
            delete projection.translate;
            delete projection.center;
            return projection.alpha(0);
        }

        // PROPERTIES
        var _layers = {},
            _graticule = d3.geo.graticule(),
            _projection = d3.geo.equirectangular(),
            _previousProjection = d3.geo.orthographic(),
            _path = d3.geo.path().projection(_projection),
            _projectionZoom = function (path, features, height, width, scale) {
                // Reset scale & translate
                path.projection().scale(1).translate([0, 0]);
                // Calculate new position
                var b = path.bounds(features),
                    s = (scale || 0.95) / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
                    t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
                return path.projection().scale(s).translate(t);
            },
            _title = function (layerName, data, titleFn) {
                return function (d) {
                    var key = getKey(layerName, d),
                        value = data[key];
                    return titleFn({key: key, value: value});
                };
            },
            _layeredData = function (data) {
                return data.reduce(function (previous, current) {
                    previous[_chart.keyAccessor()(current)] = _chart.valueAccessor()(current);
                    return previous;
                }, {});
            };

        // DEFAULTS
        _chart.colorAccessor(function (d) {
            return d || 0;
        });

        // LAYER ACCESSORS
        function layerClass(layerName) {
            return "layer-" + layerName;
        }

        function layerSelector(layerName) {
            return "g.layer-" + layerName;
        }

        function isSelected(layerName, d) {
            return _chart.hasFilter() && _chart.hasFilter(getKey(layerName, d));
        }

        function isDeselected(layerName, d) {
            return _chart.hasFilter() && !_chart.hasFilter(getKey(layerName, d));
        }

        function isDataLayer(layerName) {
            return getLayer(layerName).keyAccessor;
        }

        function getKey(layerName, d) {
            return getLayer(layerName).keyAccessor(d);
        }

        function getFeatures(layerName) {
            return getLayer(layerName).features;
        }

        function getLayer(layerName) {
            return _layers[layerName];
        }

        _chart.layers = function () {
            return _layers;
        }

        _chart.addLayer = function (features, name, keyAccessor) {
            _layers[name] = {
                features: features,
                name: name,
                keyAccessor: keyAccessor
            };
            return _chart;
        };

        _chart.removeLayer = function (name) {
            delete _layers[name];
        };

        // PROJECTION & PATH
        _chart.path = function () {
            return _path;
        }

        _chart.projection = function (_) {
            if (!arguments.length) {
                return _projection;
            }
            _previousProjection = _projection;
            _projection = _;
            _path.projection(interpolatedProjection(_previousProjection, _projection));
            return _chart;
        };

        _chart.projectionZoom = function (_) {
            if (!arguments.length) {
                return _projectionZoom;
            }
            _projectionZoom = _;
            return _chart;
        }

        // PLOT
        _chart._doRedraw = function () {
            var data = _layeredData(_chart.data());

            for (var layerName in _layers) {
                // Select layer
                var layerG = _chart.svg().selectAll(layerSelector(layerName));

                // Select path
                var pathG = layerG.selectAll("path").data(getLayer(layerName).features);

                // Add enter items
                pathG.enter().append("path")
                    .attr("fill", "white")
                    .attr("d", _path)
                    .on("click", function (d) {
                        return _chart.onClick(d, layerName);
                    }).append("title");

                // Set selected color function
                var hasData = isDataLayer(layerName);
                pathG.classed("selected", hasData ? function (d) { return isSelected(layerName, d); } :
                    function () { return false; })
                    .classed("deselected", hasData ? function (d) { return isDeselected(layerName, d); } :
                    function () { return false; });

                // Update color
                dc.transition(pathG, _chart.transitionDuration()).attr("fill", function (d, i) {
                    return _chart.getColor(data[getKey(layerName, d)], i);
                });

                // Update title
                layerG.selectAll("path title").text(_chart.renderTitle() ?
                    _title(layerName, data, _chart.title()) : function () { return ""; });
            }

            // Update Paths
            if (_path.projection().alpha) {
                var paths = _chart.svg().selectAll("path");
                dc.transition(paths, _chart.transitionDuration()).attrTween("d", function () {
                    return function (_) {
                        _path.projection().alpha(_);
                        return _path;
                    };
                });
            }
        }

        _chart._doRender = function () {
            _chart.resetSvg();
            _chart.svg().append("path").attr("class", "graticule").datum(_graticule).attr('d', _path);
            for (var layerName in _layers) {
                _chart.svg().append("g").attr("class", layerClass(layerName));
            }
            _chart._doRedraw();
        };

        _chart.onClick = function (d, layerIndex) {
            var selectedRegion = getLayer(layerIndex).keyAccessor(d);
            dc.events.trigger(function () {
                _chart.filter(selectedRegion);
                _chart.redrawGroup();
            });
        };

        return _chart.anchor(parent, chartGroup);
    };
})();<|endoftext|>