<commit_before>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.BaseComponent = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";

// class/component rules
// always call super() first in the ctor. This also calls the extended class' ctor.
// cannot call NEW on a Component class

// Classes http://exploringjs.com/es6/ch_classes.html#_the-species-pattern-in-static-methods

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var _on = require('on');
var dom = require('dom');

var BaseComponent = function (_HTMLElement) {
	_inherits(BaseComponent, _HTMLElement);

	function BaseComponent() {
		_classCallCheck(this, BaseComponent);

		var _this = _possibleConstructorReturn(this, (BaseComponent.__proto__ || Object.getPrototypeOf(BaseComponent)).call(this));

		_this._uid = dom.uid(_this.localName);
		privates[_this._uid] = { DOMSTATE: 'created' };
		privates[_this._uid].handleList = [];
		plugin('init', _this);
		return _this;
	}

	_createClass(BaseComponent, [{
		key: 'connectedCallback',
		value: function connectedCallback() {
			privates[this._uid].DOMSTATE = privates[this._uid].domReadyFired ? 'domready' : 'connected';
			plugin('preConnected', this);
			nextTick(onCheckDomReady.bind(this));
			if (this.connected) {
				this.connected();
			}
			this.fire('connected');
			plugin('postConnected', this);
		}
	}, {
		key: 'disconnectedCallback',
		value: function disconnectedCallback() {
			privates[this._uid].DOMSTATE = 'disconnected';
			plugin('preDisconnected', this);
			if (this.disconnected) {
				this.disconnected();
			}
			this.fire('disconnected');

			var time = void 0,
			    doc = BaseComponent.destroyOnDisconnect;
			if (doc) {
				time = typeof doc === 'number' ? doc : 100;
				setTimeout(this.destroy.bind(this), time);
			}
		}
	}, {
		key: 'attributeChangedCallback',
		value: function attributeChangedCallback(attrName, oldVal, newVal) {
			plugin('preAttributeChanged', this, attrName, newVal, oldVal);
			if (this.attributeChanged) {
				this.attributeChanged(attrName, newVal, oldVal);
			}
		}
	}, {
		key: 'destroy',
		value: function destroy() {
			this.fire('destroy');
			privates[this._uid].handleList.forEach(function (handle) {
				handle.remove();
			});
			dom.destroy(this);
		}
	}, {
		key: 'fire',
		value: function fire(eventName, eventDetail, bubbles) {
			return _on.fire(this, eventName, eventDetail, bubbles);
		}
	}, {
		key: 'emit',
		value: function emit(eventName, value) {
			return _on.emit(this, eventName, value);
		}
	}, {
		key: 'on',
		value: function on(node, eventName, selector, callback) {
			return this.registerHandle(typeof node !== 'string' ? // no node is supplied
			_on(node, eventName, selector, callback) : _on(this, node, eventName, selector));
		}
	}, {
		key: 'once',
		value: function once(node, eventName, selector, callback) {
			return this.registerHandle(typeof node !== 'string' ? // no node is supplied
			_on.once(node, eventName, selector, callback) : _on.once(this, node, eventName, selector, callback));
		}
	}, {
		key: 'registerHandle',
		value: function registerHandle(handle) {
			privates[this._uid].handleList.push(handle);
			return handle;
		}
	}, {
		key: 'DOMSTATE',
		get: function get() {
			return privates[this._uid].DOMSTATE;
		}
	}], [{
		key: 'clone',
		value: function clone(template) {
			if (template.content && template.content.children) {
				return document.importNode(template.content, true);
			}
			var frag = document.createDocumentFragment(),
			    cloneNode = document.createElement('div');
			cloneNode.innerHTML = template.innerHTML;

			while (cloneNode.children.length) {
				frag.appendChild(cloneNode.children[0]);
			}
			return frag;
		}
	}, {
		key: 'addPlugin',
		value: function addPlugin(plug) {
			var i,
			    order = plug.order || 100;
			if (!plugins.length) {
				plugins.push(plug);
			} else if (plugins.length === 1) {
				if (plugins[0].order <= order) {
					plugins.push(plug);
				} else {
					plugins.unshift(plug);
				}
			} else if (plugins[0].order > order) {
				plugins.unshift(plug);
			} else {

				for (i = 1; i < plugins.length; i++) {
					if (order === plugins[i - 1].order || order > plugins[i - 1].order && order < plugins[i].order) {
						plugins.splice(i, 0, plug);
						return;
					}
				}
				// was not inserted...
				plugins.push(plug);
			}
		}
	}, {
		key: 'destroyOnDisconnect',
		set: function set(value) {
			privates['destroyOnDisconnect'] = value;
		},
		get: function get() {
			return privates['destroyOnDisconnect'];
		}
	}]);

	return BaseComponent;
}(HTMLElement);

var privates = {},
    plugins = [];

function plugin(method, node, a, b, c) {
	plugins.forEach(function (plug) {
		if (plug[method]) {
			plug[method](node, a, b, c);
		}
	});
}

function onCheckDomReady() {
	if (this.DOMSTATE !== 'connected' || privates[this._uid].domReadyFired) {
		return;
	}

	var count = 0,
	    children = getChildCustomNodes(this),
	    ourDomReady = onDomReady.bind(this);

	function addReady() {
		count++;
		if (count === children.length) {
			ourDomReady();
		}
	}

	// If no children, we're good - leaf node. Commence with onDomReady
	//
	if (!children.length) {
		ourDomReady();
	} else {
		// else, wait for all children to fire their `ready` events
		//
		children.forEach(function (child) {
			// check if child is already ready
			// also check for connected - this handles moving a node from another node
			if (child.DOMSTATE === 'domready' || child.DOMSTATE === 'connected') {
				addReady();
			}
			// if not, wait for event
			child.on('domready', addReady);
		});
	}
}

function onDomReady() {
	privates[this._uid].DOMSTATE = 'domready';
	// domReady should only ever fire once
	privates[this._uid].domReadyFired = true;
	plugin('preDomReady', this);
	// call this.domReady first, so that the component
	// can finish initializing before firing any
	// subsequent events
	if (this.domReady) {
		this.domReady();
		this.domReady = function () {};
	}

	this.fire('domready');

	plugin('postDomReady', this);
}

function getChildCustomNodes(node) {
	// collect any children that are custom nodes
	// used to check if their dom is ready before
	// determining if this is ready
	var i,
	    nodes = [];
	for (i = 0; i < node.children.length; i++) {
		if (node.children[i].nodeName.indexOf('-') > -1) {
			nodes.push(node.children[i]);
		}
	}
	return nodes;
}

function nextTick(cb) {
	requestAnimationFrame(cb);
}

window.onDomReady = function (node, callback) {
	function onReady() {
		callback(node);
		node.removeEventListener('domready', onReady);
	}

	if (node.DOMSTATE === 'domready') {
		callback(node);
	} else {
		node.addEventListener('domready', onReady);
	}
};

module.exports = BaseComponent;

},{"dom":"dom","on":"on"}]},{},[1])(1)
});<commit_msg>build<commit_after>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.BaseComponent = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";

// class/component rules
// always call super() first in the ctor. This also calls the extended class' ctor.
// cannot call NEW on a Component class

// Classes http://exploringjs.com/es6/ch_classes.html#_the-species-pattern-in-static-methods

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var _on = require('on');
var dom = require('dom');

var BaseComponent = function (_HTMLElement) {
	_inherits(BaseComponent, _HTMLElement);

	function BaseComponent() {
		_classCallCheck(this, BaseComponent);

		var _this = _possibleConstructorReturn(this, (BaseComponent.__proto__ || Object.getPrototypeOf(BaseComponent)).call(this));

		_this._uid = dom.uid(_this.localName);
		privates[_this._uid] = { DOMSTATE: 'created' };
		privates[_this._uid].handleList = [];
		plugin('init', _this);
		return _this;
	}

	_createClass(BaseComponent, [{
		key: 'connectedCallback',
		value: function connectedCallback() {
			privates[this._uid].DOMSTATE = privates[this._uid].domReadyFired ? 'domready' : 'connected';
			plugin('preConnected', this);
			nextTick(onCheckDomReady.bind(this));
			if (this.connected) {
				this.connected();
			}
			this.fire('connected');
			plugin('postConnected', this);
		}
	}, {
		key: 'disconnectedCallback',
		value: function disconnectedCallback() {
			var _this2 = this;

			privates[this._uid].DOMSTATE = 'disconnected';
			plugin('preDisconnected', this);
			if (this.disconnected) {
				this.disconnected();
			}
			this.fire('disconnected');

			var time = void 0,
			    dod = BaseComponent.destroyOnDisconnect;
			if (dod) {
				time = typeof doc === 'number' ? doc : 300;
				setTimeout(function () {
					if (_this2.DOMSTATE === 'disconnected') {
						_this2.destroy();
					}
				}, time);
			}
		}
	}, {
		key: 'attributeChangedCallback',
		value: function attributeChangedCallback(attrName, oldVal, newVal) {
			plugin('preAttributeChanged', this, attrName, newVal, oldVal);
			if (this.attributeChanged) {
				this.attributeChanged(attrName, newVal, oldVal);
			}
		}
	}, {
		key: 'destroy',
		value: function destroy() {
			this.fire('destroy');
			privates[this._uid].handleList.forEach(function (handle) {
				handle.remove();
			});
			dom.destroy(this);
		}
	}, {
		key: 'fire',
		value: function fire(eventName, eventDetail, bubbles) {
			return _on.fire(this, eventName, eventDetail, bubbles);
		}
	}, {
		key: 'emit',
		value: function emit(eventName, value) {
			return _on.emit(this, eventName, value);
		}
	}, {
		key: 'on',
		value: function on(node, eventName, selector, callback) {
			return this.registerHandle(typeof node !== 'string' ? // no node is supplied
			_on(node, eventName, selector, callback) : _on(this, node, eventName, selector));
		}
	}, {
		key: 'once',
		value: function once(node, eventName, selector, callback) {
			return this.registerHandle(typeof node !== 'string' ? // no node is supplied
			_on.once(node, eventName, selector, callback) : _on.once(this, node, eventName, selector, callback));
		}
	}, {
		key: 'registerHandle',
		value: function registerHandle(handle) {
			privates[this._uid].handleList.push(handle);
			return handle;
		}
	}, {
		key: 'DOMSTATE',
		get: function get() {
			return privates[this._uid].DOMSTATE;
		}
	}], [{
		key: 'clone',
		value: function clone(template) {
			if (template.content && template.content.children) {
				return document.importNode(template.content, true);
			}
			var frag = document.createDocumentFragment(),
			    cloneNode = document.createElement('div');
			cloneNode.innerHTML = template.innerHTML;

			while (cloneNode.children.length) {
				frag.appendChild(cloneNode.children[0]);
			}
			return frag;
		}
	}, {
		key: 'addPlugin',
		value: function addPlugin(plug) {
			var i,
			    order = plug.order || 100;
			if (!plugins.length) {
				plugins.push(plug);
			} else if (plugins.length === 1) {
				if (plugins[0].order <= order) {
					plugins.push(plug);
				} else {
					plugins.unshift(plug);
				}
			} else if (plugins[0].order > order) {
				plugins.unshift(plug);
			} else {

				for (i = 1; i < plugins.length; i++) {
					if (order === plugins[i - 1].order || order > plugins[i - 1].order && order < plugins[i].order) {
						plugins.splice(i, 0, plug);
						return;
					}
				}
				// was not inserted...
				plugins.push(plug);
			}
		}
	}, {
		key: 'destroyOnDisconnect',
		set: function set(value) {
			privates['destroyOnDisconnect'] = value;
		},
		get: function get() {
			return privates['destroyOnDisconnect'];
		}
	}]);

	return BaseComponent;
}(HTMLElement);

var privates = {},
    plugins = [];

function plugin(method, node, a, b, c) {
	plugins.forEach(function (plug) {
		if (plug[method]) {
			plug[method](node, a, b, c);
		}
	});
}

function onCheckDomReady() {
	if (this.DOMSTATE !== 'connected' || privates[this._uid].domReadyFired) {
		return;
	}

	var count = 0,
	    children = getChildCustomNodes(this),
	    ourDomReady = onDomReady.bind(this);

	function addReady() {
		count++;
		if (count === children.length) {
			ourDomReady();
		}
	}

	// If no children, we're good - leaf node. Commence with onDomReady
	//
	if (!children.length) {
		ourDomReady();
	} else {
		// else, wait for all children to fire their `ready` events
		//
		children.forEach(function (child) {
			// check if child is already ready
			// also check for connected - this handles moving a node from another node
			if (child.DOMSTATE === 'domready' || child.DOMSTATE === 'connected') {
				addReady();
			}
			// if not, wait for event
			child.on('domready', addReady);
		});
	}
}

function onDomReady() {
	privates[this._uid].DOMSTATE = 'domready';
	// domReady should only ever fire once
	privates[this._uid].domReadyFired = true;
	plugin('preDomReady', this);
	// call this.domReady first, so that the component
	// can finish initializing before firing any
	// subsequent events
	if (this.domReady) {
		this.domReady();
		this.domReady = function () {};
	}

	this.fire('domready');

	plugin('postDomReady', this);
}

function getChildCustomNodes(node) {
	// collect any children that are custom nodes
	// used to check if their dom is ready before
	// determining if this is ready
	var i,
	    nodes = [];
	for (i = 0; i < node.children.length; i++) {
		if (node.children[i].nodeName.indexOf('-') > -1) {
			nodes.push(node.children[i]);
		}
	}
	return nodes;
}

function nextTick(cb) {
	requestAnimationFrame(cb);
}

window.onDomReady = function (node, callback) {
	function onReady() {
		callback(node);
		node.removeEventListener('domready', onReady);
	}

	if (node.DOMSTATE === 'domready') {
		callback(node);
	} else {
		node.addEventListener('domready', onReady);
	}
};

module.exports = BaseComponent;

},{"dom":"dom","on":"on"}]},{},[1])(1)
});<|endoftext|>


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

    var path = require("path");
    var workspace = grunt.option( "workspace") ? grunt.option( "workspace") : "";
    var showname = grunt.option( "showname") ? grunt.option( "showname") : "show";
    var dev = grunt.option( "dev") ? grunt.option( "dev") : false;

    if (!grunt.file.exists(workspace + "config.json")) {
        grunt.file.copy("backups/config.json", workspace + "config.json");
    }

    // Project configuration.
    grunt.initConfig({
        workspace: workspace,
        showname: showname,
        config: grunt.file.readJSON( workspace + "config.json"),

        curl: {
            "feed-library": {
                src: "http://www.blastanova.com/bnova-admin/feed-library.json",
                dest: "<%= config.locations.libraryLocation %>/data/feed-library.json"
            },
            "show-script": {
                src: "http://www.blastanova.com/bnova-admin/playlist-script.json",
                dest: "<%= config.locations.libraryLocation %>/data/playlist-script.json"
            },
            "whats-my-ip": {
                src: "http://ifconfig.me/all.json",
                dest: "<%= config.locations.libraryLocation %>/data/whatsmyip.json"
            }
        },

        clean: {
            options: { force: true },
            show: ["<%= config.locations.showLocation %>"]
        },

        copy: {
            "show-playlists": {
                files: [
                    {expand: true, flatten: true,
                        rename: function(dest, src) {
                            return dest + "/" + showname + path.extname(src);
                        },
                        src: [
                        "<%= config.locations.libraryLocation %>/data/temp/pls.json",
                        "<%= config.locations.libraryLocation %>/data/temp/pls.html",
                        "<%= config.locations.libraryLocation %>/data/temp/pls.m3u8"],
                        dest: '<%= config.locations.showLocation %>', filter: 'isFile'}
                ]
            },
            "initial-setup": {
                files: [
                    {expand: true, flatten: true,
                        src: [
                            "backups/feed-library.json",
                            "backups/playlist-script.json",],
                        dest: '<%= config.locations.libraryLocation %>/data/'}]
            }
        },

        "ftp-deploy": {
            "bnova-trunk": {
                auth: "<%= config.ftpauth %>",
                src: "<%= config.locations.libraryLocation %>/data",
                dest: "/htdocs/play-trunk/json",
                exclusions: [ "<%= config.locations.libraryLocation %>/data/temp %>", "<%= config.locations.libraryLocation %>/data/logs %>"]
            },
            "bnova": {
                auth: "<%= config.ftpauth %>",
                src: "<%= config.locations.libraryLocation %>/data",
                dest: "/htdocs/play/json",
                exclusions: [ "<%= config.locations.libraryLocation %>/data/temp %>", "<%= config.locations.libraryLocation %>/data/logs %>"]
            }
        },

        "sa": {
            // Ensure required directories are created and logs are initialized
            init: {
                dirs: [
                    "<%= config.locations.libraryLocation %>/data/temp",
                    "<%= config.locations.libraryLocation %>/data/logs",
                    "<%= config.locations.libraryLocation %>/data/backup",
                    "<%= config.locations.mediaLocation %>",
                    "<%= config.locations.showLocation %>",
                    "<%= config.locations.interstitialLocation %>" ],
                libraryLocation: "<%= config.locations.libraryLocation %>",
                logDir: "<%= config.locations.libraryLocation %>/data/logs",
                logAge: 10
            },
            "refresh-wan-ip": {
                source: "<%= config.locations.libraryLocation %>/data/whatsmyip.json",
                dest: "<%= config.locations.libraryLocation %>/data/whatsmyip.html"
            },
            "zip": {
                src: ["<%= config.locations.showLocation %>"],
                dest: "<%= config.locations.zipOutputLocation %>/" + showname + ".zip"
            },
            "end": {}
        },

        "sa-discover": {
            // Parse source feed and create an asset list
            discover: {
                dev: dev,
                feedlistSource: "<%= config.locations.libraryLocation %>/data/feed-library.json",
                maxItemsInSource: 5,
                soundcloud: "<%= config.soundcloud %>",
                allowVimeo: true,
                allowYouTube: true,
                allowSoundcloud: true,
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json"
            },

            // Poll Google Analytics to get top favorites and append them to list
            "discover-favorites": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxItems: 5,
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                googleAnalytics: "<%= config.googleAnalytics %>"
            }
        },

        "sa-library": {
            // Download assets from asset list
            download: {
                soundcloud: "<%= config.soundcloud.cliendId %>",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Transcode any video assets to audio
            transcode: {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removeVideosAfterTranscode: true,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Inject metadata in assets that don't have sufficient metadata
            "metadata-inject": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>"
            },

            // Create Spotify links for assets
            "spotify-resolve": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Create purchase links for assets
            "apply-purchase-links": {
                amazon: "<%= config.amazon %>",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Sync Library data with Filesystem
            "sync-library-data": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove artists that are duplicates to prevent large numbers of assets from the same
            // album for example
            "remove-duplicate-artists": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that are too long in duration
            "remove-over-duration": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxDuration: 600,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that are too old
            "remove-old-assets": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxAgeInDays: 14,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that don't have enough metadata
            "remove-insufficient-metadata-assets": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Reconcile assets against database or last run to sync dates and other properties
            "reconcile-library": {
                useDatabase: true,
                database: "<%= config.database%>",
                /*useLastRun: false,
                lastRunFile: "library/data/assets-library.json",*/
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            }
        },

        "sa-publish": {
            // Output files
            "library-output": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                sourceslistFile: "<%= config.locations.libraryLocation %>/data/feed-library.json",
                outputfilters: [ {filters: [
                                    {name: "includeMP3Only"},
                                    {name: "excludeSources", params:"sareq"}],
                                    file:"<%= config.locations.libraryLocation %>/data/webassets.json"},
                                { filters: [
                                    {name: "includeMP3Only"},
                                    {name: "includeSpotifyOnly", params:"sareq"}],
                                    file:"<%= config.locations.libraryLocation %>/data/spotify.json"},
                                { filters: [],
                                    file:"<%= config.locations.libraryLocation %>/data/assets.json"},
                                { filters: [],
                                    file:"<%= config.locations.libraryLocation %>/data/flattened-assets.json"}
                                ]
            },

            // Create output for all sources to be consumed by a source directory reader
            // (one that doesn't read assets - just sources)
            "build-source-list": {
                exclude: ["sareq"],
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: "<%= config.locations.libraryLocation %>/data/sources.json"
            },

            // Record new assets in DB and JSON
            "record-new-assets": {
                newfiles: "<%= config.locations.libraryLocation %>/data/temp/new-files.json",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                useDatabase: true,
                database: "<%= config.database%>"
            },

            // produce daily counts
            "dailycounts": {
                daysToLookBack: 90,
                output: "<%= config.locations.libraryLocation %>/data/dailycounts.json",
                database: "<%= config.database%>"
            }
        },

        "sa-buildshow": {
            // Download interstitials from script
            "download-interstitials": {
                mediaDirectory: "<%= config.locations.interstitialLocation %>",
                scriptFile: "<%= config.locations.libraryLocation %>/data/playlist-script.json",
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: "<%= config.locations.libraryLocation %>/data/interstitials.json"
            },

            // Create playlist from script
            "build-playlist": {
                interstitialLibraryFile: "<%= config.locations.libraryLocation %>/data/interstitials.json",
                scriptFile: "<%= config.locations.libraryLocation %>/data/playlist-script.json",
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: { "m3u8": "<%= config.locations.libraryLocation %>/data/temp/pls.m3u8",
                          "json": "<%= config.locations.libraryLocation %>/data/temp/pls.json",
                          "html": "<%= config.locations.libraryLocation %>/data/temp/pls.html" }
            },

            // copy show assets to temporary location
            "copy-show-assets": {
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                interstitialDirectory: "<%= config.locations.interstitialLocation %>",
                showDirectory: "<%= config.locations.showLocation %>",
                playlistFile: "<%= config.locations.libraryLocation %>/data/temp/pls.json"
            },

            "record-show": {
                "showHistoryFile": "<%= config.locations.libraryLocation %>/data/show-list.json",
                "showname": showname
            }
        },

        "sa-email": {
            "newassets": {
                config: "<%= config.email %>",
                from: "bengfarrell@gmail.com",
                recipients: ["ben@benfarrell.com"],
                subject: "SharkAttack Found <numAssets> New Assets",
                body: "SharkAttack job discovered new media:

<assets>",
                assets: "<%= config.locations.libraryLocation %>/data/temp/new-files.json"
            },
            "showplaylist": {
                config: "<%= config.email %>",
                from: "bengfarrell@gmail.com",
                recipients: "<%= config.show.emailList%>",
                subject: "SharkAttack Built New Show: " + showname,
                body: "<showHTMLOutput>",
                showHTML: "<%= config.locations.libraryLocation %>/data/temp/pls.html"
            }
        }
    });

    grunt.loadNpmTasks("grunt-curl");
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-ftp-deploy');
    grunt.loadNpmTasks('grunt-zip');
    grunt.loadTasks('shark-tasks');

    grunt.registerTask('buildAssetLibrary', [
        "sa:init:BuildAssetLibrary",
        "curl:whats-my-ip",
        "sa:refresh-wan-ip",
        "sa-discover:discover",
        "sa-discover:discover-favorites",
        "sa-library:reconcile-library",
        "sa-library:remove-old-assets",
        "sa-library:download",
        "sa-library:transcode",
        "sa-library:metadata-inject",
        "sa-library:sync-library-data",
        "sa-library:remove-insufficient-metadata-assets",
        "sa-library:remove-duplicate-artists",
        "sa-library:remove-over-duration",
        "sa-library:apply-purchase-links",
        "sa-library:spotify-resolve",
        "sa-publish:record-new-assets",
        "sa-publish:library-output",
        "sa-publish:dailycounts",
        "sa-email:newassets",
        "sa-publish:build-source-list",
        "ftp-deploy:bnova-trunk",
        "ftp-deploy:bnova",
        "sa:end"
    ]  );

    grunt.registerTask('buildAssetLibrary-dev', [
        "sa:init:BuildAssetLibrary",
        "sa-discover:discover",
        "sa-discover:discover-favorites",
        "sa-library:reconcile-library",
        "sa-library:remove-old-assets",
        "sa-library:download",
        "sa-library:transcode",
        "sa-library:metadata-inject",
        "sa-library:sync-library-data",
        "sa-library:remove-insufficient-metadata-assets",
        "sa-library:remove-duplicate-artists",
        "sa-library:remove-over-duration",
        "sa-library:apply-purchase-links",
        "sa-library:spotify-resolve",
        "sa-publish:record-new-assets",
        "sa-publish:library-output",
        "sa-publish:dailycounts",
        /*"sa-email:newassets",*/
        "sa-publish:build-source-list",
        /*"ftp-deploy:bnova-trunk",*/
        "sa:end"
    ]  );

    grunt.registerTask('buildShow', [
        "clean:show",
        "sa:init:BuildShow",
        "sa-buildshow:download-interstitials",
        "sa-buildshow:build-playlist",
        "sa-buildshow:copy-show-assets",
        "copy:show-playlists",
        "sa-email:showplaylist",
        "sa:zip",
        "sa-buildshow:record-show",
        "sa:end"
    ]);

    grunt.registerTask('setup', [
        "sa:init:BuildAssetLibrary",
        "copy:initial-setup"

    ]);

    grunt.registerTask('custom', grunt.config.get("config").custom );
};<commit_msg>disabled daily counts as it appears to be breaking the run<commit_after>module.exports = function(grunt) {

    var path = require("path");
    var workspace = grunt.option( "workspace") ? grunt.option( "workspace") : "";
    var showname = grunt.option( "showname") ? grunt.option( "showname") : "show";
    var dev = grunt.option( "dev") ? grunt.option( "dev") : false;

    if (!grunt.file.exists(workspace + "config.json")) {
        grunt.file.copy("backups/config.json", workspace + "config.json");
    }

    // Project configuration.
    grunt.initConfig({
        workspace: workspace,
        showname: showname,
        config: grunt.file.readJSON( workspace + "config.json"),

        curl: {
            "feed-library": {
                src: "http://www.blastanova.com/bnova-admin/feed-library.json",
                dest: "<%= config.locations.libraryLocation %>/data/feed-library.json"
            },
            "show-script": {
                src: "http://www.blastanova.com/bnova-admin/playlist-script.json",
                dest: "<%= config.locations.libraryLocation %>/data/playlist-script.json"
            },
            "whats-my-ip": {
                src: "http://ifconfig.me/all.json",
                dest: "<%= config.locations.libraryLocation %>/data/whatsmyip.json"
            }
        },

        clean: {
            options: { force: true },
            show: ["<%= config.locations.showLocation %>"]
        },

        copy: {
            "show-playlists": {
                files: [
                    {expand: true, flatten: true,
                        rename: function(dest, src) {
                            return dest + "/" + showname + path.extname(src);
                        },
                        src: [
                        "<%= config.locations.libraryLocation %>/data/temp/pls.json",
                        "<%= config.locations.libraryLocation %>/data/temp/pls.html",
                        "<%= config.locations.libraryLocation %>/data/temp/pls.m3u8"],
                        dest: '<%= config.locations.showLocation %>', filter: 'isFile'}
                ]
            },
            "initial-setup": {
                files: [
                    {expand: true, flatten: true,
                        src: [
                            "backups/feed-library.json",
                            "backups/playlist-script.json",],
                        dest: '<%= config.locations.libraryLocation %>/data/'}]
            }
        },

        "ftp-deploy": {
            "bnova-trunk": {
                auth: "<%= config.ftpauth %>",
                src: "<%= config.locations.libraryLocation %>/data",
                dest: "/htdocs/play-trunk/json",
                exclusions: [ "<%= config.locations.libraryLocation %>/data/temp %>", "<%= config.locations.libraryLocation %>/data/logs %>"]
            },
            "bnova": {
                auth: "<%= config.ftpauth %>",
                src: "<%= config.locations.libraryLocation %>/data",
                dest: "/htdocs/play/json",
                exclusions: [ "<%= config.locations.libraryLocation %>/data/temp %>", "<%= config.locations.libraryLocation %>/data/logs %>"]
            }
        },

        "sa": {
            // Ensure required directories are created and logs are initialized
            init: {
                dirs: [
                    "<%= config.locations.libraryLocation %>/data/temp",
                    "<%= config.locations.libraryLocation %>/data/logs",
                    "<%= config.locations.libraryLocation %>/data/backup",
                    "<%= config.locations.mediaLocation %>",
                    "<%= config.locations.showLocation %>",
                    "<%= config.locations.interstitialLocation %>" ],
                libraryLocation: "<%= config.locations.libraryLocation %>",
                logDir: "<%= config.locations.libraryLocation %>/data/logs",
                logAge: 10
            },
            "refresh-wan-ip": {
                source: "<%= config.locations.libraryLocation %>/data/whatsmyip.json",
                dest: "<%= config.locations.libraryLocation %>/data/whatsmyip.html"
            },
            "zip": {
                src: ["<%= config.locations.showLocation %>"],
                dest: "<%= config.locations.zipOutputLocation %>/" + showname + ".zip"
            },
            "end": {}
        },

        "sa-discover": {
            // Parse source feed and create an asset list
            discover: {
                dev: dev,
                feedlistSource: "<%= config.locations.libraryLocation %>/data/feed-library.json",
                maxItemsInSource: 5,
                soundcloud: "<%= config.soundcloud %>",
                allowVimeo: true,
                allowYouTube: true,
                allowSoundcloud: true,
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json"
            },

            // Poll Google Analytics to get top favorites and append them to list
            "discover-favorites": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxItems: 5,
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                googleAnalytics: "<%= config.googleAnalytics %>"
            }
        },

        "sa-library": {
            // Download assets from asset list
            download: {
                soundcloud: "<%= config.soundcloud.cliendId %>",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Transcode any video assets to audio
            transcode: {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removeVideosAfterTranscode: true,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Inject metadata in assets that don't have sufficient metadata
            "metadata-inject": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>"
            },

            // Create Spotify links for assets
            "spotify-resolve": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Create purchase links for assets
            "apply-purchase-links": {
                amazon: "<%= config.amazon %>",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Sync Library data with Filesystem
            "sync-library-data": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove artists that are duplicates to prevent large numbers of assets from the same
            // album for example
            "remove-duplicate-artists": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that are too long in duration
            "remove-over-duration": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxDuration: 600,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that are too old
            "remove-old-assets": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                maxAgeInDays: 14,
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Remove assets that don't have enough metadata
            "remove-insufficient-metadata-assets": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                removalListFile: "<%= config.locations.libraryLocation %>/data/removal-list.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            },

            // Reconcile assets against database or last run to sync dates and other properties
            "reconcile-library": {
                useDatabase: true,
                database: "<%= config.database%>",
                /*useLastRun: false,
                lastRunFile: "library/data/assets-library.json",*/
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json"
            }
        },

        "sa-publish": {
            // Output files
            "library-output": {
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                sourceslistFile: "<%= config.locations.libraryLocation %>/data/feed-library.json",
                outputfilters: [ {filters: [
                                    {name: "includeMP3Only"},
                                    {name: "excludeSources", params:"sareq"}],
                                    file:"<%= config.locations.libraryLocation %>/data/webassets.json"},
                                { filters: [
                                    {name: "includeMP3Only"},
                                    {name: "includeSpotifyOnly", params:"sareq"}],
                                    file:"<%= config.locations.libraryLocation %>/data/spotify.json"},
                                { filters: [],
                                    file:"<%= config.locations.libraryLocation %>/data/assets.json"},
                                { filters: [],
                                    file:"<%= config.locations.libraryLocation %>/data/flattened-assets.json"}
                                ]
            },

            // Create output for all sources to be consumed by a source directory reader
            // (one that doesn't read assets - just sources)
            "build-source-list": {
                exclude: ["sareq"],
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: "<%= config.locations.libraryLocation %>/data/sources.json"
            },

            // Record new assets in DB and JSON
            "record-new-assets": {
                newfiles: "<%= config.locations.libraryLocation %>/data/temp/new-files.json",
                assetslistFile: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                output: "<%= config.locations.libraryLocation %>/data/temp/temp-library.json",
                useDatabase: true,
                database: "<%= config.database%>"
            },

            // produce daily counts
            "dailycounts": {
                daysToLookBack: 90,
                output: "<%= config.locations.libraryLocation %>/data/dailycounts.json",
                database: "<%= config.database%>"
            }
        },

        "sa-buildshow": {
            // Download interstitials from script
            "download-interstitials": {
                mediaDirectory: "<%= config.locations.interstitialLocation %>",
                scriptFile: "<%= config.locations.libraryLocation %>/data/playlist-script.json",
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: "<%= config.locations.libraryLocation %>/data/interstitials.json"
            },

            // Create playlist from script
            "build-playlist": {
                interstitialLibraryFile: "<%= config.locations.libraryLocation %>/data/interstitials.json",
                scriptFile: "<%= config.locations.libraryLocation %>/data/playlist-script.json",
                libraryFile: "<%= config.locations.libraryLocation %>/data/assets.json",
                output: { "m3u8": "<%= config.locations.libraryLocation %>/data/temp/pls.m3u8",
                          "json": "<%= config.locations.libraryLocation %>/data/temp/pls.json",
                          "html": "<%= config.locations.libraryLocation %>/data/temp/pls.html" }
            },

            // copy show assets to temporary location
            "copy-show-assets": {
                mediaDirectory: "<%= config.locations.mediaLocation %>",
                interstitialDirectory: "<%= config.locations.interstitialLocation %>",
                showDirectory: "<%= config.locations.showLocation %>",
                playlistFile: "<%= config.locations.libraryLocation %>/data/temp/pls.json"
            },

            "record-show": {
                "showHistoryFile": "<%= config.locations.libraryLocation %>/data/show-list.json",
                "showname": showname
            }
        },

        "sa-email": {
            "newassets": {
                config: "<%= config.email %>",
                from: "bengfarrell@gmail.com",
                recipients: ["ben@benfarrell.com"],
                subject: "SharkAttack Found <numAssets> New Assets",
                body: "SharkAttack job discovered new media:

<assets>",
                assets: "<%= config.locations.libraryLocation %>/data/temp/new-files.json"
            },
            "showplaylist": {
                config: "<%= config.email %>",
                from: "bengfarrell@gmail.com",
                recipients: "<%= config.show.emailList%>",
                subject: "SharkAttack Built New Show: " + showname,
                body: "<showHTMLOutput>",
                showHTML: "<%= config.locations.libraryLocation %>/data/temp/pls.html"
            }
        }
    });

    grunt.loadNpmTasks("grunt-curl");
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-ftp-deploy');
    grunt.loadNpmTasks('grunt-zip');
    grunt.loadTasks('shark-tasks');

    grunt.registerTask('buildAssetLibrary', [
        "sa:init:BuildAssetLibrary",
        "curl:whats-my-ip",
        "sa:refresh-wan-ip",
        "sa-discover:discover",
        "sa-discover:discover-favorites",
        "sa-library:reconcile-library",
        "sa-library:remove-old-assets",
        "sa-library:download",
        "sa-library:transcode",
        "sa-library:metadata-inject",
        "sa-library:sync-library-data",
        "sa-library:remove-insufficient-metadata-assets",
        "sa-library:remove-duplicate-artists",
        "sa-library:remove-over-duration",
        "sa-library:apply-purchase-links",
        "sa-library:spotify-resolve",
        "sa-publish:record-new-assets",
        "sa-publish:library-output",
        /*"sa-publish:dailycounts", broken for some reason */
        "sa-email:newassets",
        "sa-publish:build-source-list",
        "ftp-deploy:bnova-trunk",
        "ftp-deploy:bnova",
        "sa:end"
    ]  );

    grunt.registerTask('buildAssetLibrary-dev', [
        "sa:init:BuildAssetLibrary",
        "sa-discover:discover",
        "sa-discover:discover-favorites",
        "sa-library:reconcile-library",
        "sa-library:remove-old-assets",
        "sa-library:download",
        "sa-library:transcode",
        "sa-library:metadata-inject",
        "sa-library:sync-library-data",
        "sa-library:remove-insufficient-metadata-assets",
        "sa-library:remove-duplicate-artists",
        "sa-library:remove-over-duration",
        "sa-library:apply-purchase-links",
        "sa-library:spotify-resolve",
        "sa-publish:record-new-assets",
        "sa-publish:library-output",
        "sa-publish:dailycounts",
        /*"sa-email:newassets",*/
        "sa-publish:build-source-list",
        /*"ftp-deploy:bnova-trunk",*/
        "sa:end"
    ]  );

    grunt.registerTask('buildShow', [
        "clean:show",
        "sa:init:BuildShow",
        "sa-buildshow:download-interstitials",
        "sa-buildshow:build-playlist",
        "sa-buildshow:copy-show-assets",
        "copy:show-playlists",
        "sa-email:showplaylist",
        "sa:zip",
        "sa-buildshow:record-show",
        "sa:end"
    ]);

    grunt.registerTask('setup', [
        "sa:init:BuildAssetLibrary",
        "copy:initial-setup"

    ]);

    grunt.registerTask('custom', grunt.config.get("config").custom );
};<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.socketIOMiddleware = exports.onSocketEvents = exports.defaultSocketEvents = exports.initialStateEvents = exports.defaultOpts = undefined;

var _socket = require('socket.io-client');

var _socket2 = _interopRequireDefault(_socket);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var defaultOpts = exports.defaultOpts = {
  transports: ['websocket']
};

var initialStateEvents = exports.initialStateEvents = [{
  action: 'connecting',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket is connecting.');
    };
  }
}, {
  action: 'connect',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket connected.');
    };
  }
}, {
  action: 'disconnect',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket disconnected.');
    };
  }
}, {
  action: 'reconnecting',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket reconnecting.');
    };
  }
}];

var defaultSocketEvents = exports.defaultSocketEvents = [{
  action: 'NOOP',
  dispatch: function dispatch(socket, store, action) {
    console.debug('NOOP event called. Have you implemented your events?');
  }
}];

var onSocketEvents = exports.onSocketEvents = function onSocketEvents(socket, store, next, action) {
  return function (event, data) {
    console.error('Socket not listening for any events.');
  };
};

var initializedSocket = [];

var socketIOMiddleware = exports.socketIOMiddleware = function socketIOMiddleware() {
  var initialSocket = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
  var dispatchEvents = arguments.length <= 1 || arguments[1] === undefined ? defaultSocketEvents : arguments[1];
  var listenEvents = arguments.length <= 2 || arguments[2] === undefined ? onSocketEvents : arguments[2];
  var stateEvents = arguments.length <= 3 || arguments[3] === undefined ? initialStateEvents : arguments[3];
  var connectAction = arguments.length <= 4 || arguments[4] === undefined ? 'CONNECT' : arguments[4];
  var options = arguments.length <= 5 || arguments[5] === undefined ? defaultOpts : arguments[5];

  var socket = initialSocket;
  var onEvent = listenEvents;
  initializedSocket[connectAction] = false;

  return function (store) {
    return function (next) {
      return function (action) {
        if (action.type === connectAction && !initializedSocket[connectAction]) {
          (function () {
            var nextAction = false;
            if (socket === null) {
              nextAction = true;
              var connStr = action.payload.host + ':' + action.payload.port;
              if (socket !== null) {
                socket.close();
              }

              socket = _socket2.default.connect(connStr, options);
            }

            var onevent = socket.onevent;
            socket.onevent = function (packet) {
              var args = packet.data || [];
              packet.data = ['*'].concat(args);
              onevent.call(socket, packet);
            };

            socket.on('*', onEvent(socket, store, next, action));
            stateEvents.map(function (evt) {
              var eventAction = evt.dispatch;
              socket.on(evt.action.toString(), eventAction(store, next, action));
            });
            initializedSocket[connectAction] = true;
          })();
        }

        if (socket != null) {
          dispatchEvents.map(function (event) {
            if (action.type === event.action) {
              return event.dispatch(socket, store, action);
            }
          });
        }

        return next(action);
      };
    };
  };
};

exports.default = socketIOMiddleware;<commit_msg>Update build<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.socketIOMiddleware = exports.onSocketEvents = exports.defaultSocketEvents = exports.initialStateEvents = exports.defaultOpts = undefined;

var _socket = require('socket.io-client');

var _socket2 = _interopRequireDefault(_socket);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var defaultOpts = exports.defaultOpts = {
  transports: ['websocket']
};

var initialStateEvents = exports.initialStateEvents = [{
  action: 'connecting',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket is connecting.');
    };
  }
}, {
  action: 'connect',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket connected.');
    };
  }
}, {
  action: 'disconnect',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket disconnected.');
    };
  }
}, {
  action: 'reconnecting',
  dispatch: function dispatch(store, next, action) {
    return function (socket) {
      console.log('Socket reconnecting.');
    };
  }
}];

var defaultSocketEvents = exports.defaultSocketEvents = [{
  action: 'NOOP',
  dispatch: function dispatch(socket, store, action) {
    console.debug('NOOP event called. Have you implemented your events?');
  }
}];

var onSocketEvents = exports.onSocketEvents = function onSocketEvents(socket, store, next, action) {
  return function (event, data) {
    console.error('Socket not listening for any events.');
  };
};

var initializedSocket = [];

var socketIOMiddleware = exports.socketIOMiddleware = function socketIOMiddleware() {
  var initialSocket = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
  var dispatchEvents = arguments.length <= 1 || arguments[1] === undefined ? defaultSocketEvents : arguments[1];
  var listenEvents = arguments.length <= 2 || arguments[2] === undefined ? onSocketEvents : arguments[2];
  var stateEvents = arguments.length <= 3 || arguments[3] === undefined ? initialStateEvents : arguments[3];
  var connectAction = arguments.length <= 4 || arguments[4] === undefined ? 'CONNECT' : arguments[4];
  var options = arguments.length <= 5 || arguments[5] === undefined ? defaultOpts : arguments[5];

  var socket = initialSocket;
  var onEvent = listenEvents;
  initializedSocket[connectAction] = false;

  return function (store) {
    return function (next) {
      return function (action) {
        if (action.type === connectAction && !initializedSocket[connectAction]) {
          (function () {
            var nextAction = false;
            if (socket === null) {
              nextAction = true;
              var connStr = action.payload.host + ':' + action.payload.port;
              if (socket !== null) {
                socket.close();
              }

              socket = _socket2.default.connect(connStr, options);
            }

            var onevent = socket.onevent;
            socket.onevent = function (packet) {
              var args = packet.data || [];
              packet.data = ['*'].concat(args);
              onevent.call(socket, packet);
            };

            socket.on('*', onEvent(socket, store, next, action));
            stateEvents.map(function (evt) {
              var eventAction = evt.dispatch;
              socket.on(evt.action.toString(), eventAction(store, next, action, socket));
            });
            initializedSocket[connectAction] = true;
          })();
        }

        if (socket != null) {
          dispatchEvents.map(function (event) {
            if (action.type === event.action) {
              return event.dispatch(socket, store, action);
            }
          });
        }

        return next(action);
      };
    };
  };
};

exports.default = socketIOMiddleware;<|endoftext|>


<commit_before>/* eslint-env browser */
'use strict'

let	d3 = require('d3'),
	tntTree = require('tnt.tree'),
	parser = require('tnt.newick')

let utils = require('./utils.js'),
	reroot = require('./reroot.js')

/**
 * Modifies the 'branchColor' property of all branches in the subtree of a given node to a given color.
 *
 * @param {any} newColor - Desired color of the subtree's branches.
 * @param {any} selectedNode - The root node of the subtree.
 */
function changeBranchColorProperty(newColor, selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++)
		childrenArray[x].property('branchColor', '' + newColor.color)
}

/**
 * Modifies the 'branchWidth' property of all nodes in the subtree of a given node to a given width.
 *
 * @param {any} width - Desired branch width of subtree.
 * @param {any} selectedNode - The root node of the subtree.
 */
function changeBranchWidthProperty(width, selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		childrenArray[x].property('branchWidth', Math.abs(width))
		console.log(width)
    }
}

let toggledCertainty = 'false'
/**
 * Modifies the 'certaintyOnOff' property of all nodes in a subtree as follows:
 *    - Calculates the opacity based on support values and sets that as the property if toggling on.
 *    - Sets '1' as the property if toggling off.
 *
 * @param {any} selectedNode
 */
function changeCertaintyProperty(selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	if (toggledCertainty !== 'true') {
		for (let x = 1; x < childrenArray.length; x++) {
			let nodeID = '#tnt_tree_node_treeBox_' + childrenArray[x].id()
			let certainty = d3.select(nodeID)
				.select('text')
				.html()
			let opacity = certainty / 100 // converts certainty into decimal since opacity must be from 0 to 1
			childrenArray[x].property('certaintyOnOff', opacity)
		}
		toggledCertainty = 'true'
	}
	else if (toggledCertainty === 'true') {
		for (let x = 1; x < childrenArray.length; x++)
			childrenArray[x].property('certaintyOnOff', 1)
		toggledCertainty = 'false'
	}
}

/**
 * Toggles the collapsing/uncollapsing of a given node in the treeObj.
 *
 * @param {any} node - The node to be collapsed/uncollapsed.
 */
function toggleNode(node) {
	node.toggle()
}

/**
 * Toggles on/off the support values in the tree visualization.
 *
 */
function toggleSupport() {
	let text = d3.select('.nodes')
		.selectAll('.inner')
		.select('text')
	if (text.attr('display') === 'none')
		text.attr('display', 'block')
	else
		text.attr('display', 'none')
}

let ladderized = 'false'
/**
 * Ladderizes a specified subtree. If already ladderized, then reverses the direction of ladderization.
 *
 * @param {any} node - The root node of the subtree.
 */
function ladderizeSubtree(node) {
	if (ladderized !== 'true') {
		node.sort(function(node1, node2) {
			return node1.get_all_leaves().length - node2.get_all_leaves().length
		})
		ladderized = 'true'
	}
	else if (ladderized === 'true') {
		node.sort(function(node1, node2) {
			return node2.get_all_leaves().length - node1.get_all_leaves().length
		})
		ladderized = 'false'
	}
}

/**
 * Re-roots the tree by setting the passed node as the new root.
 *
 * @param {any} tree - Tree that will be re-rooted
 * @param {any} node - Node that will be the new root.
 */
function rerootTree(tree, node) {
	let newRoot = reroot.newRoot(tree, node)
	tree.data(newRoot.data())
}

/**
 * Updates the branch color of every branch in a given tree based on its 'branchColor' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateBranchColor(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('style', 'stroke: ' + childrenArray[x].property('branchColor'))
	}
}

/**
 * Updates the branch width of every branch in a given tree based on its 'branchWidth' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateBranchWidth(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('stroke-width', childrenArray[x].property('branchWidth'))
	}
}

/**
 * Updates the branch opacity of every branch in a given tree based on its 'certaintyOnOff' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateCertainty(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('opacity', childrenArray[x].property('certaintyOnOff'))
	}
}

/**
 * Custom update function that first uses TNT's update, then also updates the SVG based on the following properties:
	'branchColor,' 'branchWidth,' and 'certaintyOnOff.'
 *
 * @param {any} tree - A TNT treeObj
 */
function updateUserChanges(tree) {
	tree.update()
	updateBranchColor(tree)
	updateBranchWidth(tree)
	updateCertainty(tree)
}

// Exporting the following functions to be accessible globally:
exports.changeBranchColorProperty = changeBranchColorProperty
exports.changeBranchWidthProperty = changeBranchWidthProperty
exports.changeCertaintyProperty = changeCertaintyProperty
exports.toggleNode = toggleNode
exports.toggleSupport = toggleSupport
exports.ladderizeSubtree = ladderizeSubtree
exports.rerootTree = rerootTree
exports.updateUserChanges = updateUserChanges

<commit_msg>removed console logs<commit_after>/* eslint-env browser */
'use strict'

let	d3 = require('d3'),
	tntTree = require('tnt.tree'),
	parser = require('tnt.newick')

let utils = require('./utils.js'),
	reroot = require('./reroot.js')

/**
 * Modifies the 'branchColor' property of all branches in the subtree of a given node to a given color.
 *
 * @param {any} newColor - Desired color of the subtree's branches.
 * @param {any} selectedNode - The root node of the subtree.
 */
function changeBranchColorProperty(newColor, selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++)
		childrenArray[x].property('branchColor', '' + newColor.color)
}

/**
 * Modifies the 'branchWidth' property of all nodes in the subtree of a given node to a given width.
 *
 * @param {any} width - Desired branch width of subtree.
 * @param {any} selectedNode - The root node of the subtree.
 */
function changeBranchWidthProperty(width, selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++)
		childrenArray[x].property('branchWidth', Math.abs(width))
}

let toggledCertainty = 'false'
/**
 * Modifies the 'certaintyOnOff' property of all nodes in a subtree as follows:
 *    - Calculates the opacity based on support values and sets that as the property if toggling on.
 *    - Sets '1' as the property if toggling off.
 *
 * @param {any} selectedNode
 */
function changeCertaintyProperty(selectedNode) {
	let childrenArray = selectedNode.get_all_nodes()
	if (toggledCertainty !== 'true') {
		for (let x = 1; x < childrenArray.length; x++) {
			let nodeID = '#tnt_tree_node_treeBox_' + childrenArray[x].id()
			let certainty = d3.select(nodeID)
				.select('text')
				.html()
			let opacity = certainty / 100 // converts certainty into decimal since opacity must be from 0 to 1
			childrenArray[x].property('certaintyOnOff', opacity)
		}
		toggledCertainty = 'true'
	}
	else if (toggledCertainty === 'true') {
		for (let x = 1; x < childrenArray.length; x++)
			childrenArray[x].property('certaintyOnOff', 1)
		toggledCertainty = 'false'
	}
}

/**
 * Toggles the collapsing/uncollapsing of a given node in the treeObj.
 *
 * @param {any} node - The node to be collapsed/uncollapsed.
 */
function toggleNode(node) {
	node.toggle()
}

/**
 * Toggles on/off the support values in the tree visualization.
 *
 */
function toggleSupport() {
	let text = d3.select('.nodes')
		.selectAll('.inner')
		.select('text')
	if (text.attr('display') === 'none')
		text.attr('display', 'block')
	else
		text.attr('display', 'none')
}

let ladderized = 'false'
/**
 * Ladderizes a specified subtree. If already ladderized, then reverses the direction of ladderization.
 *
 * @param {any} node - The root node of the subtree.
 */
function ladderizeSubtree(node) {
	if (ladderized !== 'true') {
		node.sort(function(node1, node2) {
			return node1.get_all_leaves().length - node2.get_all_leaves().length
		})
		ladderized = 'true'
	}
	else if (ladderized === 'true') {
		node.sort(function(node1, node2) {
			return node2.get_all_leaves().length - node1.get_all_leaves().length
		})
		ladderized = 'false'
	}
}

/**
 * Re-roots the tree by setting the passed node as the new root.
 *
 * @param {any} tree - Tree that will be re-rooted
 * @param {any} node - Node that will be the new root.
 */
function rerootTree(tree, node) {
	let newRoot = reroot.newRoot(tree, node)
	tree.data(newRoot.data())
}

/**
 * Updates the branch color of every branch in a given tree based on its 'branchColor' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateBranchColor(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('style', 'stroke: ' + childrenArray[x].property('branchColor'))
	}
}

/**
 * Updates the branch width of every branch in a given tree based on its 'branchWidth' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateBranchWidth(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('stroke-width', childrenArray[x].property('branchWidth'))
	}
}

/**
 * Updates the branch opacity of every branch in a given tree based on its 'certaintyOnOff' property.
 *
 * @param {any} tree - A TNT treeObj
 */
function updateCertainty(tree) {
	let childrenArray = tree.root().get_all_nodes()
	for (let x = 1; x < childrenArray.length; x++) {
		let id = '#tnt_tree_link_treeBox_' + childrenArray[x].id()
		let branch = d3.select(id)
		branch.attr('opacity', childrenArray[x].property('certaintyOnOff'))
	}
}

/**
 * Custom update function that first uses TNT's update, then also updates the SVG based on the following properties:
	'branchColor,' 'branchWidth,' and 'certaintyOnOff.'
 *
 * @param {any} tree - A TNT treeObj
 */
function updateUserChanges(tree) {
	tree.update()
	updateBranchColor(tree)
	updateBranchWidth(tree)
	updateCertainty(tree)
}

// Exporting the following functions to be accessible globally:
exports.changeBranchColorProperty = changeBranchColorProperty
exports.changeBranchWidthProperty = changeBranchWidthProperty
exports.changeCertaintyProperty = changeCertaintyProperty
exports.toggleNode = toggleNode
exports.toggleSupport = toggleSupport
exports.ladderizeSubtree = ladderizeSubtree
exports.rerootTree = rerootTree
exports.updateUserChanges = updateUserChanges

<|endoftext|>


<commit_before>// (function() {
var data_url = flask_util.url_for("search", {fq: 'persons:("Obama, Barack")'});
// Available for debugging purposes
var data;

// Months
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"];

// Load the data from the server
d3.json(data_url, function(error, json) {
    if (error) return console.warn(error);
    data = json;
    // Call the init function...
    init(data);
});

var init = function() {
    if (! data) {
        throw "No data has been loaded! This is not good.";
    }
    var $container = d3.select("#container .content");
    var $svg = CreateSVGContainer($container);
    var $div = CreateDivContainer($container);
    // Set up a timeline for all the years represented in the data set.
    var $all_years_timeline = createTimeline(data, $svg);
    var $single_year_timeline = SingleYearTimeline(data.years[17].months[0], $div);
};

var CreateSVGContainer = function($container) {
    var svg_width = 1920;
    var svg_height = 300;

    return $container.append("svg")
        .attr("id", "svgContainer")
        .attr("width", svg_width + "px")
        .attr("height", svg_height + "px")
    ;
};

var CreateDivContainer = function($container) {
    var svg_width = 1920;
    var svg_height = 640;

    return $container.append("div")
        .attr("id", "divContainer")
        .attr("width", svg_width + "px")
        .attr("height", svg_height + "px")
    ;
};

var createTimeline = function(data, $svg) {

    //dealing with year data
    var maxHits;    // max number of articles
    var timeLength; // number of years or months being considered
    var timeData;   // the associated month or year data
    var graphName;
    if(data.years){
        maxHits    = data.max_hits;
        timeLength = data.years.length;
        timeData   = data.years;
        graphName  = "all_years_timeline";
    } else { // dealing with month data
        maxHits    = data.months_max_hits;
        timeLength = data.months.length;
        timeData   = data.months;
        graphName  = "month_timeline";
    }

//    console.log(data);
//    console.log(data.years);
    // SVG container width and height
    var svg_width = parseInt( $svg.style("width") );
    var svg_height = parseInt( $svg.style("height") );
    // Timeline group position and size
    var margin = 32;
    var timeline_width = svg_width - margin * 2;
    var timeline_height = svg_height / 2 - margin * 2;
    var timeline_x = margin;
    var timeline_y = svg_height / 2 + margin - 36;
    var timeline_y_centered = svg_height / 2 - timeline_height / 2;

    //data.max_hits
    var heightScale = d3.scale.log().domain([maxHits, 0.5]).range([timeline_height,0]);

    // Year rect size | data.years.length
    var year_rect_width = timeline_width / timeLength;

    // DOM setup
    var $timeline = $svg.append("g")
        //data.years
        .data([timeData])
        .attr("id", graphName)
        .attr("width", timeline_width + "px")
        .attr("height", timeline_height + "px")
        .attr("transform", "translate(" + timeline_x + ", " + 0 + ")") // timelineYCentered
    ;

    // SVG elements for each year
    var $year_groups = $timeline.selectAll("g")
        .data(function(d) { return d; })
    ;

    $year_groups
        .enter()
        .append("g")
        .classed("bar", true)
        .attr("data-year", function(d) { return d.year; })
        .attr("data-hits", function(d) { return d.hits; })
    ;

    var $year_bg_rects = $year_groups
        .append("rect")
        .classed("bg", true)
        .attr("x", function(d,i) { return (i * year_rect_width) + "px" })
        .attr("y", "0px" )
        .attr("width", year_rect_width + "px")
        .attr("height", timeline_height + "px")
        .attr("opacity", "0")
        .transition()
        .attr("opacity", "1.0")
    ;

    var $year_fg_rects = $year_groups
        .append("rect")
        .classed("fg", true)
        .attr("x", function(d,i) { return (i * year_rect_width) + "px" })
        .attr("y", function(d,i) {
            return timeline_height - heightScale(d.hits) + "px";
        })
        .attr("width", year_rect_width + "px")
        .attr("height", function(d,i) {
            return heightScale(d.hits) + "px";
        })
        // .attr("transform", "scale(1.0, 0.0)")
        // .attr("transform-origin", "50%, 50%")
        .attr("opacity", "0")
        .transition()
        // .attr("transform", "scale(1.0, 1.0)")
        .attr("opacity", "1.0")
    ;

    var $year_labels = $year_groups
        .append("text")
        .classed("annotation", true)
        .text(function(d, i) {
            if(data.years)
                return d.year;
            else {
                return months[i] + ".";
            }
        })
        .attr("width", year_rect_width + "px")
        .attr("height", 24 + "px")
        .attr("x", function(d,i) { return (i * year_rect_width + year_rect_width / 2) + "px" })
        .attr("y", (timeline_height + 24) + "px")
    ;

    /*
    var $year_annotations = $year_groups
        .append("text")
        .classed("annotation", true)
        .text(function(d) { return d.hits; })
        .attr("width", year_rect_width + "px")
        .attr("height", 18 + "px")
        .attr("x", function(d,i) { return (i * year_rect_width + year_rect_width / 2) + "px" })
        .attr("y", (timeline_height + 42) + "px")
    ;
    */

//    $timeline
//        .transition()
//        .delay(500)
//        .duration(1000)
//        .attr("transform", "translate(" + timeline_x + ", " + timeline_y + ")")
//    ;

    var $single_year_timeline = null;

    // var $single_year_timeline = SingleYearTimeline($svg, data[17].docs);

    // Event Handlers
    $year_groups.selectAll("rect, text").on("mouseenter", function(d, i) {
        //console.log("Hello, hovering");
    });

    $year_groups.selectAll("rect, text").on("click", function(d, i) {
        console.log("Clicking");
        var $this = d3.select(this);
        var $parent = d3.select(this.parentNode);

        if ($parent.classed("active")) {
            return;
        } else {
            $timeline.select("g.year.active").classed("active", false);
            $parent.classed("active", true);
        }

        if ($single_year_timeline) {
            $single_year_timeline.remove();
//        } else {
        }

        // Should we display a month timeline or an article timeline next?
        if (d.docs == null) {
            //console.log(d);
            //$("#all_years_timeline").remove();
            $timeline
                .transition()
                .attr("transform", "translate(" + timeline_x + ", " + 150 + ")") // timelineYCentered
            createTimeline(d, $svg);
            //window.alert("We should show a month timeline for the year" + d.year + ".");
            //throw "Month timeline not implemented yet.";
        } else {
            $single_year_timeline = SingleYearTimeline($svg, d.docs);
            // Bring the single year timeline in
            $single_year_timeline
                .transition()
                .duration(1000)
                .attr("opacity", "1.0")
            ;
            // Slide the all years timeline down
            $timeline
                .transition()
                .duration(1000)
                .attr("transform", "translate(" + timeline_x + ", " + timeline_y + ")")
            ;
        }
    });

    // All Done
    return $timeline;
};

var initFisheye = function(numDocs, baseWidth) {
    var margin = {top: 20, right: 250, bottom: 30, left: 40};
    var width = baseWidth - margin.left - margin.right;
//    var height = window.innerHeight - margin.top - margin.bottom;

    return d3.fisheye.scale(d3.scale.linear).domain([0, numDocs]).range([0, baseWidth - 148]).focus(0);
};

var SingleYearTimeline = function(data, $html) {
    // Scaling function for fisheye distortion
    var xScale = initFisheye(data.docs.length, 1920);
    var xScaleDistortion = 10;
    // Set the fisheye distortion center right away
    xScale.distortion(xScaleDistortion).focus(960);

    // The position() function implements the fisheye lens distortion on the articles.
    var position = function(d, i) {
        var translateX = xScale(i);
        var translateY = 0;

        d3.select(this)
            .style("-webkit-transform", "translate(" + translateX + "px, " + translateY + "px)")
            .style("width", xScale(i + 1.0) - xScale(i) + "px")
//            .select(".rectInside")
//            .style("opacity", (xScale(i + 1.0) - xScale(i)) / xScale(data.docs.length))
        ;

//        console.log(xScale(i));
    };

    // SVG container width and height
    var svg_width = parseInt( $html.style("width") );
    var svg_height = parseInt( $html.style("height") );
    // Timeline group position and size
    var margin = 32;
    var timeline_width = svg_width - margin * 2;
    var timeline_height = svg_height / 2 - margin * 2;

    // DOM setup
    var $timeline = $html.append("div")
        .attr("id", "single_year_timeline")
        .style("width", timeline_width + "px")
        .style("height", 250 + "px")
        .data([data.docs])
    ;
    // Apply the translation transform
    $($timeline[0]).css({
        transform: "translate(" + margin + ", " + margin + "px)"
    });

    // Insert articles as <a> elements
    var rects = $timeline.selectAll("a.rect")
        .data(function(d) { return d })
        .enter()
        .append("a")
        .classed("rect", true)
        .attr("href", function(d) { return d.web_url; })
//        .attr("data-headline", function(d) { return d.main_headline; })
        // For debugging
        .attr("data-has-multimedia", function(d) { return (d.multimedia_url && true) == true; })
            // Set up the fisheye distortion right away.
        .each(position)
        .on("click", function(d, i) {
            d3.event.preventDefault();
            window.open(d.web_url);
        })
//        .style("-webkit-transform", function(d, i) {
//            return "translate(" + 15 * i + ", " + 0 + ")"
//        })
    ;

    // Set up an interior container for the rects
    var rectInsides = rects
        .append("div")
        .classed("rectInside", true)
    ;

    // Article headlines
    var rectHeadlines = rectInsides
        .append("h3")
//        .attr("data-headline", function(d) { return d.main_headline; })
        .text(function(d) { return d.main_headline; })
        .style("text-transform", "capitalize")
    ;

    // Article Snippets
    var rectSnippets = rectInsides
        .append("p")
        .text(function(d) { return d.snippet; })
    ;

    // Article Dates
    var rectDates = rectInsides
        .append("cite")
        .text(function(d) {
            var pub_date = new Date(d.pub_date);
            return pub_date.getDate() + " " + months[pub_date.getMonth()] + " " + pub_date.getFullYear();
        })
    ;

    // Article Images
    rectImgs = rects.each(function(d) {
        if (d.multimedia_url) {
            d3.select(this)
                .append("div")
                .classed("imgContainer", true)
                .append("img")
                .attr("src", d.multimedia_url)
                .attr("class", d.multimedia_type)
            ;
        }
    });

    // Event Handler
    $timeline.on("mousemove", function() {
        var mouse = d3.mouse(this);
        // Change the fisheye distortion.
        xScale.distortion(xScaleDistortion).focus(mouse[0]);
        // Previously this was rects.call(position), and I'm not actually sure how that worked in the first place.
        rects.each(position);
    });

    // Return
    return $timeline;
};

// })();
<commit_msg>gimme that shit<commit_after>// (function() {
var data_url = flask_util.url_for("search", {fq: 'persons:("Obama, Barack")'});
// Available for debugging purposes
var data;

// Months
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"];

// Load the data from the server
d3.json(data_url, function(error, json) {
    if (error) return console.warn(error);
    data = json;
    // Call the init function...
    init(data);
});

var init = function() {
    if (! data) {
        throw "No data has been loaded! This is not good.";
    }
    var $container = d3.select("#container .content");
    var $svg = CreateSVGContainer($container);
    var $div = CreateDivContainer($container);
    // Set up a timeline for all the years represented in the data set.
    var $all_years_timeline = createTimeline(data, $svg);
    var $single_year_timeline = SingleYearTimeline(data.years[17].months[0], $div);
};

var CreateSVGContainer = function($container) {
    var svg_width = 1920;
    var svg_height = 300;

    return $container.append("svg")
        .attr("id", "svgContainer")
        .attr("width", svg_width + "px")
        .attr("height", svg_height + "px")
    ;
};

var CreateDivContainer = function($container) {
    var svg_width = 1920;
    var svg_height = 640;

    return $container.append("div")
        .attr("id", "divContainer")
        .attr("width", svg_width + "px")
        .attr("height", svg_height + "px")
    ;
};

var createTimeline = function(data, $svg) {

    //dealing with year data
    var maxHits;    // max number of articles
    var timeLength; // number of years or months being considered
    var timeData;   // the associated month or year data
    var graphName;
    if(data.years){
        maxHits    = data.max_hits;
        timeLength = data.years.length;
        timeData   = data.years;
        graphName  = "all_years_timeline";
    } else { // dealing with month data
        maxHits    = data.months_max_hits;
        timeLength = data.months.length;
        timeData   = data.months;
        graphName  = "month_timeline";
    }

//    console.log(data);
//    console.log(data.years);
    // SVG container width and height
    var svg_width = parseInt( $svg.style("width") );
    var svg_height = parseInt( $svg.style("height") );
    // Timeline group position and size
    var margin = 32;
    var timeline_width = svg_width - margin * 2;
    var timeline_height = svg_height / 2 - margin * 2;
    var timeline_x = margin;
    var timeline_y = svg_height / 2 + margin - 36;
    var timeline_y_centered = svg_height / 2 - timeline_height / 2;

    //data.max_hits
    var heightScale = d3.scale.log().domain([maxHits, 0.5]).range([timeline_height,0]);

    // Year rect size | data.years.length
    var year_rect_width = timeline_width / timeLength;

    // DOM setup
    var $timeline = $svg.append("g")
        //data.years
        .data([timeData])
        .attr("id", graphName)
        .attr("width", timeline_width + "px")
        .attr("height", timeline_height + "px")
        .attr("transform", "translate(" + timeline_x + ", " + 0 + ")") // timelineYCentered
    ;

    // SVG elements for each year
    var $year_groups = $timeline.selectAll("g")
        .data(function(d) { return d; })
    ;

    $year_groups
        .enter()
        .append("g")
        .classed("bar", true)
        .attr("data-year", function(d) { return d.year; })
        .attr("data-hits", function(d) { return d.hits; })
    ;

    var $year_bg_rects = $year_groups
        .append("rect")
        .classed("bg", true)
        .attr("x", function(d,i) { return (i * year_rect_width) + "px" })
        .attr("y", "0px" )
        .attr("width", year_rect_width + "px")
        .attr("height", timeline_height + "px")
        .attr("opacity", "0")
        .transition()
        .attr("opacity", "1.0")
    ;

    var $year_fg_rects = $year_groups
        .append("rect")
        .classed("fg", true)
        .attr("x", function(d,i) { return (i * year_rect_width) + "px" })
        .attr("y", function(d,i) {
            return timeline_height - heightScale(d.hits) + "px";
        })
        .attr("width", year_rect_width + "px")
        .attr("height", function(d,i) {
            return heightScale(d.hits) + "px";
        })
        // .attr("transform", "scale(1.0, 0.0)")
        // .attr("transform-origin", "50%, 50%")
        .attr("opacity", "0")
        .transition()
        .attr("height", function(d,i) {
            return heightScale(d.hits) + "px";
        })
        // .attr("transform", "scale(1.0, 1.0)")
        .attr("opacity", "1.0")
    ;

    var $year_labels = $year_groups
        .append("text")
        .classed("annotation", true)
        .text(function(d, i) {
            if(data.years)
                return d.year;
            else {
                return months[i] + ".";
            }
        })
        .attr("width", year_rect_width + "px")
        .attr("height", 24 + "px")
        .attr("x", function(d,i) { return (i * year_rect_width + year_rect_width / 2) + "px" })
        .attr("y", (timeline_height + 24) + "px")
    ;

    /*
    var $year_annotations = $year_groups
        .append("text")
        .classed("annotation", true)
        .text(function(d) { return d.hits; })
        .attr("width", year_rect_width + "px")
        .attr("height", 18 + "px")
        .attr("x", function(d,i) { return (i * year_rect_width + year_rect_width / 2) + "px" })
        .attr("y", (timeline_height + 42) + "px")
    ;
    */

//    $timeline
//        .transition()
//        .delay(500)
//        .duration(1000)
//        .attr("transform", "translate(" + timeline_x + ", " + timeline_y + ")")
//    ;

    var $single_year_timeline = null;

    // var $single_year_timeline = SingleYearTimeline($svg, data[17].docs);

    // Event Handlers
    $year_groups.selectAll("rect, text").on("mouseenter", function(d, i) {
        //console.log("Hello, hovering");
    });

    $year_groups.selectAll("rect, text").on("click", function(d, i) {
        console.log("Clicking");
        var $this = d3.select(this);
        var $parent = d3.select(this.parentNode);

        if ($parent.classed("active")) {
            return;
        } else {
            $timeline.select("g.year.active").classed("active", false);
            $parent.classed("active", true);
        }

        if ($single_year_timeline) {
            $single_year_timeline.remove();
//        } else {
        }

        // Should we display a month timeline or an article timeline next?
        if (d.docs == null) {
            //console.log(d);
            //$("#all_years_timeline").remove();
            $timeline
                .transition()
                .attr("transform", "translate(" + timeline_x + ", " + 150 + ")") // timelineYCentered
            createTimeline(d, $svg);
            //window.alert("We should show a month timeline for the year" + d.year + ".");
            //throw "Month timeline not implemented yet.";
        } else {
            $single_year_timeline = SingleYearTimeline($svg, d.docs);
            // Bring the single year timeline in
            $single_year_timeline
                .transition()
                .duration(1000)
                .attr("opacity", "1.0")
            ;
            // Slide the all years timeline down
            $timeline
                .transition()
                .duration(1000)
                .attr("transform", "translate(" + timeline_x + ", " + timeline_y + ")")
            ;
        }
    });

    // All Done
    return $timeline;
};

var initFisheye = function(numDocs, baseWidth) {
    var margin = {top: 20, right: 250, bottom: 30, left: 40};
    var width = baseWidth - margin.left - margin.right;
//    var height = window.innerHeight - margin.top - margin.bottom;

    return d3.fisheye.scale(d3.scale.linear).domain([0, numDocs]).range([0, baseWidth - 148]).focus(0);
};

var SingleYearTimeline = function(data, $html) {
    // Scaling function for fisheye distortion
    var xScale = initFisheye(data.docs.length, 1920);
    var xScaleDistortion = 10;
    // Set the fisheye distortion center right away
    xScale.distortion(xScaleDistortion).focus(960);

    // The position() function implements the fisheye lens distortion on the articles.
    var position = function(d, i) {
        var translateX = xScale(i);
        var translateY = 0;

        d3.select(this)
            .style("-webkit-transform", "translate(" + translateX + "px, " + translateY + "px)")
            .style("width", xScale(i + 1.0) - xScale(i) + "px")
//            .select(".rectInside")
//            .style("opacity", (xScale(i + 1.0) - xScale(i)) / xScale(data.docs.length))
        ;

//        console.log(xScale(i));
    };

    // SVG container width and height
    var svg_width = parseInt( $html.style("width") );
    var svg_height = parseInt( $html.style("height") );
    // Timeline group position and size
    var margin = 32;
    var timeline_width = svg_width - margin * 2;
    var timeline_height = svg_height / 2 - margin * 2;

    // DOM setup
    var $timeline = $html.append("div")
        .attr("id", "single_year_timeline")
        .style("width", timeline_width + "px")
        .style("height", 250 + "px")
        .data([data.docs])
    ;
    // Apply the translation transform
    $($timeline[0]).css({
        transform: "translate(" + margin + ", " + margin + "px)"
    });

    // Insert articles as <a> elements
    var rects = $timeline.selectAll("a.rect")
        .data(function(d) { return d })
        .enter()
        .append("a")
        .classed("rect", true)
        .attr("href", function(d) { return d.web_url; })
//        .attr("data-headline", function(d) { return d.main_headline; })
        // For debugging
        .attr("data-has-multimedia", function(d) { return (d.multimedia_url && true) == true; })
            // Set up the fisheye distortion right away.
        .each(position)
        .on("click", function(d, i) {
            d3.event.preventDefault();
            window.open(d.web_url);
        })
//        .style("-webkit-transform", function(d, i) {
//            return "translate(" + 15 * i + ", " + 0 + ")"
//        })
    ;

    // Set up an interior container for the rects
    var rectInsides = rects
        .append("div")
        .classed("rectInside", true)
    ;

    // Article headlines
    var rectHeadlines = rectInsides
        .append("h3")
//        .attr("data-headline", function(d) { return d.main_headline; })
        .text(function(d) { return d.main_headline; })
        .style("text-transform", "capitalize")
    ;

    // Article Snippets
    var rectSnippets = rectInsides
        .append("p")
        .text(function(d) { return d.snippet; })
    ;

    // Article Dates
    var rectDates = rectInsides
        .append("cite")
        .text(function(d) {
            var pub_date = new Date(d.pub_date);
            return pub_date.getDate() + " " + months[pub_date.getMonth()] + " " + pub_date.getFullYear();
        })
    ;

    // Article Images
    rectImgs = rects.each(function(d) {
        if (d.multimedia_url) {
            d3.select(this)
                .append("div")
                .classed("imgContainer", true)
                .append("img")
                .attr("src", d.multimedia_url)
                .attr("class", d.multimedia_type)
            ;
        }
    });

    // Event Handler
    $timeline.on("mousemove", function() {
        var mouse = d3.mouse(this);
        // Change the fisheye distortion.
        xScale.distortion(xScaleDistortion).focus(mouse[0]);
        // Previously this was rects.call(position), and I'm not actually sure how that worked in the first place.
        rects.each(position);
    });

    // Return
    return $timeline;
};

// })();
<|endoftext|>