<commit_before>(function($) {
devsite.devsite.Init($, {'FULL_SITE_SEARCH_ENABLED': 1, 'ENABLE_BLOCKED_VIDEO_PLACEHOLDER': 0, 'VERSION_HASH': '1d7f5dcee3', 'SITE_NAME': 'devsite', 'HISTORY_ENABLED': 1, 'SUBPATH': '', 'ENABLE_BLOCKED_LINK_TOOLTIP': 0, 'ALLOWED_HOSTS': ['.github.io'], 'BLOCK_RSS_FEEDS': 0, 'SCRIPTSAFE_DOMAIN': '.github.io'},
'[]', 'en',
true, '',
{"f62218c009ec029abef196bba5aa34cf": false, "039e5d84b87fd75807ffb37b7f1bbf2c": true, "098dafe57affddc137df300142652cfd": false, "cb025a64a50094835616312f4774a53d": true, "51470233c56fc1fde50f00b73c52b216": false, "752953480de00a336d911a46966cc16d": false, "700def1a83e356c06c0925afb05de4b0": false, "6749dcb526ce9bde6993550c7d928d24": true},
'/',
'https://ephellon.github.io/Paramour/');

  var timer, blink = false, last = {}, ltr = $("html").css(["writing-mode"]), isJS = false,
      swapicon = $("#swapButton span > div.docs-icon-redo, #swapButton span > div.docs-icon-undo"),
      runicons = $("#runButton div.docs-icon-run, #runButton div.docs-icon-debug"),
      icons = {
        swap: ["docs-icon-redo", "docs-icon-undo"],
        run: ["docs-icon-run", "docs-icon-debug"]
      },
      input, output, last_active, display, tinyurl, Paramour = Paramour || window.Paramour;

  if(Paramour == undefined)
    Paramour = function(string){return string};

  ltr = (ltr == "" || ltr == "vertical-lr");
  tinyurl = tinyurl || window.tinyurl;

  function swapIcons(element, pack, bool) {
    bool = bool == undefined? true: bool;
    return element
      .toggleClass(icons[pack][0], bool)
      .toggleClass(icons[pack][1], bool = !bool),
      bool;
  }

  function encodeHTML(string) {
    return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  }

  function decodeHTML(string) {
    return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  }

  function getCurrent(index) {
    return last_active = (last_active == undefined)?
      $(".pretty-input > textarea.active, .pretty-input > textarea.last-active, .pretty-input > textarea").slice(0, 1):
    (last_active instanceof $)?
      last_active:
    $(last_active),
      display = last_active.siblings(".prettyprint"),
      (index != undefined && index != null)? (display = display[index], last_active[index]): last_active;
  }

  function updateCursor() {
    var textarea  = getCurrent(0),
        start     = textarea.selectionStart,
        end       = textarea.selectionEnd,
        value     = textarea.value || "",
        direction = textarea.selectionDirection;

    if(direction == undefined || direction == null)
      direction = ((last.start > start || end < last.end) && ltr)? "left": "right";
    else
      direction = (direction != "forward" && ltr)? "left": "right";

    if((last.start = start) == (last.end = end))
      return encodeHTML(value.slice(0, start)) +
        '' +
        encodeHTML(value.slice(end, value.length));
    else
      return encodeHTML(value.slice(0, start)) +
        '' +
        encodeHTML(value.slice(start, end)) +
        '' +
        encodeHTML(value.slice(end, value.length));
  }

  function updateDisplay() {
    return updateCursor() + "
";
  }

  function updateHTML() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      getCurrent();
      display.html(updateDisplay);
      prettyPrint();
    }, 100);
  }

  $(".pretty-input > textarea")
  .on("keyup", function(event) {
    last["in"] = input = ($(event.target).val() || "");
    updateHTML();
  })
  .on("mousemove", updateHTML)
  .on("mousedown", updateHTML)
  .on("scroll", function(event) {
    var T = "scrollTop", L = "scrollLeft",
        t = getCurrent(0), s = display,
        a = t[T], b = t[L], o = {};

    if(a == (last[t]||o)[T] && b == (last[t]||o)[L])
      return;
    else
      s[T] = a, s[L] = b;

    if(a > s[T])
      last[T] = t[T] = s[T] - 1;
    if(b > s[L])
      last[L] = t[L] = s[L] - 1;
  })
  .on("focus", function(event) {
    $(last_active = event.target).toggleClass("active", true);
  })
  .on("blur", function(event) {
    $(".pretty-input > textarea.last-active")
      .toggleClass("last-active", false);
    $(event.target)
      .toggleClass("active", false)
      .toggleClass("last-active", true);
  });

  $("#saveButton").click(function(event) {

  });

  $("#runButton").click(function(event) {
    var self = $(event.target), textarea = getCurrent();

    try {
      eval(last["out"] = output = Paramour(input));
      last.error = undefined;
      swapIcons(runicons, "run", isJS = true);
      self.attr("title", "Run");
      display.toggleClass("lang-paramour", false).toggleClass("lang-javascript", true);
    } catch(error) {
      last.error = error;
      swapIcons(runicons, "run", isJS = false);
      self.attr("title", "Uncaught: " + error.message);
      display.toggleClass("lang-paramour", true).toggleClass("lang-javascript", false);
      return alert(error);
    }

    isJS = false;
    $("#swapButton").click();
  });

  $("#linkButton").click(function(event) {
    if(!tinyurl)
      throw Error("The tinyurl API is not loaded.");
    var textarea = getCurrent(),
        url      = "https://ephellon.github.io/Paramour/extras/?code=" + encodeURIComponent(textarea.val()),
        self     = $(event.target);
    tinyurl(url, function() {
      var url = tinyurl.url;
      try {
        alert("The URL [" + url + "] was " + (document.execCommand("copy", false, url)? "": "not ") + "copied to the clipboard.");
      } catch(e) {
        alert("The URL [" + url + "] cannot be copied to the clipboard.");
      }
    });
  });

  $("#helpButton").click(function(event) {
    window.open("https://ephellon.github.io/Paramour/help/", "blank_");
  });

  $("#swapButton").click(function(event) {
    var textarea = getCurrent();

    isJS = swapIcons(swapicon, "swap", isJS);

    event.target.setAttribute("title", "Switch to " + (!isJS? "JavaScript": "Paramour"));

    last["out"] = output = Paramour(input);

    if(!isJS)
      textarea.val(input);
    else
      textarea.val(output);

    updateHTML();
  });

  last_active = getCurrent(), display.html(last_active.val());
  input = last_active.val() || "";

  setInterval(function() {
    $(".cursor").css({"border-color": (blink = !blink)? "#ffffff": "#212121"});
  }, 500);

})(jQuery);
      devsite.localInit = function() {};
<commit_msg>Update main.js<commit_after>(function($) {
devsite.devsite.Init($, {'FULL_SITE_SEARCH_ENABLED': 1, 'ENABLE_BLOCKED_VIDEO_PLACEHOLDER': 0, 'VERSION_HASH': '1d7f5dcee3', 'SITE_NAME': 'devsite', 'HISTORY_ENABLED': 1, 'SUBPATH': '', 'ENABLE_BLOCKED_LINK_TOOLTIP': 0, 'ALLOWED_HOSTS': ['.github.io'], 'BLOCK_RSS_FEEDS': 0, 'SCRIPTSAFE_DOMAIN': '.github.io'},
'[]', 'en',
true, '',
{"f62218c009ec029abef196bba5aa34cf": false, "039e5d84b87fd75807ffb37b7f1bbf2c": true, "098dafe57affddc137df300142652cfd": false, "cb025a64a50094835616312f4774a53d": true, "51470233c56fc1fde50f00b73c52b216": false, "752953480de00a336d911a46966cc16d": false, "700def1a83e356c06c0925afb05de4b0": false, "6749dcb526ce9bde6993550c7d928d24": true},
'/',
'https://ephellon.github.io/Paramour/');

  var timer, blink = false, last = {}, ltr = $("html").css(["writing-mode"]), isJS = false,
      swapicon = $("#swapButton span > div.docs-icon-redo, #swapButton span > div.docs-icon-undo"),
      runicons = $("#runButton div.docs-icon-run, #runButton div.docs-icon-debug"),
      icons = {
        swap: ["docs-icon-redo", "docs-icon-undo"],
        run: ["docs-icon-run", "docs-icon-debug"]
      },
      input, output, last_active, display, tinyurl, Paramour = Paramour || window.Paramour;

  if(Paramour == undefined)
    Paramour = function(string){return string};

  ltr = (ltr == "" || ltr == "vertical-lr");
  tinyurl = tinyurl || window.tinyurl;

  function swapIcons(element, pack, bool) {
    bool = bool == undefined? true: bool;
    return element
      .toggleClass(icons[pack][0], bool)
      .toggleClass(icons[pack][1], bool = !bool),
      bool;
  }

  function encodeHTML(string) {
    return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  }

  function decodeHTML(string) {
    return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  }

  function getCurrent(index) {
    return last_active = (last_active == undefined)?
      $(".pretty-input > textarea.active, .pretty-input > textarea.last-active, .pretty-input > textarea").slice(0, 1):
    (last_active instanceof $)?
      last_active:
    $(last_active),
      display = last_active.siblings(".prettyprint"),
      (index != undefined && index != null)? (display = display[index], last_active[index]): last_active;
  }

  function updateCursor() {
    var textarea  = getCurrent(0),
        start     = textarea.selectionStart,
        end       = textarea.selectionEnd,
        value     = textarea.value || "",
        direction = textarea.selectionDirection;

    if(direction == undefined || direction == null)
      direction = ((last.start > start || end < last.end) && ltr)? "left": "right";
    else
      direction = (direction != "forward" && ltr)? "left": "right";

    if((last.start = start) == (last.end = end))
      return encodeHTML(value.slice(0, start)) +
        '' +
        encodeHTML(value.slice(end, value.length));
    else
      return encodeHTML(value.slice(0, start)) +
        '' +
        encodeHTML(value.slice(start, end)) +
        '' +
        encodeHTML(value.slice(end, value.length));
  }

  function updateDisplay() {
    return updateCursor() + "
";
  }

  function updateHTML() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      getCurrent();
      display.html(updateDisplay);
      prettyPrint();
    }, 100);
  }

  $(".pretty-input > textarea")
  .on("keyup", function(event) {
    last["in"] = input = ($(event.target).val() || "");
    updateHTML();
  })
  .on("mousemove", updateHTML)
  .on("mousedown", updateHTML)
  .on("scroll", function(event) {
    var T = "scrollTop", L = "scrollLeft",
        t = getCurrent(0), s = display,
        a = t[T], b = t[L], o = {};

    if(a == (last[t]||o)[T] && b == (last[t]||o)[L])
      return;
    else
      s[T] = a, s[L] = b;

    if(a > s[T])
      last[T] = t[T] = s[T] - 1;
    if(b > s[L])
      last[L] = t[L] = s[L] - 1;
  })
  .on("focus", function(event) {
    $(last_active = event.target).toggleClass("active", true);
  })
  .on("blur", function(event) {
    $(".pretty-input > textarea.last-active")
      .toggleClass("last-active", false);
    $(event.target)
      .toggleClass("active", false)
      .toggleClass("last-active", true);
  });

  $("#saveButton").click(function(event) {

  });

  $("#runButton").click(function(event) {
    var self = $(event.target), textarea = getCurrent();

    try {
      eval(last["out"] = output = Paramour(input));
      last.error = undefined;
      swapIcons(runicons, "run", isJS = true);
      self.attr("title", "Run");
      display.toggleClass("lang-paramour", false).toggleClass("lang-javascript", true);
    } catch(error) {
      last.error = error;
      swapIcons(runicons, "run", isJS = false);
      self.attr("title", "Uncaught: " + error.message);
      display.toggleClass("lang-paramour", true).toggleClass("lang-javascript", false);
      return alert(error);
    }

    isJS = false;
    $("#swapButton").click();
  });

  $("#linkButton").click(function(event) {
    if(!tinyurl)
      throw Error("The tinyurl API is not loaded.");
    isJS = true;
    $("#swapButton").click();
    var textarea = getCurrent(),
        url      = "https://ephellon.github.io/Paramour/extras/?code=" + encodeURIComponent(textarea.val()),
        self     = $(event.target);
    tinyurl(url, function() {
      var url = tinyurl.url;
      try {
        alert("The URL [" + url + "] was " + (document.execCommand("copy", false, url)? "": "not ") + "copied to the clipboard.");
      } catch(e) {
        alert("The URL [" + url + "] cannot be copied to the clipboard.");
      }
    });
  });

  $("#helpButton").click(function(event) {
    window.open("https://ephellon.github.io/Paramour/help/", "blank_");
  });

  $("#swapButton").click(function(event) {
    var textarea = getCurrent();

    isJS = swapIcons(swapicon, "swap", isJS);

    event.target.setAttribute("title", "Switch to " + (!isJS? "JavaScript": "Paramour"));

    last["out"] = output = Paramour(input);

    if(!isJS)
      textarea.val(input);
    else
      textarea.val(output);

    updateHTML();
  });

  last_active = getCurrent(), display.html(last_active.val());
  input = last_active.val() || "";

  setInterval(function() {
    $(".cursor").css({"border-color": (blink = !blink)? "#ffffff": "#212121"});
  }, 500);

})(jQuery);
      devsite.localInit = function() {};
<|endoftext|>


<commit_before>var planet = require('../../planet'),
	http = require('http'),
	io = require('socket.io');

exports.setup = function(Tests){

	Tests.describe('Planet Server: Constructor', function(it){

		it('should start new planet', function(expect){

			var server = http.createServer(),
				socket = io.listen(server, {'log level': 1});

			var mercury = new planet(socket, {});

			server.listen(8101, '127.0.0.1');

			mercury.on('listening', function(location, port){
				expect(mercury).toBeAnInstanceOf(planet);
				expect(this).toBeAnInstanceOf(planet);

				expect(location).toBeType('string');
				expect(port).toBeType('number');

				expect(location).toBe('127.0.0.1');
				expect(port).toBe(8101);

				mercury.destroy();
				server.close();
			});

		});

		it('should start planet', function(expect){

			var server = http.createServer(),
				socket = io.listen(server, {'log level': 1});

			var venus = planet(socket, {});

			server.listen(8102);

			venus.on('listening', function(location, port){
				expect(port).toBe(8102);
				venus.destroy();
				server.close();
			});
		});

		it('should return planet cli help', function(expect){

			var exec = require('child_process').exec;

			exec('./bin/planet --help', function(error, stdout, stderr){
				expect(error).toBeNull();
				expect(stdout).toMatch(/Usage:/);
				expect(stdout).toMatch(/Available options:/);
			});

		});

		it('should start planet from cli', function(expect){

			var spawn = require('child_process').spawn;

			var child = spawn('./bin/planet', ['--port', 8103]);

			child.stdout.on('data', function(data){
				data = data.toString();
				expect(data).toMatch(/Planet started/);
				expect(data).toMatch(/8103/);
				child.kill();
			});

			child.stderr.on('data', function(error){
				console.log('error', error.toString());
			});

		});

	});

};
<commit_msg>adds tests without http server<commit_after>var planet = require('../../planet'),
	http = require('http'),
	io = require('socket.io');

exports.setup = function(Tests){

	Tests.describe('Planet Server: Constructor', function(it){

		it('should start new planet', function(expect){

			var server = http.createServer(),
				socket = io.listen(server, {'log level': 1});

			var mercury = new planet(socket, {});

			server.listen(8101, '127.0.0.1');

			mercury.on('listening', function(location, port){
				expect(mercury).toBeAnInstanceOf(planet);
				expect(this).toBeAnInstanceOf(planet);

				expect(location).toBeType('string');
				expect(port).toBeType('number');

				expect(location).toBe('127.0.0.1');
				expect(port).toBe(8101);

				mercury.destroy();
				server.close();
			});

		});

		it('should start planet', function(expect){

			var server = http.createServer(),
				socket = io.listen(server, {'log level': 1});

			var venus = planet(socket, {});

			server.listen(8102);

			venus.on('listening', function(location, port){
				expect(port).toBe(8102);
				venus.destroy();
				server.close();
			});
		});

		it('should start planet without a http server', function(expect){

			var socket = io.listen(8103, {
				'log level': 1
			});

			planet(socket, {})
				.on('listening', function(location, port){
					expect(port).toBe(8103);

					require('socket.io-client')
						.connect('//:8103')
						.on('connect', function(){
							this.disconnect();
						});
				})
				.on('connection', function(socket){
					expect(socket).toBeType('object');
				})
				.on('disconnect', function(socket){
					expect(socket).toBeType('object');
					this.destroy();
				});
		});

		it('should return planet cli help', function(expect){

			var exec = require('child_process').exec;

			exec('./bin/planet --help', function(error, stdout, stderr){
				expect(error).toBeNull();
				expect(stdout).toMatch(/Usage:/);
				expect(stdout).toMatch(/Available options:/);
			});

		});

		it('should start planet from cli', function(expect){

			var spawn = require('child_process').spawn;

			var child = spawn('./bin/planet', ['--port', 8104]);

			child.stdout.on('data', function(data){
				data = data.toString();
				expect(data).toMatch(/Planet started/);
				expect(data).toMatch(/8104/);
				child.kill();
			});

			child.stderr.on('data', function(error){
				console.log('error', error.toString());
			});

		});

	});

};
<|endoftext|>


<commit_before>var Chrome = {
    init: function () {

    },

    getAllWindows: function (callback) {
        chrome.windows.getAll({
            populate: true
        }, Utils.errorLogger(Utils.handleUndefinedCallback(callback)));
    },

    getWindow: function (windowId, callback) {
        chrome.windows.get(windowId, {
            populate: true
        }, Utils.errorLogger(Utils.handleUndefinedCallback(callback)));
    },

    findPinnedTab: function (urls, window) {
        if (!window.tabs)
            return undefined;
        return window.tabs.filter(function (x) {
            return (urls.filter(function (y) {
                return y === x.url;
            }).length > 0) && x.pinned;
        })[0];
    },

    createPinnedTab: function (window, url, favIconUrl, callback) {
        chrome.tabs.create({
            url: url,
            pinned: true,
            active: false,
            windowId: window.id
        }, Utils.errorLogger(Utils.handleUndefinedCallback(callback)));
    },

    pinTab: function (tabId, callback) {
        chrome.tabs.update(tabId, {
            pinned: true
        }, Utils.errorLogger(Utils.handleUndefinedCallback(callback)));
    },

    activateTab: function (tabId, callback) {
        chrome.tabs.update(tabId, {
            active: true
        }, Utils.errorLogger(Utils.handleUndefinedCallback(callback)));
    },

    moveTabs: function (tabIds, targetWindowId, index, callback, startTime) {

        startTime = startTime || Date.now();

        if (Date.now() - startTime > 20000) {
            console.error('Moving of tabs failed for 1 minute. Giving up...');
            return;
        }

        chrome.tabs.move(tabIds, {
            windowId: targetWindowId,
            index: index
        }, Utils.errorLogger(function (tabs) {
            if (!(tabs instanceof Array))
                tabs = [ tabs ];

            var lastError = chrome.runtime.lastError;
            if (tabs === undefined || lastError !== undefined) {
                console.warn("Couldn't move tabs.");
                if (lastError !== undefined && lastError.message)
                    console.warn('Reason: ' + lastError.message);
                setTimeout(function () {
                    Chrome.moveTabs(tabIds, targetWindowId, index, callback, startTime);
                }, 500);
            }
            else {
                Utils.handleUndefinedCallback(callback(tabs));
            }
        }));
    }
};<commit_msg>Improve error logging when interacting with Chrome<commit_after>var Chrome = {
    init: function () {

    },

    errorLogger: function (f) {
        return function (args) {
            if(chrome.runtime.lastError === undefined)
                Utils.errorLogger(Utils.handleUndefinedCallback(f)).apply(this, arguments);
            else
                console.error(chrome.runtime.lastError.message);
        };
    },
    getAllWindows: function (callback) {
        chrome.windows.getAll({
            populate: true
        }, Chrome.errorLogger(callback));
    },

    getWindow: function (windowId, callback) {
        chrome.windows.get(windowId, {
            populate: true
        }, Chrome.errorLogger(callback));
    },

    findPinnedTab: function (urls, window) {
        if (!window.tabs)
            return undefined;
        return window.tabs.filter(function (x) {
            return (urls.filter(function (y) {
                return y === x.url;
            }).length > 0) && x.pinned;
        })[0];
    },

    createPinnedTab: function (window, url, favIconUrl, callback) {
        chrome.tabs.create({
            url: url,
            pinned: true,
            active: false,
            windowId: window.id
        }, Chrome.errorLogger(callback));
    },

    pinTab: function (tabId, callback) {
        chrome.tabs.update(tabId, {
            pinned: true
        }, Chrome.errorLogger(callback));
    },

    activateTab: function (tabId, callback) {
        chrome.tabs.update(tabId, {
            active: true
        }, Chrome.errorLogger(callback));
    },

    moveTabs: function (tabIds, targetWindowId, index, callback, startTime) {

        startTime = startTime || Date.now();

        if (Date.now() - startTime > 20000) {
            console.error('Moving of tabs failed for 1 minute. Giving up...');
            return;
        }

        chrome.tabs.move(tabIds, {
            windowId: targetWindowId,
            index: index
        }, Chrome.errorLogger(function (tabs) {
            if (!(tabs instanceof Array))
                tabs = [ tabs ];

            var lastError = chrome.runtime.lastError;
            if (tabs === undefined || lastError !== undefined) {
                console.warn("Couldn't move tabs.");
                if (lastError !== undefined && lastError.message)
                    console.warn('Reason: ' + lastError.message);
                setTimeout(function () {
                    Chrome.moveTabs(tabIds, targetWindowId, index, callback, startTime);
                }, 500);
            }
            else {
                Utils.handleUndefinedCallback(callback(tabs));
            }
        }));
    }
};<|endoftext|>


<commit_before>var ver = "0.1"

var frontpage = [
	"                            _           _         _       _   ",
	"                           | |_ ___ ___| |_   ___| |_ ___| |_ ",
	"                           |   |_ ||  _| '_| |  _|   |_ ||  _|",
	"                           |_|_|__/|___|_,_|.|___|_|_|__/|_|  ",
	"",
	"",
	"Welcome to hack.chat, a minimal, distraction-free chat application.",
	"You are running hackers.chat.client" + ver
	"Original code by @AndrewBelt, Custom client by @ac1dburnn"
	"Channels are created and joined by going to https://hack.chat/?your-channel. There are no channel lists, so a secret channel name can be used for private discussions.",
	"",
	"Here are some pre-made channels you can join:",
	"?lobby ?meta ?random",
	"?technology ?programming",
	"?math ?physics ?asciiart",
	"And here's a random one generated just for you: ?" + Math.random().toString(36).substr(2, 8),
	"",
	"",
	"Formatting:",
	"Whitespace is preserved, so source code can be pasted verbatim.",
	"Surround LaTeX with a dollar sign for inline style $\\zeta(2) = \\pi^2/6$, and two dollars for display.",
	"$$\\int_0^1 \\int_0^1 \\frac{1}{1-xy} dx dy = \\frac{\\pi^2}{6}$$",
	"",
	"GitHub repo: https://github.com/AndrewBelt/hack.chat",
	"Server and client released under the GNU General Public License.",
	"No message history is retained on the hack.chat server.",
].join("\n")

var hccFront = [
	"",
	" _           _                     _       _  ",
	"| |_ ___ ___| |_ ___ ___ ___   ___| |_ ___| |_ ",
	"|   | .'|  _| '_| -_|  _|_ -|_|  _|   | .'|  _|",
	"|_|_|__,|___|_,_|___|_| |___|_|___|_|_|__,|_|  ",
	"A hackers client for hack.chat - by Kate Libby",
	"Menu:",
	"Join|Original Homepage|Settings|About",
	"Popular Channels:",
	"Channel History:",
	"Friends:",
	"Bookmarked Channels:",
	"",
].join("\n")

function $(query) {return document.querySelector(query)}

window.onload = function() {
	myChannel = window.location.search.replace(/^\?/, '')
	if (myChannel == '') {
		pushMessage('', frontpage)
		$('#footer').classList.add('hidden')
		$('#sidebar').classList.add('hidden')
	}
	else {
		join(myChannel)
	}
}

var ws
var myNick
var myChannel
var lastSent = ""

function join(channel) {
	if (document.domain == 'hack.chat') {
		// For https://hack.chat/
		ws = new WebSocket('wss://hack.chat/chat-ws')
	}
	else {
		// for local installs
		ws = new WebSocket('ws://' + document.domain + ':6060')
	}

	ws.onopen = function() {
		myNick = prompt('Nickname:')
		if (myNick) {
			send({cmd: 'join', channel: channel, nick: myNick})
		}
	}

	ws.onmessage = function(message) {
		var args = JSON.parse(message.data)
		var cmd = args.cmd
		var command = COMMANDS[cmd]
		command.call(null, args)
	}

	ws.onclose = function() {
		pushMessage('[HCC]', "Server disconnected - Reconnecting", Date.now(), 'warn')
		if (document.domain == 'hack.chat') {
			ws = new WebSocket('wss://hack.chat/chat-ws')

		} else {
			ws = new WebSocket('ws://' + document.domain + ':6060')
		}
	}

var COMMANDS = {
	chat: function(args) {
		var cls
		if (args.admin) {
			cls = 'admin'
		}
		else if (myNick == args.nick) {
			cls = 'me'
		}
		pushMessage(args.nick, args.text, args.time, cls)
	},
	info: function(args) {
		pushMessage('*', args.text, args.time, 'info')
	},
	warn: function(args) {
		pushMessage('!', args.text, args.time, 'warn')
	},
	onlineSet: function(args) {
		var nicks = args.nicks
		usersClear()
		nicks.forEach(function(nick) {
			userAdd(nick)
		})
		pushMessage('*', "Users online: " + nicks.join(", "), Date.now(), 'info')
	},
	onlineAdd: function(args) {
		var nick = args.nick
		userAdd(nick)
		if ($('#joined-left').checked) {
			pushMessage('*', nick + " joined", Date.now(), 'info')
		}
	},
	onlineRemove: function(args) {
		var nick = args.nick
		userRemove(nick)
		if ($('#joined-left').checked) {
			pushMessage('*', nick + " left", Date.now(), 'info')
		}
	},
}

function pushMessage(nick, text, time, cls) {
	var messageEl = document.createElement('div')
	messageEl.classList.add('message')
	if (cls) {
		messageEl.classList.add(cls)
	}

	var nickEl = document.createElement('span')
	nickEl.classList.add('nick')
	nickEl.textContent = nick || ''
	if (time) {
		var date = new Date(time)
		nickEl.title = date.toLocaleString()
	}
	nickEl.onclick = function() {
		insertAtCursor("@" + nick + " ")
		$('#chatinput').focus()
	}
	messageEl.appendChild(nickEl)

	var textEl = document.createElement('pre')
	textEl.classList.add('text')

	textEl.textContent = text || ''
	textEl.innerHTML = textEl.innerHTML.replace(/(\?|https?:\/\/)\S+?(?=[,.!?:)]?\s|$)/g, parseLinks)
	try {
		renderMathInElement(textEl, {delimiters: [
		  {left: "$$", right: "$$", display: true},
		  {left: "$", right: "$", display: false},
		]})
	}
	catch (e) {
		console.warn(e)
	}
	messageEl.appendChild(textEl)

	var atBottom = isAtBottom()
	$('#messages').appendChild(messageEl)
	if (atBottom) {
		window.scrollTo(0, document.body.scrollHeight)
	}

	unread += 1
	updateTitle()
}

function insertAtCursor(text) {
	var input = $('#chatinput')
	var start = input.selectionStart || 0
	input.value = input.value.substr(0, start) + text + input.value.substr(start)
}

function send(data) {
	ws.send(JSON.stringify(data))
}

function parseLinks(g0) {
	var a = document.createElement('a')
	a.innerHTML = g0
	var url = a.textContent
	if (url[0] == '?') {
		url = "/" + url
	}
	a.href = url
	a.target = '_blank'
	return a.outerHTML
}

var windowActive = true
var unread = 0

window.onfocus = function() {
	windowActive = true
	updateTitle()
}

window.onblur = function() {
	windowActive = false
}

window.onscroll = function() {
	if (isAtBottom()) {
		updateTitle()
	}
}

function isAtBottom() {
	return (window.innerHeight + window.scrollY) >= (document.body.scrollHeight - 1)
}

function updateTitle() {
	if (windowActive && isAtBottom()) {
		unread = 0
	}

	var title
	if (myChannel) {
		title = "?" + myChannel
	}
	else {
		title = "hack.chat"
	}
	if (unread > 0) {
		title = '(' + unread + ') ' + title
	}
	document.title = title
}

/* footer */

$('#footer').onclick = function() {
	$('#chatinput').focus()
}

$('#chatinput').onkeydown = function(e) {
	if (e.keyCode == 13 /* ENTER */ && !e.shiftKey) {
		if (e.target.value != '') {
			var text = e.target.value
			e.target.value = ''
			send({cmd: 'chat', text: text})
			lastSent = text
			updateInputSize()
		}
		e.preventDefault()
	}
	else if (e.keyCode == 38 /* UP */) {
		// Restore previous sent message
		if (e.target.value == '') {
			e.target.value = lastSent
			e.target.selectionStart = e.target.value.length
			updateInputSize()
			e.preventDefault()
		}
	}
}

function updateInputSize() {
	var atBottom = isAtBottom()

	var input = $('#chatinput')
	input.style.height = 0
	input.style.height = input.scrollHeight + 'px'
	document.body.style.marginBottom = $('#footer').offsetHeight + 'px'

	if (atBottom) {
		window.scrollTo(0, document.body.scrollHeight)
	}
}

$('#chatinput').oninput = function() {
	updateInputSize()
}

updateInputSize()
$('#chatinput').focus()

/* sidebar */

$('#sidebar').onmouseenter = function() {
	$('#sidebar-content').classList.remove('hidden')
}

$('#sidebar').onmouseleave = function() {
	if (!$('#pin-sidebar').checked) {
		$('#sidebar-content').classList.add('hidden')
	}
}

$('#clear-history').onclick = function() {
	// Delete children elements
	var messages = $('#messages')
	while (messages.firstChild) {
		messages.removeChild(messages.firstChild)
	}
}

function userAdd(nick) {
	var user = document.createElement('li')
	user.textContent = nick
	user.onclick = userInvite
	$('#users').appendChild(user)
}

function userRemove(nick) {
	var users = $('#users')
	var children = users.children
	for (var i = 0; i < children.length; i++) {
		var user = children[i]
		if (user.textContent == nick) {
			users.removeChild(user)
		}
	}
}

function usersClear() {
	var users = $('#users')
	while (users.firstChild) {
		users.removeChild(users.firstChild)
	}
}

function userInvite(e) {
	var nick = e.target.textContent
	send({cmd: 'invite', nick: nick})
}

/* color scheme switcher */

var schemes = [
	'android',
	'atelier-dune',
	'atelier-forest',
	'atelier-heath',
	'atelier-lakeside',
	'atelier-seaside',
	'bright',
	'chalk',
	'default',
	'eighties',
	'greenscreen',
	'mocha',
	'monokai',
	'nese',
	'ocean',
	'pop',
	'railscasts',
	'solarized',
	'tomorrow',
]

var currentScheme = 'atelier-dune'

function setScheme(scheme) {
	currentScheme = scheme
	$('#scheme-link').href = "/schemes/" + scheme + ".css"
	if (localStorage) {
		localStorage['scheme'] = scheme
	}
}

// Add scheme options to dropdown selector
schemes.forEach(function(scheme) {
	var option = document.createElement('option')
	option.textContent = scheme
	option.value = scheme
	$('#scheme-selector').appendChild(option)
})

$('#scheme-selector').onchange = function(e) {
	setScheme(e.target.value)
}

// Load and select scheme from local storage if available
if (localStorage) {
	var scheme = localStorage['scheme']
	if (scheme) {
		setScheme(scheme)
	}
}

$('#scheme-selector').value = currentScheme
<commit_msg>Only connects to hack.chat now, cant be fucked adding in menu atm<commit_after>var ver = "0.1"

var frontpage = [
	"                            _           _         _       _   ",
	"                           | |_ ___ ___| |_   ___| |_ ___| |_ ",
	"                           |   |_ ||  _| '_| |  _|   |_ ||  _|",
	"                           |_|_|__/|___|_,_|.|___|_|_|__/|_|  ",
	"",
	"",
	"Welcome to hack.chat, a minimal, distraction-free chat application.",
	"You are running hackers.chat.client" + ver
	"Original code by @AndrewBelt, Custom client by @ac1dburnn"
	"Channels are created and joined by going to https://hack.chat/?your-channel. There are no channel lists, so a secret channel name can be used for private discussions.",
	"",
	"Here are some pre-made channels you can join:",
	"?lobby ?meta ?random",
	"?technology ?programming",
	"?math ?physics ?asciiart",
	"And here's a random one generated just for you: ?" + Math.random().toString(36).substr(2, 8),
	"",
	"",
	"Formatting:",
	"Whitespace is preserved, so source code can be pasted verbatim.",
	"Surround LaTeX with a dollar sign for inline style $\\zeta(2) = \\pi^2/6$, and two dollars for display.",
	"$$\\int_0^1 \\int_0^1 \\frac{1}{1-xy} dx dy = \\frac{\\pi^2}{6}$$",
	"",
	"GitHub repo: https://github.com/AndrewBelt/hack.chat",
	"Server and client released under the GNU General Public License.",
	"No message history is retained on the hack.chat server.",
].join("\n")

var hccFront = [
	"",
	" _           _                     _       _  ",
	"| |_ ___ ___| |_ ___ ___ ___   ___| |_ ___| |_ ",
	"|   | .'|  _| '_| -_|  _|_ -|_|  _|   | .'|  _|",
	"|_|_|__,|___|_,_|___|_| |___|_|___|_|_|__,|_|  ",
	"A hackers client for hack.chat - by Kate Libby",
	"Menu:",
	"Join|Original Homepage|Settings|About",
	"Popular Channels:",
	"Channel History:",
	"Friends:",
	"Bookmarked Channels:",
	"",
].join("\n")

function $(query) {return document.querySelector(query)}

window.onload = function() {
	myChannel = window.location.search.replace(/^\?/, '')
	if (myChannel == '') {
		pushMessage('', frontpage)
		$('#footer').classList.add('hidden')
		$('#sidebar').classList.add('hidden')
	}
	else {
		join(myChannel)
	}
}

var ws
var myNick
var myChannel
var lastSent = ""

function join(channel) {
		ws = new WebSocket('wss://hack.chat/chat-ws')
	}

	ws.onopen = function() {
		myNick = prompt('Nickname:')
		if (myNick) {
			send({cmd: 'join', channel: channel, nick: myNick})
		}
	}

	ws.onmessage = function(message) {
		var args = JSON.parse(message.data)
		var cmd = args.cmd
		var command = COMMANDS[cmd]
		command.call(null, args)
	}

	ws.onclose = function() {
		pushMessage('[HCC]', "Server disconnected - Reconnecting", Date.now(), 'warn')
		ws = new WebSocket('wss://hack.chat/chat-ws')
	}

var COMMANDS = {
	chat: function(args) {
		var cls
		if (args.admin) {
			cls = 'admin'
		}
		else if (myNick == args.nick) {
			cls = 'me'
		}
		pushMessage(args.nick, args.text, args.time, cls)
	},
	info: function(args) {
		pushMessage('*', args.text, args.time, 'info')
	},
	warn: function(args) {
		pushMessage('!', args.text, args.time, 'warn')
	},
	onlineSet: function(args) {
		var nicks = args.nicks
		usersClear()
		nicks.forEach(function(nick) {
			userAdd(nick)
		})
		pushMessage('*', "Users online: " + nicks.join(", "), Date.now(), 'info')
	},
	onlineAdd: function(args) {
		var nick = args.nick
		userAdd(nick)
		if ($('#joined-left').checked) {
			pushMessage('*', nick + " joined", Date.now(), 'info')
		}
	},
	onlineRemove: function(args) {
		var nick = args.nick
		userRemove(nick)
		if ($('#joined-left').checked) {
			pushMessage('*', nick + " left", Date.now(), 'info')
		}
	},
}

function pushMessage(nick, text, time, cls) {
	var messageEl = document.createElement('div')
	messageEl.classList.add('message')
	if (cls) {
		messageEl.classList.add(cls)
	}

	var nickEl = document.createElement('span')
	nickEl.classList.add('nick')
	nickEl.textContent = nick || ''
	if (time) {
		var date = new Date(time)
		nickEl.title = date.toLocaleString()
	}
	nickEl.onclick = function() {
		insertAtCursor("@" + nick + " ")
		$('#chatinput').focus()
	}
	messageEl.appendChild(nickEl)

	var textEl = document.createElement('pre')
	textEl.classList.add('text')

	textEl.textContent = text || ''
	textEl.innerHTML = textEl.innerHTML.replace(/(\?|https?:\/\/)\S+?(?=[,.!?:)]?\s|$)/g, parseLinks)
	try {
		renderMathInElement(textEl, {delimiters: [
		  {left: "$$", right: "$$", display: true},
		  {left: "$", right: "$", display: false},
		]})
	}
	catch (e) {
		console.warn(e)
	}
	messageEl.appendChild(textEl)

	var atBottom = isAtBottom()
	$('#messages').appendChild(messageEl)
	if (atBottom) {
		window.scrollTo(0, document.body.scrollHeight)
	}

	unread += 1
	updateTitle()
}

function insertAtCursor(text) {
	var input = $('#chatinput')
	var start = input.selectionStart || 0
	input.value = input.value.substr(0, start) + text + input.value.substr(start)
}

function send(data) {
	ws.send(JSON.stringify(data))
}

function parseLinks(g0) {
	var a = document.createElement('a')
	a.innerHTML = g0
	var url = a.textContent
	if (url[0] == '?') {
		url = "/" + url
	}
	a.href = url
	a.target = '_blank'
	return a.outerHTML
}

var windowActive = true
var unread = 0

window.onfocus = function() {
	windowActive = true
	updateTitle()
}

window.onblur = function() {
	windowActive = false
}

window.onscroll = function() {
	if (isAtBottom()) {
		updateTitle()
	}
}

function isAtBottom() {
	return (window.innerHeight + window.scrollY) >= (document.body.scrollHeight - 1)
}

function updateTitle() {
	if (windowActive && isAtBottom()) {
		unread = 0
	}

	var title
	if (myChannel) {
		title = "?" + myChannel
	}
	else {
		title = "hack.chat"
	}
	if (unread > 0) {
		title = '(' + unread + ') ' + title
	}
	document.title = title
}

/* footer */

$('#footer').onclick = function() {
	$('#chatinput').focus()
}

$('#chatinput').onkeydown = function(e) {
	if (e.keyCode == 13 /* ENTER */ && !e.shiftKey) {
		if (e.target.value != '') {
			var text = e.target.value
			e.target.value = ''
			send({cmd: 'chat', text: text})
			lastSent = text
			updateInputSize()
		}
		e.preventDefault()
	}
	else if (e.keyCode == 38 /* UP */) {
		// Restore previous sent message
		if (e.target.value == '') {
			e.target.value = lastSent
			e.target.selectionStart = e.target.value.length
			updateInputSize()
			e.preventDefault()
		}
	}
}

function updateInputSize() {
	var atBottom = isAtBottom()

	var input = $('#chatinput')
	input.style.height = 0
	input.style.height = input.scrollHeight + 'px'
	document.body.style.marginBottom = $('#footer').offsetHeight + 'px'

	if (atBottom) {
		window.scrollTo(0, document.body.scrollHeight)
	}
}

$('#chatinput').oninput = function() {
	updateInputSize()
}

updateInputSize()
$('#chatinput').focus()

/* sidebar */

$('#sidebar').onmouseenter = function() {
	$('#sidebar-content').classList.remove('hidden')
}

$('#sidebar').onmouseleave = function() {
	if (!$('#pin-sidebar').checked) {
		$('#sidebar-content').classList.add('hidden')
	}
}

$('#clear-history').onclick = function() {
	// Delete children elements
	var messages = $('#messages')
	while (messages.firstChild) {
		messages.removeChild(messages.firstChild)
	}
}

function userAdd(nick) {
	var user = document.createElement('li')
	user.textContent = nick
	user.onclick = userInvite
	$('#users').appendChild(user)
}

function userRemove(nick) {
	var users = $('#users')
	var children = users.children
	for (var i = 0; i < children.length; i++) {
		var user = children[i]
		if (user.textContent == nick) {
			users.removeChild(user)
		}
	}
}

function usersClear() {
	var users = $('#users')
	while (users.firstChild) {
		users.removeChild(users.firstChild)
	}
}

function userInvite(e) {
	var nick = e.target.textContent
	send({cmd: 'invite', nick: nick})
}

/* color scheme switcher */

var schemes = [
	'android',
	'atelier-dune',
	'atelier-forest',
	'atelier-heath',
	'atelier-lakeside',
	'atelier-seaside',
	'bright',
	'chalk',
	'default',
	'eighties',
	'greenscreen',
	'mocha',
	'monokai',
	'nese',
	'ocean',
	'pop',
	'railscasts',
	'solarized',
	'tomorrow',
]

var currentScheme = 'atelier-dune'

function setScheme(scheme) {
	currentScheme = scheme
	$('#scheme-link').href = "/schemes/" + scheme + ".css"
	if (localStorage) {
		localStorage['scheme'] = scheme
	}
}

// Add scheme options to dropdown selector
schemes.forEach(function(scheme) {
	var option = document.createElement('option')
	option.textContent = scheme
	option.value = scheme
	$('#scheme-selector').appendChild(option)
})

$('#scheme-selector').onchange = function(e) {
	setScheme(e.target.value)
}

// Load and select scheme from local storage if available
if (localStorage) {
	var scheme = localStorage['scheme']
	if (scheme) {
		setScheme(scheme)
	}
}

$('#scheme-selector').value = currentScheme
<|endoftext|>


<commit_before>/**
 * Created by andreas on 04.05.14.
 */
avnav.provide('avnav.nav.AisData');

/**
 * the handler for the ais data
 * query the server...
 * @param {avnav.util.PropertyHandler} propertyHandler
 * @param {avnav.nav.NavObject} navobject
 * @constructor
 */
avnav.nav.AisData=function(propertyHandler,navobject){
    /** @private */
    this.propertyHandler=propertyHandler;
    /** @private */
    this.navobject=navobject;
    /** @private
     * @type {Array.<avnav.nav.navdata.Ais>}
     * */
    this.currentAis=[];

    /**
     * the last successfull query
     * @type {number}
     */
    this.lastAisQuery=new Date().getTime();
    /**
     * @private
     * @type {null}
     */
    this.timer=null;
    /**
     * @private
     * @type {number}
     */
    this.aisErrors=0;
    /**
     * the mmsi of the tracked target
     * @type {number}
     */
    this.trackedAIStarget=null;

    /**
     * @private
     * @type {properties.NM}
     */
    this.NM=this.propertyHandler.getProperties().NM;

    /**
     * this is a translation between the display names and the aisparam values
     * @type {{aisDst: string, aisSog: string, aisCog: string, aisCpa: string, aisTcpa: string, aisMmsi: string, aisName: string, aisDestination: string, aisFront: string, aisShiptype: string}}
     */
    this.formattedDataDescription={
        aisDst:'distance',
        aisSog:'speed',
        aisCog:'course',
        aisCpa:'cpa',
        aisTcpa:'tcpa',
        aisMmsi:'mmsi',
        aisName:'shipname',
        aisDestination:'destination',
        aisFront:'passFront',
        aisShiptype:'shiptype'
    };

    this.formattedData={};
    for (var i in this.formattedDataDescription){
        this.formattedData[i]="";
        this.navobject.registerValueProvider(i,this,this.getFormattedAisValue)
    }

    /**
     * the nearest target - being returned when values are queried
     *
     * @type {avnav.nav.navdata.Ais}
     */
    this.nearestAisTarget={};
    var self=this;

    /**
     * the formatter for AIS data
     * @private
     * @type {{distance: {headline: string, format: format}, speed: {headline: string, format: format}, course: {headline: string, format: format}, cpa: {headline: string, format: format}, tcpa: {headline: string, format: format}, passFront: {headline: string, format: format}, shipname: {headline: string, format: format}, callsign: {headline: string, format: format}, mmsi: {headline: string, format: format}, shiptype: {headline: string, format: format}, position: {headline: string, format: format}, destination: {headline: string, format: format}}}
     */
    this.aisparam={
        distance:{
            headline: 'dist(nm)',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.distance||0),3,2);}
        },
        speed: {
            headline: 'speed(kn)',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.speed||0),3,1);}
        },
        course:	{
            headline: 'course',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.course||0),3,0);}
        },
        cpa:{
            headline: 'cpa',
            format: function(v){
                var tval=parseFloat(v.tcpa||0);
                //no cpa if tcpa < 0
                if (tval < 0) return "-----";
                return self.formatter.formatDecimal(parseFloat(v.cpa||0),3,2);}
        },
        tcpa:{
            headline: 'tcpa',
            format: function(v){
                var tval=parseFloat(v.tcpa||0);
                if (tval < 0) return "--:--:--";
                var h=Math.floor(tval/3600);
                var m=Math.floor((tval-h*3600)/60);
                var s=tval-3600*h-60*m;
                return self.formatter.formatDecimal(h,2,0)+':'+self.formatter.formatDecimal(m,2,0)+':'+self.formatter.formatDecimal(s,2,0);
            }
        },
        passFront:{
            headline: 'pass',
            format: function(v){
                if (! v.cpa) return "-";
                if (v.passFront) return "Front";
                return "Back";
            }
        },
        shipname:{
            headline: 'name',
            format: function(v){ return v.shipname;}
        },
        callsign:{
            headline: 'call',
            format: function(v){ return v.callsign;}
        },
        mmsi: {
            headline: 'mmsi',
            format: function(v){ return v.mmsi;}
        },
        shiptype:{
            headline: 'type',
            format: function(v){
                var t=0;
                try{
                    t=parseInt(v.shiptype||0);
                }catch (e){}
                if (t>=20 && t<=29) return "WIG";
                if (t==30) return "Fishing";
                if (t==31 || t==32) return "Towing";
                if (t==33) return "Dredging";
                if (t==34) return "Diving";
                if (t==35) return "Military";
                if (t ==36)return "Sail";
                if (t==37) return "Pleasure";
                if (t>=40 && t<=49) return "HighSp";
                if (t==50) return "Pilot";
                if (t==51) return "SAR";
                if (t==52) return "Tug";
                if (t==53) return "PortT";
                if (t==54) return "AntiPol";
                if (t==55) return "Law";
                if (t==58) return "Medical";
                if (t>=60 && t<=69) return "Passenger";
                if (t>=70 && t<=79) return "Cargo";
                if (t>=80 && t<=89) return "Tanker";
                if (t>=91 && t<=94) return "Hazard";
                return "Other";
            }
        },
        position:{
            headline: 'position',
            format: function(v){return self.formatter.formatLonLats({lon:v.lon,lat:v.lat});}
        },
        destination: {
            headline: 'destination',
            format: function(v){ var d=v.destination; if (d) return d; return "unknown";}
        }

    };

    /**
     * @private
     * @type {avnav.util.Formatter}
     */
    this.formatter=new avnav.util.Formatter();
    this.startQuery();
};

/**
 * compute all the cpa data...
 * @private
 */
avnav.nav.AisData.prototype.handleAisData=function() {
    /** @type {avnav.nav.navdata.GpsInfo}*/
    var boatPos = this.navobject.getRawData(avnav.nav.NavEventType.GPS);
    var properties=this.propertyHandler.getProperties();
    var trackedTarget=null; //ref to tracked target
    var aisWarningAis = null;
    if (boatPos.valid) {
        var foundTrackedTarget = false;
        for (var aisidx in this.currentAis) {
            var ais = this.currentAis[aisidx];
            ais.warning=false;
            ais.tracking=false;
            ais.nearest=false;
            var dst = avnav.nav.NavCompute.computeDistance(boatPos, new avnav.nav.navdata.Point(parseFloat(ais.lon||0), parseFloat(ais.lat||0)));
            var cpadata = avnav.nav.NavCompute.computeCpa({
                    lon: boatPos.lon,
                    lat: boatPos.lat,
                    course: boatPos.course || 0,
                    speed: boatPos.speed || 0
                },
                {
                    lon: parseFloat(ais.lon || 0),
                    lat: parseFloat(ais.lat || 0),
                    course: parseFloat(ais.course || 0),
                    speed: parseFloat(ais.speed || 0)
                },
                properties
            );
            ais.distance = dst.dtsnm;
            ais.headingTo = dst.heading;
            if (cpadata.tcpa >=0) {
                ais.cpa = cpadata.cpanm;
                ais.tcpa = cpadata.tcpa;
            }
            else {
                ais.cpa = 0;
                ais.tcpa = 0;
            }
            ais.passFront = cpadata.front;
            if (!ais.shipname) ais.shipname = "unknown";
            if (!ais.callsign) ais.callsign = "????";
            var warningCpa=properties.aisWarningCpa/this.NM;
            if (ais.cpa && ais.cpa < warningCpa && ais.tcpa && ais.tcpa < properties.aisWarningTpa) {
                if (aisWarningAis) {
                    if (aisWarningAis.tcpa > ais.tcpa) aisWarningAis = ais;
                }
                else aisWarningAis = ais;
            }
            if (ais.mmsi == this.trackedAIStarget) {
                foundTrackedTarget = true;
                ais.tracking=true;
                trackedTarget=ais;
            }
        }
        if (!foundTrackedTarget) this.trackedAIStarget = null;
    }
    this.currentAis.sort(this.aisSort);
    if (this.currentAis.length){
        this.currentAis[0].nearest=true;
    }
    if (aisWarningAis) {
        aisWarningAis.warning=true;
    }
    //handling of the nearest target
    //warning active - this one
    //no tracked target set - nearest
    //tracked set - this one
    if (this.currentAis.length) {
        if (aisWarningAis) this.nearestAisTarget = aisWarningAis;
        else {
            if (trackedTarget) this.nearestAisTarget = trackedTarget;
            else this.nearestAisTarget = this.currentAis[0];
        }
    }
    else {
        this.nearestAisTarget={};
    }
    this.navobject.aisEvent();
};
/**
 * sorter for the AIS data - sort by distance
 * @param a
 * @param b
 * @returns {number}
 */
avnav.nav.AisData.prototype.aisSort=function(a,b) {
    try {
        if (a.distance == b.distance) return 0;
        if (a.distance < b.distance) return -1;
        return 1;
    } catch (err) {
        return 0;
    }
};
/**
 * get the formatter for AIS data
 * @returns {{distance: {headline: string, format: format}, speed: {headline: string, format: format}, course: {headline: string, format: format}, cpa: {headline: string, format: format}, tcpa: {headline: string, format: format}, passFront: {headline: string, format: format}, shipname: {headline: string, format: format}, callsign: {headline: string, format: format}, mmsi: {headline: string, format: format}, shiptype: {headline: string, format: format}, position: {headline: string, format: format}, destination: {headline: string, format: format}}}
 */
avnav.nav.AisData.prototype.getAisFormatter=function(){
    return this.aisparam;
};
/**
 *
 * @param dname
 * @returns {string}
 */
avnav.nav.AisData.prototype.getFormattedAisValue=function(dname){
    var key=this.formattedDataDescription[dname];
    if (! key) return "";
    if (this.nearestAisTarget[key] === undefined) return "";
    return this.aisparam[key].format(this.nearestAisTarget);
};

/**
 * @private
 */
avnav.nav.AisData.prototype.startQuery=function() {
    var url = this.propertyHandler.getProperties().navUrl+"?request=ais";
    var timeout = this.propertyHandler.getProperties().aisQueryTimeout; //in ms
    var center=this.navobject.getAisCenter();
    var self=this;
    if (! center){
        window.clearTimeout(this.timer);
        this.timer=window.setTimeout(function(){
            self.startQuery();
        },timeout);
        return;
    }
    url+="&lon="+this.formatter.formatDecimal(center.lon,3,5);
    url+="&lat="+this.formatter.formatDecimal(center.lat,3,5);
    url+="&distance="+this.formatter.formatDecimal(this.propertyHandler.getProperties().aisDistance||10,4,1);
    $.ajax({
        url: url,
        dataType: 'json',
        cache:	false,
        success: function(data,status){
            self.aisErrors=0;
            self.lastAisQuery=new Date().getTime();
            var aisList=[];
            if (data['class'] && data['class'] == "error") aisList=[];
            else aisList=data;
            self.currentAis=aisList;
            try {
                self.handleAisData();
            }catch (e){
                var x=e;
            }
            window.clearTimeout(self.timer);
            self.timer=window.setTimeout(function(){self.startQuery();},timeout);
        },
        error: function(status,data,error){
            log("query ais error");
            self.aisErrors+=1;
            if (self.aisErrors >= self.propertyHandler.getProperties().maxAisErrors){
                self.currentAis=[];
                self.handleAisData();
            }
            window.clearTimeout(self.timer);
            self.timer=window.setTimeout(function(){self.startQuery();},timeout);
        },
        timeout: timeout
    });
};

/**
 * return the current aisData
 * @returns {Array.<avnav.nav.navdata.Ais>}
 */
avnav.nav.AisData.prototype.getAisData=function(){
    return this.currentAis;
};

/**
 * get an ais target by mmsi, return undefined if not found
 * @param mmsi
 * @returns {*}
 */
avnav.nav.AisData.prototype.getAisByMmsi=function(mmsi){
    for (var i in this.currentAis){
        if (this.currentAis[i].mmsi == mmsi) return this.currentAis[i];
    }
    return undefined;
};
/**
 * get the position of an AIS target
 * @param mmsi
 * @returns {*}
 */
avnav.nav.AisData.prototype.getAisPositionByMmsi=function(mmsi){
    var ais=this.getAisByMmsi(mmsi);
    if (! ais) return undefined;
    return new avnav.nav.navdata.Point(parseFloat(ais.lon||0),parseFloat(ais.lat||0));
};

/**
 * get the raw data for the currently tracked target
 * @returns {avnav.nav.navdata.Ais}
 */
avnav.nav.AisData.prototype.getNearestAisTarget=function(){
    return this.nearestAisTarget;
};

/**
 * return the mmsi of the tracked target or 0
 * @returns {number}
 */
avnav.nav.AisData.prototype.getTrackedTarget=function(){
    return this.trackedAIStarget;
};
/**
 * set the target to be tracked, 0 to use nearest
 * @param {number} mmsi
 */
avnav.nav.AisData.prototype.setTrackedTarget=function(mmsi){
    if (this.trackedAIStarget == mmsi) return;
    this.trackedAIStarget=mmsi;
    this.handleAisData();
};
<commit_msg>avoid uncaught exception when no ais data is available<commit_after>/**
 * Created by andreas on 04.05.14.
 */
avnav.provide('avnav.nav.AisData');

/**
 * the handler for the ais data
 * query the server...
 * @param {avnav.util.PropertyHandler} propertyHandler
 * @param {avnav.nav.NavObject} navobject
 * @constructor
 */
avnav.nav.AisData=function(propertyHandler,navobject){
    /** @private */
    this.propertyHandler=propertyHandler;
    /** @private */
    this.navobject=navobject;
    /** @private
     * @type {Array.<avnav.nav.navdata.Ais>}
     * */
    this.currentAis=[];

    /**
     * the last successfull query
     * @type {number}
     */
    this.lastAisQuery=new Date().getTime();
    /**
     * @private
     * @type {null}
     */
    this.timer=null;
    /**
     * @private
     * @type {number}
     */
    this.aisErrors=0;
    /**
     * the mmsi of the tracked target
     * @type {number}
     */
    this.trackedAIStarget=null;

    /**
     * @private
     * @type {properties.NM}
     */
    this.NM=this.propertyHandler.getProperties().NM;

    /**
     * this is a translation between the display names and the aisparam values
     * @type {{aisDst: string, aisSog: string, aisCog: string, aisCpa: string, aisTcpa: string, aisMmsi: string, aisName: string, aisDestination: string, aisFront: string, aisShiptype: string}}
     */
    this.formattedDataDescription={
        aisDst:'distance',
        aisSog:'speed',
        aisCog:'course',
        aisCpa:'cpa',
        aisTcpa:'tcpa',
        aisMmsi:'mmsi',
        aisName:'shipname',
        aisDestination:'destination',
        aisFront:'passFront',
        aisShiptype:'shiptype'
    };

    this.formattedData={};
    for (var i in this.formattedDataDescription){
        this.formattedData[i]="";
        this.navobject.registerValueProvider(i,this,this.getFormattedAisValue)
    }

    /**
     * the nearest target - being returned when values are queried
     *
     * @type {avnav.nav.navdata.Ais}
     */
    this.nearestAisTarget={};
    var self=this;

    /**
     * the formatter for AIS data
     * @private
     * @type {{distance: {headline: string, format: format}, speed: {headline: string, format: format}, course: {headline: string, format: format}, cpa: {headline: string, format: format}, tcpa: {headline: string, format: format}, passFront: {headline: string, format: format}, shipname: {headline: string, format: format}, callsign: {headline: string, format: format}, mmsi: {headline: string, format: format}, shiptype: {headline: string, format: format}, position: {headline: string, format: format}, destination: {headline: string, format: format}}}
     */
    this.aisparam={
        distance:{
            headline: 'dist(nm)',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.distance||0),3,2);}
        },
        speed: {
            headline: 'speed(kn)',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.speed||0),3,1);}
        },
        course:	{
            headline: 'course',
            format: function(v){ return self.formatter.formatDecimal(parseFloat(v.course||0),3,0);}
        },
        cpa:{
            headline: 'cpa',
            format: function(v){
                var tval=parseFloat(v.tcpa||0);
                //no cpa if tcpa < 0
                if (tval < 0) return "-----";
                return self.formatter.formatDecimal(parseFloat(v.cpa||0),3,2);}
        },
        tcpa:{
            headline: 'tcpa',
            format: function(v){
                var tval=parseFloat(v.tcpa||0);
                if (tval < 0) return "--:--:--";
                var h=Math.floor(tval/3600);
                var m=Math.floor((tval-h*3600)/60);
                var s=tval-3600*h-60*m;
                return self.formatter.formatDecimal(h,2,0)+':'+self.formatter.formatDecimal(m,2,0)+':'+self.formatter.formatDecimal(s,2,0);
            }
        },
        passFront:{
            headline: 'pass',
            format: function(v){
                if (! v.cpa) return "-";
                if (v.passFront) return "Front";
                return "Back";
            }
        },
        shipname:{
            headline: 'name',
            format: function(v){ return v.shipname;}
        },
        callsign:{
            headline: 'call',
            format: function(v){ return v.callsign;}
        },
        mmsi: {
            headline: 'mmsi',
            format: function(v){ return v.mmsi;}
        },
        shiptype:{
            headline: 'type',
            format: function(v){
                var t=0;
                try{
                    t=parseInt(v.shiptype||0);
                }catch (e){}
                if (t>=20 && t<=29) return "WIG";
                if (t==30) return "Fishing";
                if (t==31 || t==32) return "Towing";
                if (t==33) return "Dredging";
                if (t==34) return "Diving";
                if (t==35) return "Military";
                if (t ==36)return "Sail";
                if (t==37) return "Pleasure";
                if (t>=40 && t<=49) return "HighSp";
                if (t==50) return "Pilot";
                if (t==51) return "SAR";
                if (t==52) return "Tug";
                if (t==53) return "PortT";
                if (t==54) return "AntiPol";
                if (t==55) return "Law";
                if (t==58) return "Medical";
                if (t>=60 && t<=69) return "Passenger";
                if (t>=70 && t<=79) return "Cargo";
                if (t>=80 && t<=89) return "Tanker";
                if (t>=91 && t<=94) return "Hazard";
                return "Other";
            }
        },
        position:{
            headline: 'position',
            format: function(v){return self.formatter.formatLonLats({lon:v.lon,lat:v.lat});}
        },
        destination: {
            headline: 'destination',
            format: function(v){ var d=v.destination; if (d) return d; return "unknown";}
        }

    };

    /**
     * @private
     * @type {avnav.util.Formatter}
     */
    this.formatter=new avnav.util.Formatter();
    this.startQuery();
};

/**
 * compute all the cpa data...
 * @private
 */
avnav.nav.AisData.prototype.handleAisData=function() {
    /** @type {avnav.nav.navdata.GpsInfo}*/
    var boatPos = this.navobject.getRawData(avnav.nav.NavEventType.GPS);
    var properties=this.propertyHandler.getProperties();
    var trackedTarget=null; //ref to tracked target
    var aisWarningAis = null;
    if (boatPos.valid) {
        var foundTrackedTarget = false;
        for (var aisidx in this.currentAis) {
            var ais = this.currentAis[aisidx];
            ais.warning=false;
            ais.tracking=false;
            ais.nearest=false;
            var dst = avnav.nav.NavCompute.computeDistance(boatPos, new avnav.nav.navdata.Point(parseFloat(ais.lon||0), parseFloat(ais.lat||0)));
            var cpadata = avnav.nav.NavCompute.computeCpa({
                    lon: boatPos.lon,
                    lat: boatPos.lat,
                    course: boatPos.course || 0,
                    speed: boatPos.speed || 0
                },
                {
                    lon: parseFloat(ais.lon || 0),
                    lat: parseFloat(ais.lat || 0),
                    course: parseFloat(ais.course || 0),
                    speed: parseFloat(ais.speed || 0)
                },
                properties
            );
            ais.distance = dst.dtsnm;
            ais.headingTo = dst.heading;
            if (cpadata.tcpa >=0) {
                ais.cpa = cpadata.cpanm;
                ais.tcpa = cpadata.tcpa;
            }
            else {
                ais.cpa = 0;
                ais.tcpa = 0;
            }
            ais.passFront = cpadata.front;
            if (!ais.shipname) ais.shipname = "unknown";
            if (!ais.callsign) ais.callsign = "????";
            var warningCpa=properties.aisWarningCpa/this.NM;
            if (ais.cpa && ais.cpa < warningCpa && ais.tcpa && ais.tcpa < properties.aisWarningTpa) {
                if (aisWarningAis) {
                    if (aisWarningAis.tcpa > ais.tcpa) aisWarningAis = ais;
                }
                else aisWarningAis = ais;
            }
            if (ais.mmsi == this.trackedAIStarget) {
                foundTrackedTarget = true;
                ais.tracking=true;
                trackedTarget=ais;
            }
        }
        if (!foundTrackedTarget) this.trackedAIStarget = null;
    }
    if (this.currentAis) {
        this.currentAis.sort(this.aisSort);
        if (this.currentAis.length) {
            this.currentAis[0].nearest = true;
        }
    }
    if (aisWarningAis) {
        aisWarningAis.warning=true;
    }
    //handling of the nearest target
    //warning active - this one
    //no tracked target set - nearest
    //tracked set - this one
    if (this.currentAis.length) {
        if (aisWarningAis) this.nearestAisTarget = aisWarningAis;
        else {
            if (trackedTarget) this.nearestAisTarget = trackedTarget;
            else this.nearestAisTarget = this.currentAis[0];
        }
    }
    else {
        this.nearestAisTarget={};
    }
    this.navobject.aisEvent();
};
/**
 * sorter for the AIS data - sort by distance
 * @param a
 * @param b
 * @returns {number}
 */
avnav.nav.AisData.prototype.aisSort=function(a,b) {
    try {
        if (a.distance == b.distance) return 0;
        if (a.distance < b.distance) return -1;
        return 1;
    } catch (err) {
        return 0;
    }
};
/**
 * get the formatter for AIS data
 * @returns {{distance: {headline: string, format: format}, speed: {headline: string, format: format}, course: {headline: string, format: format}, cpa: {headline: string, format: format}, tcpa: {headline: string, format: format}, passFront: {headline: string, format: format}, shipname: {headline: string, format: format}, callsign: {headline: string, format: format}, mmsi: {headline: string, format: format}, shiptype: {headline: string, format: format}, position: {headline: string, format: format}, destination: {headline: string, format: format}}}
 */
avnav.nav.AisData.prototype.getAisFormatter=function(){
    return this.aisparam;
};
/**
 *
 * @param dname
 * @returns {string}
 */
avnav.nav.AisData.prototype.getFormattedAisValue=function(dname){
    var key=this.formattedDataDescription[dname];
    if (! key) return "";
    if (this.nearestAisTarget[key] === undefined) return "";
    return this.aisparam[key].format(this.nearestAisTarget);
};

/**
 * @private
 */
avnav.nav.AisData.prototype.startQuery=function() {
    var url = this.propertyHandler.getProperties().navUrl+"?request=ais";
    var timeout = this.propertyHandler.getProperties().aisQueryTimeout; //in ms
    var center=this.navobject.getAisCenter();
    var self=this;
    if (! center){
        window.clearTimeout(this.timer);
        this.timer=window.setTimeout(function(){
            self.startQuery();
        },timeout);
        return;
    }
    url+="&lon="+this.formatter.formatDecimal(center.lon,3,5);
    url+="&lat="+this.formatter.formatDecimal(center.lat,3,5);
    url+="&distance="+this.formatter.formatDecimal(this.propertyHandler.getProperties().aisDistance||10,4,1);
    $.ajax({
        url: url,
        dataType: 'json',
        cache:	false,
        success: function(data,status){
            self.aisErrors=0;
            self.lastAisQuery=new Date().getTime();
            var aisList=[];
            if (data['class'] && data['class'] == "error") aisList=[];
            else aisList=data;
            self.currentAis=aisList;
            try {
                self.handleAisData();
            }catch (e){
                var x=e;
            }
            window.clearTimeout(self.timer);
            self.timer=window.setTimeout(function(){self.startQuery();},timeout);
        },
        error: function(status,data,error){
            log("query ais error");
            self.aisErrors+=1;
            if (self.aisErrors >= self.propertyHandler.getProperties().maxAisErrors){
                self.currentAis=[];
                self.handleAisData();
            }
            window.clearTimeout(self.timer);
            self.timer=window.setTimeout(function(){self.startQuery();},timeout);
        },
        timeout: timeout
    });
};

/**
 * return the current aisData
 * @returns {Array.<avnav.nav.navdata.Ais>}
 */
avnav.nav.AisData.prototype.getAisData=function(){
    return this.currentAis;
};

/**
 * get an ais target by mmsi, return undefined if not found
 * @param mmsi
 * @returns {*}
 */
avnav.nav.AisData.prototype.getAisByMmsi=function(mmsi){
    for (var i in this.currentAis){
        if (this.currentAis[i].mmsi == mmsi) return this.currentAis[i];
    }
    return undefined;
};
/**
 * get the position of an AIS target
 * @param mmsi
 * @returns {*}
 */
avnav.nav.AisData.prototype.getAisPositionByMmsi=function(mmsi){
    var ais=this.getAisByMmsi(mmsi);
    if (! ais) return undefined;
    return new avnav.nav.navdata.Point(parseFloat(ais.lon||0),parseFloat(ais.lat||0));
};

/**
 * get the raw data for the currently tracked target
 * @returns {avnav.nav.navdata.Ais}
 */
avnav.nav.AisData.prototype.getNearestAisTarget=function(){
    return this.nearestAisTarget;
};

/**
 * return the mmsi of the tracked target or 0
 * @returns {number}
 */
avnav.nav.AisData.prototype.getTrackedTarget=function(){
    return this.trackedAIStarget;
};
/**
 * set the target to be tracked, 0 to use nearest
 * @param {number} mmsi
 */
avnav.nav.AisData.prototype.setTrackedTarget=function(mmsi){
    if (this.trackedAIStarget == mmsi) return;
    this.trackedAIStarget=mmsi;
    this.handleAisData();
};
<|endoftext|>


<commit_before>import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';

import JSZip from 'jszip';
import { saveAs } from 'file-saver';

/* import IconButton from 'material-ui/IconButton';*/

import Table, {
  TableBody,
  TableCell,
  TableHead,
  TableRow,
} from 'material-ui/Table';
import Button from 'material-ui/Button';
import Grid from 'material-ui/Grid';
import { MdClear,
  MdEdit,
  MdClose,
  MdContentCopy,
  MdDelete,
  MdFileDownload } from 'react-icons/lib/md';
import { withStyles } from 'material-ui/styles';
import { LinearProgress } from 'material-ui/Progress';
import Paper from 'material-ui/Paper';
import Slide from 'material-ui/transitions/Slide';

import * as moment from 'moment/moment';

import axios from 'axios';
import { apiRoot } from 'utils/constants';
import { styles } from './styles';

const fireworksRoot = `${apiRoot}/apps/fireworks`;
const fireworksUrl = `${fireworksRoot}/schedule_workflows`;

const initialState = {
  loading: false,
};

class CalculationsView extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.state = initialState;
    this.clearCalculations = this.clearCalculations.bind(this);
    this.removeCalculation = this.removeCalculation.bind(this);
    this.editCalculation = this.editCalculation.bind(this);
    this.downloadCalculations = this.downloadCalculations.bind(this);
    this.queueCalculations = this.queueCalculations.bind(this);
  }
  clearCalculations() {
    this.props.clearCalculations();
  }
  removeCalculation(n) {
    this.props.removeCalculation(n);
    if (this.props.openCalculation === n) {
      this.props.setOpenCalculation(-1);
    } else if (this.props.openCalculation > n) {
      this.props.setOpenCalculation(this.props.openCalculation - 1);
    }
  }

  copyCalculation(n) {
    this.props.copyCalculation(n);
    if (this.props.openCalculation > n) {
      this.props.setOpenCalculation(this.props.openCalculation + 1);
    }
  }

  editCalculation(n) {
    this.props.editCalculation(n);
    this.props.stepperHandleReset();
  }

  downloadCalculations() {
    this.setState({
      loading: true,
    });

    const date = moment().format('YYYYMMDD_HHmmss');
    const zip = new JSZip();
    const dir = zip.folder(`calc_${date}`);
    let adsDir;
    let bulkDir;
    let bulkStr;
    let cdir;
    let format;
    let gasDir;
    let layers;
    let miller;
    let slabDir;
    let termination;
    let vacuum;

    dir.file('calculations.json', JSON.stringify(this.props.calculations, null, 4));

    this.props.calculations.map((calculation) => {
      cdir = dir
               .folder(calculation.bulkParams.format)
               .folder('xcFunctional');

      format = calculation.bulkParams.format;
      gasDir = cdir.folder('gas');
      _.forOwn(_.get(calculation, 'adsorbateParams.molecules', {}),
        (value, key) => {
          gasDir.file(`${key}.${format}`, value);
        }
      );

      bulkStr = `${calculation.bulkParams.elements.join('')
        }:${calculation.bulkParams.wyckoff.name}`;

      bulkDir = cdir.folder(bulkStr);
      format = calculation.bulkParams.format;
      bulkDir.file(`bulk.${format}`, calculation.bulkParams.input);
      miller = `${calculation.slabParams.millerX}${calculation.slabParams.millerY}${calculation.slabParams.millerZ}`;
      vacuum = calculation.slabParams.vacuum;
      layers = calculation.slabParams.layers;
      termination = calculation.slabParams.termination;
      slabDir = bulkDir.folder(`${miller}_layers:${layers}_termination:${termination}_vacuum:${vacuum}`);
      slabDir.file(`empty_slab.${format}`, calculation.slabParams.input);
      return calculation.adsorbateParams.inputs.map((cif, i) => {
        adsDir = slabDir.folder(calculation.adsorbateParams.equations[i]);
        return adsDir.file(`${calculation.adsorbateParams.adsorbate}.${format}`, cif);
      });
    });

    zip.generateAsync({ type: 'blob' }).then((zipFile) => {
      saveAs(zipFile, `calculations_${date}.zip`);
    });
    this.setState({ loading: false });
  }

  queueCalculations() {
    const params = { params: {
      calculations: JSON.stringify(this.props.calculations),
    } };
    axios.get(fireworksUrl, params).then(() => {
    });
  }

  render() {
    return (

        {this.props.calculations.length === 0 ? null :
        <Slide
          in
          mountOnEnter
          unmountOnExit
          direction="up"
        >
          <Paper className={this.props.classes.paper} height={8}>

Stored Calculations

              <TableHead>
                <TableRow>
                  <TableCell padding="none">Prototype</TableCell>
                  <TableCell padding="none">Composition</TableCell>
                  <TableCell padding="none">Miller</TableCell>
                  <TableCell padding="none">Layers</TableCell>
                  <TableCell padding="none">Termination</TableCell>
                  <TableCell padding="none">Vacuum</TableCell>
                  <TableCell padding="none">Adsorbates</TableCell>
                  <TableCell padding="none">Input Format</TableCell>
                  <TableCell padding="none"></TableCell>

                </TableRow>
              </TableHead>
              <TableBody>
                {this.props.calculations.map((calculation, i) => (
                  <TableRow
                    key={`calculation_${i}`}
                    className={(this.props.openCalculation === i)
                          ? this.props.classes.highlightedRow
                          : this.props.classes.row}
                  >
                    <TableCell padding="none">{_.get(calculation, 'bulkParams.wyckoff.name', '???')}</TableCell>
                    <TableCell padding="none">{`
            [${calculation.bulkParams.elements.join(', ')}]
              `}</TableCell>
                    <TableCell padding="none">{
              `(
              ${calculation.slabParams.millerX},
              ${calculation.slabParams.millerY},
              ${calculation.slabParams.millerZ}
            )`
            }</TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.layers}`} </TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.termination}`} </TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.vacuum}`} </TableCell>
                    <TableCell padding="none">{`${calculation.adsorbateParams.adsorbate}@${calculation.adsorbateParams.siteType} [${calculation.adsorbateParams.cifs.length} sites]`} </TableCell>
                    <TableCell padding="none">{`
            ${calculation.bulkParams.format}
            `}</TableCell>
                    <TableCell padding="none">
                      <Button
                        fab
                        mini
                        className={this.props.classes.actionIcon}
                      >
                        <MdEdit
                          onClick={() => { this.editCalculation(i); }}
                        />
                      </Button>
                      <Button
                        className={this.props.classes.actionIcon}
                        fab
                        mini
                      >
                        <MdContentCopy
                          onClick={() => { this.copyCalculation(i); }}
                        />
                      </Button>
                      <Button
                        fab
                        mini
                        className={this.props.classes.actionIcon}
                      >
                        <MdDelete
                          onClick={() => { this.removeCalculation(i); }}
                        />
                      </Button>
                      {(this.props.openCalculation === i) ?
                        <Button
                          fab mini
                          className={this.props.classes.actionIcon}
                        >
                          <MdClose
                            onClick={() => { this.props.setOpenCalculation(-1); }}
                          />
                        </Button>
                        : null}
                    </TableCell>
                  </TableRow>
                    ))}
              </TableBody>

            <Grid container justify="flex-end" direction="row">
              <Grid item>
                <Button raised onClick={this.clearCalculations} color="inherit" className={this.props.classes.button}><MdClear /> {'\u00A0'}Clear</Button>
              </Grid>
              <Grid item>
                <Button
                  raised
                  onClick={this.downloadCalculations}
                  className={this.props.classes.button}
                  color="primary"
                ><MdFileDownload />{'\u00A0'} Download</Button>
              </Grid>
              {/*
              <Grid item>
                <Button
                  raised
                  onClick={() => {this.queueCalculations()}}
                  color="primary"
                  className={this.props.classes.button}
                ><MdCloud />{'\u00A0'} Queue</Button>
              </Grid>
              */}
            </Grid>

          </Paper>
        </Slide>
        }
        {this.state.loading ? <LinearProgress className={this.props.classes.progress} /> : null }

    );
  }
}

CalculationsView.propTypes = {
  calculations: PropTypes.array,
  clearCalculations: PropTypes.func,
  removeCalculation: PropTypes.func,
  copyCalculation: PropTypes.func,
  openCalculation: PropTypes.number,
  setOpenCalculation: PropTypes.func,
  editCalculation: PropTypes.func,
  stepperHandleReset: PropTypes.func,
  classes: PropTypes.object,
};

module.exports = {
  CalculationsView: withStyles(styles, { withTheme: true })(CalculationsView),
};
<commit_msg>Changed material folder name scheme from composition:prototype to composition_prototype to work better with existing cathub folder2db command<commit_after>import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';

import JSZip from 'jszip';
import { saveAs } from 'file-saver';

/* import IconButton from 'material-ui/IconButton';*/

import Table, {
  TableBody,
  TableCell,
  TableHead,
  TableRow,
} from 'material-ui/Table';
import Button from 'material-ui/Button';
import Grid from 'material-ui/Grid';
import { MdClear,
  MdEdit,
  MdClose,
  MdContentCopy,
  MdDelete,
  MdFileDownload } from 'react-icons/lib/md';
import { withStyles } from 'material-ui/styles';
import { LinearProgress } from 'material-ui/Progress';
import Paper from 'material-ui/Paper';
import Slide from 'material-ui/transitions/Slide';

import * as moment from 'moment/moment';

import axios from 'axios';
import { apiRoot } from 'utils/constants';
import { styles } from './styles';

const fireworksRoot = `${apiRoot}/apps/fireworks`;
const fireworksUrl = `${fireworksRoot}/schedule_workflows`;

const initialState = {
  loading: false,
};

class CalculationsView extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.state = initialState;
    this.clearCalculations = this.clearCalculations.bind(this);
    this.removeCalculation = this.removeCalculation.bind(this);
    this.editCalculation = this.editCalculation.bind(this);
    this.downloadCalculations = this.downloadCalculations.bind(this);
    this.queueCalculations = this.queueCalculations.bind(this);
  }
  clearCalculations() {
    this.props.clearCalculations();
  }
  removeCalculation(n) {
    this.props.removeCalculation(n);
    if (this.props.openCalculation === n) {
      this.props.setOpenCalculation(-1);
    } else if (this.props.openCalculation > n) {
      this.props.setOpenCalculation(this.props.openCalculation - 1);
    }
  }

  copyCalculation(n) {
    this.props.copyCalculation(n);
    if (this.props.openCalculation > n) {
      this.props.setOpenCalculation(this.props.openCalculation + 1);
    }
  }

  editCalculation(n) {
    this.props.editCalculation(n);
    this.props.stepperHandleReset();
  }

  downloadCalculations() {
    this.setState({
      loading: true,
    });

    const date = moment().format('YYYYMMDD_HHmmss');
    const zip = new JSZip();
    const dir = zip.folder(`calc_${date}`);
    let adsDir;
    let bulkDir;
    let bulkStr;
    let cdir;
    let format;
    let gasDir;
    let layers;
    let miller;
    let slabDir;
    let termination;
    let vacuum;

    dir.file('calculations.json', JSON.stringify(this.props.calculations, null, 4));

    this.props.calculations.map((calculation) => {
      cdir = dir
               .folder(calculation.bulkParams.format)
               .folder('xcFunctional');

      format = calculation.bulkParams.format;
      gasDir = cdir.folder('gas');
      _.forOwn(_.get(calculation, 'adsorbateParams.molecules', {}),
        (value, key) => {
          gasDir.file(`${key}.${format}`, value);
        }
      );

      bulkStr = `${calculation.bulkParams.elements.join('')
        }_${calculation.bulkParams.wyckoff.name}`;

      bulkDir = cdir.folder(bulkStr);
      format = calculation.bulkParams.format;
      bulkDir.file(`bulk.${format}`, calculation.bulkParams.input);
      miller = `${calculation.slabParams.millerX}${calculation.slabParams.millerY}${calculation.slabParams.millerZ}`;
      vacuum = calculation.slabParams.vacuum;
      layers = calculation.slabParams.layers;
      termination = calculation.slabParams.termination;
      slabDir = bulkDir.folder(`${miller}_layers:${layers}_termination:${termination}_vacuum:${vacuum}`);
      slabDir.file(`empty_slab.${format}`, calculation.slabParams.input);
      return calculation.adsorbateParams.inputs.map((cif, i) => {
        adsDir = slabDir.folder(calculation.adsorbateParams.equations[i]);
        return adsDir.file(`${calculation.adsorbateParams.adsorbate}.${format}`, cif);
      });
    });

    zip.generateAsync({ type: 'blob' }).then((zipFile) => {
      saveAs(zipFile, `calculations_${date}.zip`);
    });
    this.setState({ loading: false });
  }

  queueCalculations() {
    const params = { params: {
      calculations: JSON.stringify(this.props.calculations),
    } };
    axios.get(fireworksUrl, params).then(() => {
    });
  }

  render() {
    return (

        {this.props.calculations.length === 0 ? null :
        <Slide
          in
          mountOnEnter
          unmountOnExit
          direction="up"
        >
          <Paper className={this.props.classes.paper} height={8}>

Stored Calculations

              <TableHead>
                <TableRow>
                  <TableCell padding="none">Prototype</TableCell>
                  <TableCell padding="none">Composition</TableCell>
                  <TableCell padding="none">Miller</TableCell>
                  <TableCell padding="none">Layers</TableCell>
                  <TableCell padding="none">Termination</TableCell>
                  <TableCell padding="none">Vacuum</TableCell>
                  <TableCell padding="none">Adsorbates</TableCell>
                  <TableCell padding="none">Input Format</TableCell>
                  <TableCell padding="none"></TableCell>

                </TableRow>
              </TableHead>
              <TableBody>
                {this.props.calculations.map((calculation, i) => (
                  <TableRow
                    key={`calculation_${i}`}
                    className={(this.props.openCalculation === i)
                          ? this.props.classes.highlightedRow
                          : this.props.classes.row}
                  >
                    <TableCell padding="none">{_.get(calculation, 'bulkParams.wyckoff.name', '???')}</TableCell>
                    <TableCell padding="none">{`
            [${calculation.bulkParams.elements.join(', ')}]
              `}</TableCell>
                    <TableCell padding="none">{
              `(
              ${calculation.slabParams.millerX},
              ${calculation.slabParams.millerY},
              ${calculation.slabParams.millerZ}
            )`
            }</TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.layers}`} </TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.termination}`} </TableCell>
                    <TableCell padding="none">{`${calculation.slabParams.vacuum}`} </TableCell>
                    <TableCell padding="none">{`${calculation.adsorbateParams.adsorbate}@${calculation.adsorbateParams.siteType} [${calculation.adsorbateParams.cifs.length} sites]`} </TableCell>
                    <TableCell padding="none">{`
            ${calculation.bulkParams.format}
            `}</TableCell>
                    <TableCell padding="none">
                      <Button
                        fab
                        mini
                        className={this.props.classes.actionIcon}
                      >
                        <MdEdit
                          onClick={() => { this.editCalculation(i); }}
                        />
                      </Button>
                      <Button
                        className={this.props.classes.actionIcon}
                        fab
                        mini
                      >
                        <MdContentCopy
                          onClick={() => { this.copyCalculation(i); }}
                        />
                      </Button>
                      <Button
                        fab
                        mini
                        className={this.props.classes.actionIcon}
                      >
                        <MdDelete
                          onClick={() => { this.removeCalculation(i); }}
                        />
                      </Button>
                      {(this.props.openCalculation === i) ?
                        <Button
                          fab mini
                          className={this.props.classes.actionIcon}
                        >
                          <MdClose
                            onClick={() => { this.props.setOpenCalculation(-1); }}
                          />
                        </Button>
                        : null}
                    </TableCell>
                  </TableRow>
                    ))}
              </TableBody>

            <Grid container justify="flex-end" direction="row">
              <Grid item>
                <Button raised onClick={this.clearCalculations} color="inherit" className={this.props.classes.button}><MdClear /> {'\u00A0'}Clear</Button>
              </Grid>
              <Grid item>
                <Button
                  raised
                  onClick={this.downloadCalculations}
                  className={this.props.classes.button}
                  color="primary"
                ><MdFileDownload />{'\u00A0'} Download</Button>
              </Grid>
              {/*
              <Grid item>
                <Button
                  raised
                  onClick={() => {this.queueCalculations()}}
                  color="primary"
                  className={this.props.classes.button}
                ><MdCloud />{'\u00A0'} Queue</Button>
              </Grid>
              */}
            </Grid>

          </Paper>
        </Slide>
        }
        {this.state.loading ? <LinearProgress className={this.props.classes.progress} /> : null }

    );
  }
}

CalculationsView.propTypes = {
  calculations: PropTypes.array,
  clearCalculations: PropTypes.func,
  removeCalculation: PropTypes.func,
  copyCalculation: PropTypes.func,
  openCalculation: PropTypes.number,
  setOpenCalculation: PropTypes.func,
  editCalculation: PropTypes.func,
  stepperHandleReset: PropTypes.func,
  classes: PropTypes.object,
};

module.exports = {
  CalculationsView: withStyles(styles, { withTheme: true })(CalculationsView),
};
<|endoftext|>


<commit_before>(function () {
	function SongPlayer ($rootScope, Fixtures) {
		var SongPlayer = {};

		/**
		* @desc Album information
		* @type {Object}
		*/
		var currentAlbum = Fixtures.getAlbum();

		/**
		* @desc Buzz object audio file
		* @type {Object}
		*/
		var currentBuzzObject = null;

		/**
		* @function setSong
		* @desc Stops currently playing song and loads new audio file as currentBuzzObject
		* @param {Object} song
		*/
		var setSong = function (song) {
			if (currentBuzzObject) {
				currentBuzzObject.stop();
				SongPlayer.currentSong.playing = null;
			}

			currentBuzzObject = new buzz.sound(song.audioUrl, {
				formats: ['mp3'],
				preload: true
			});

			currentBuzzObject.bind('timeupdate', function () {
				$rootScope.$apply(function() {
					SongPlayer.currentTime = currentBuzzObject.getTime();
				});
			});

			SongPlayer.currentSong = song;
		};

		/**
		* @function playSong
		* @desc Plays song and sets the song to currently playing and true.
		* @param {Object} song
		*/
		var playSong = function (song) {
			currentBuzzObject.play();
			song.playing = true;
		};

		/**
		* @function playSong
		* @desc Stops song and sets the song to not currently playing and false.
		* @param {Object} song
		*/
		var stopSong = function (song) {
			currentBuzzObject.stop();
			song.playing = false;
		};

		/**
		* @function getSongIndex
		* @desc Finds the index of a song from the provided album data.
		* @param {Object} song
		*/
		var getSongIndex = function (song) {
			return currentAlbum.songs.indexOf(song);
		};

		/**
		* @method SongPlayer.currentSong
		* @desc Active song object from list of songs
		* @type {Object}
		*/
		SongPlayer.currentSong = null;

		/**
		* @desc Current playback time (in seconds) of currently playing song
		* @type {Number}
		*/
		SongPlayer.currentTime = null;

		/**
		* @desc Current current volume of currently playing song
		* @type {Number}
		*/
		SongPlayer.volume = 80;

		/**
		* @method SongPlayer.play
		* @desc Sets and plays a song or plays a different song based on whether or not song is or is not currently playing.
		* @param {Object} song
		*/
		SongPlayer.play = function (song) {
			song = song || SongPlayer.currentSong;
			if (SongPlayer.currentSong !== song) {
				setSong(song);
				playSong(song);
			} else if (SongPlayer.currentSong === song) {
				if (currentBuzzObject.isPaused()) {
					playSong(song);
				}
			}
		};

		/**
		* @method SongPlayer.pause
		* @desc Pauses a currently playing song and sets it to not currently playing and false
		* @param {Object} song
		*/
		SongPlayer.pause = function (song) {
			song = song || SongPlayer.currentSong;
			currentBuzzObject.pause();
			song.playing = false;
		};

		/**
		* @method SongPlayer.previous
		* @desc Sets and plays the song directly before the current song using the songs index.
		* @param {Object} song
		*/
		SongPlayer.previous = function () {
			var currentSongIndex = getSongIndex(SongPlayer.currentSong);
			currentSongIndex--;

			if (currentSongIndex < 0) {
				var song = SongPlayer.currentSong;
				stopSong(song);
			} else {
				var song = currentAlbum.songs[currentSongIndex];
				setSong(song);
				playSong(song);
			}
		};

		/**
		* @method SongPlayer.next
		* @desc Sets and plays the song directly after the current song using the songs index.
		* @param {Object} song
		*/
		SongPlayer.next = function () {
			var currentSongIndex = getSongIndex(SongPlayer.currentSong);
			currentSongIndex++;

			if (currentSongIndex > currentAlbum.songs.length - 1) {
				var song = SongPlayer.currentSong;
				stopSong(song);
			} else {
				var song = currentAlbum.songs[currentSongIndex];
				setSong(song);
				playSong(song);
			}
		};

		/**
		* @function setCurrentTime
		* @desc Set current time (in seconds) of currently playing song
		* @param {Number} time
		*/
		SongPlayer.setCurrentTime = function (time) {
			if (currentBuzzObject) {
				currentBuzzObject.setTime(time);
			}
		};

		/**
		* @function setVolume
		* @desc Set volume value from 0 - 100 based on the buzz library
		* @param {Number} volume
		*/
		SongPlayer.setVolume = function (volume) {
			if (currentBuzzObject) {
				currentBuzzObject.setVolume(volume);
			}
			SongPlayer.volume = volume;
		};

		return SongPlayer;
	}

	angular
		.module ('blocJams')
		.factory ('SongPlayer',  ['$rootScope', 'Fixtures', SongPlayer]);
})();

<commit_msg>Extra Credit: When song ends next song auto plays<commit_after>(function () {
	function SongPlayer ($rootScope, Fixtures) {
		var SongPlayer = {};

		/**
		* @desc Album information
		* @type {Object}
		*/
		var currentAlbum = Fixtures.getAlbum();

		/**
		* @desc Buzz object audio file
		* @type {Object}
		*/
		var currentBuzzObject = null;

		/**
		* @function setSong
		* @desc Stops currently playing song and loads new audio file as currentBuzzObject
		* @param {Object} song
		*/
		var setSong = function (song) {
			if (currentBuzzObject) {
				currentBuzzObject.stop();
				SongPlayer.currentSong.playing = null;
			}

			currentBuzzObject = new buzz.sound(song.audioUrl, {
				formats: ['mp3'],
				preload: true
			});

			currentBuzzObject.bind('timeupdate', function () {
				$rootScope.$apply(function() {
					SongPlayer.currentTime = currentBuzzObject.getTime();
					if (currentBuzzObject.isEnded()) {
						SongPlayer.next();
					}
				});
			});

			SongPlayer.currentSong = song;
		};

		/**
		* @function playSong
		* @desc Plays song and sets the song to currently playing and true.
		* @param {Object} song
		*/
		var playSong = function (song) {
			currentBuzzObject.play();
			song.playing = true;
		};

		/**
		* @function playSong
		* @desc Stops song and sets the song to not currently playing and false.
		* @param {Object} song
		*/
		var stopSong = function (song) {
			currentBuzzObject.stop();
			song.playing = false;
		};

		/**
		* @function getSongIndex
		* @desc Finds the index of a song from the provided album data.
		* @param {Object} song
		*/
		var getSongIndex = function (song) {
			return currentAlbum.songs.indexOf(song);
		};

		/**
		* @method SongPlayer.currentSong
		* @desc Active song object from list of songs
		* @type {Object}
		*/
		SongPlayer.currentSong = null;

		/**
		* @desc Current playback time (in seconds) of currently playing song
		* @type {Number}
		*/
		SongPlayer.currentTime = null;

		/**
		* @desc Current current volume of currently playing song
		* @type {Number}
		*/
		SongPlayer.volume = 80;

		/**
		* @method SongPlayer.play
		* @desc Sets and plays a song or plays a different song based on whether or not song is or is not currently playing.
		* @param {Object} song
		*/
		SongPlayer.play = function (song) {
			song = song || SongPlayer.currentSong;
			if (SongPlayer.currentSong !== song) {
				setSong(song);
				playSong(song);
			} else if (SongPlayer.currentSong === song) {
				if (currentBuzzObject.isPaused()) {
					playSong(song);
				}
			}
		};

		/**
		* @method SongPlayer.pause
		* @desc Pauses a currently playing song and sets it to not currently playing and false
		* @param {Object} song
		*/
		SongPlayer.pause = function (song) {
			song = song || SongPlayer.currentSong;
			currentBuzzObject.pause();
			song.playing = false;
		};

		/**
		* @method SongPlayer.previous
		* @desc Sets and plays the song directly before the current song using the songs index.
		* @param {Object} song
		*/
		SongPlayer.previous = function () {
			var currentSongIndex = getSongIndex(SongPlayer.currentSong);
			currentSongIndex--;

			if (currentSongIndex < 0) {
				var song = SongPlayer.currentSong;
				stopSong(song);
			} else {
				var song = currentAlbum.songs[currentSongIndex];
				setSong(song);
				playSong(song);
			}
		};

		/**
		* @method SongPlayer.next
		* @desc Sets and plays the song directly after the current song using the songs index.
		* @param {Object} song
		*/
		SongPlayer.next = function () {
			var currentSongIndex = getSongIndex(SongPlayer.currentSong);
			currentSongIndex++;

			if (currentSongIndex > currentAlbum.songs.length - 1) {
				var song = SongPlayer.currentSong;
				stopSong(song);
			} else {
				var song = currentAlbum.songs[currentSongIndex];
				setSong(song);
				playSong(song);
			}
		};

		/**
		* @function setCurrentTime
		* @desc Set current time (in seconds) of currently playing song
		* @param {Number} time
		*/
		SongPlayer.setCurrentTime = function (time) {
			if (currentBuzzObject) {
				currentBuzzObject.setTime(time);
			}
		};

		/**
		* @function setVolume
		* @desc Set volume value from 0 - 100 based on the buzz library
		* @param {Number} volume
		*/
		SongPlayer.setVolume = function (volume) {
			if (currentBuzzObject) {
				currentBuzzObject.setVolume(volume);
			}
			SongPlayer.volume = volume;
		};

		return SongPlayer;
	}

	angular
		.module ('blocJams')
		.factory ('SongPlayer',  ['$rootScope', 'Fixtures', SongPlayer]);
})();

<|endoftext|>