<commit_before>var drawerIsOpen = false;
var browserStorage = $.localStorage;
var defaultSettings = {
	"units": "mg/dl",
	"alarmHigh": true,
	"alarmLow": true,
	"nightMode": false
}

var app = {};
$.ajax("/api/v1/status.json", {
	success: function (xhr) {
		app = {
			"name": xhr.name,
			"version": xhr.version,
			"apiEnabled": xhr.apiEnabled
		}
	}
}).done(function() {
	$(".appName").text(app.name);
	$(".version").text(app.version);
	if (app.apiEnabled) {
		$(".serverSettings").show();
	}
});

function getBrowserSettings(storage) {
	var json = {
		"units": storage.get("units"),
		"alarmHigh": storage.get("alarmHigh"),
		"alarmLow": storage.get("alarmLow"),
		"nightMode": storage.get("nightMode"),
		"customTitle": storage.get("customTitle")
	};

	// Default browser units to server units if undefined.
	json.units = setDefault(json.units, serverSettings.units);
	if (json.units == "mmol") {
		$("#mmol-browser").prop("checked", true);
	} else {
		$("#mgdl-browser").prop("checked", true);
	}

	json.alarmHigh = setDefault(json.alarmHigh, defaultSettings.alarmHigh);
	$("#alarmhigh-browser").prop("checked", json.alarmHigh);
	json.alarmLow = setDefault(json.alarmLow, defaultSettings.alarmLow);
	$("#alarmlow-browser").prop("checked", json.alarmLow);

	json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode);
	$("#nightmode-browser").prop("checked", json.nightMode);

	if (json.customTitle) {
		$("h1.customTitle").html(json.customTitle);
		$("input#customTitle").prop("value", json.customTitle);
		document.title = "Nightscout: " + json.customTitle;
	}

	return json;
}
function getServerSettings() {
	var json = {
		"units": Object()
	};

	json.units = setDefault(json.units, defaultSettings.units);
	//console.log("serverSettings.units: " + json.units);
	if (json.units == "mmol") {
		$("#mmol-server").prop("checked", true);
	} else {
		$("#mgdl-server").prop("checked", true);
	}

	return json;
}
function setDefault(variable, defaultValue) {
	if (typeof(variable) === "object") {
		return defaultValue;
	}
	return variable;
}
function jsonIsNotEmpty(json) {
	var jsonAsString = JSON.stringify(json);
	jsonAsString.replace(/\s/g, "");
	return (jsonAsString != "{}")
}
function storeInBrowser(json, storage) {
	if (json.units) storage.set("units", json.units);
	if (json.alarmHigh == true) {
		storage.set("alarmHigh", true)
	} else {
		storage.set("alarmHigh", false)
	}
	if (json.alarmLow == true) {
		storage.set("alarmLow", true)
	} else {
		storage.set("alarmLow", false)
	}
	if (json.nightMode == true) {
		storage.set("nightMode", true)
	} else {
		storage.set("nightMode", false)
	}
	if (json.customTitle) storage.set("customTitle", json.customTitle);
	event.preventDefault();
}
function storeOnServer(json) {
	if (jsonIsNotEmpty(json)) {
		alert("TO DO: add storeOnServer() logic.");
		// reference: http://code.tutsplus.com/tutorials/submit-a-form-without-page-refresh-using-jquery--net-59
		//var dataString = "name="+ name + "&email=" + email + "&phone=" + phone;
		//alert (dataString);return false;
		/* $.ajax({
		  type: "POST",
		  url: "/api/v1/settings",
		  data: json
		});
		*/
	}
}

function getQueryParms() {
	params = {};
	if (location.search) {
		location.search.substr(1).split("&").forEach(function(item) {
			params[item.split("=")[0]] = item.split("=")[1].replace(/[_\+]/g, " ");
		});
	}
	return params;
}

function isTouch() {
	try{ document.createEvent("TouchEvent"); return true; }
	catch(e){ return false; }
}

function closeDrawer(callback) {
	$("#container").animate({marginLeft: "0px"}, 300, callback);
	$("#chartContainer").animate({marginLeft: "0px"}, 300);
	$("#drawer").animate({right: "-200px"}, 300, function() {
		$("#drawer").css("display", "none");
	});
	drawerIsOpen = false;
}
function openDrawer()  {
	drawerIsOpen = true;
	$("#container").animate({marginLeft: "-200px"}, 300);
	$("#chartContainer").animate({marginLeft: "-200px"}, 300);
	$("#drawer").css("display", "block");
	$("#drawer").animate({right: "0"}, 300);
}

function closeNotification() {
	var notify = $("#notification");
	notify.hide();
	notify.find("span").html("");
}
function showNotification(note, type)  {
	var notify = $("#notification");
	notify.hide();

	// Notification types: "info", "warn", "success", "urgent".
	// - default: "urgent"
	notify.removeClass("info warn urgent");
	notify.addClass(type ? type : "urgent");

	notify.find("span").html(note);
	notify.css("left", "calc(50% - " + ($("#notification").width() / 2) + "px)");
	notify.show();
}

function closeToolbar() {
	stretchStatusForToolbar("close");

	$("#showToolbar").css({top: "44px"});
	$("#showToolbar").fadeIn(50, function() {
		$("#showToolbar").animate({top: 0}, 200);
		$("#toolbar").animate({marginTop: "-44px"}, 200);
	});
}
function openToolbar() {
	$("#showToolbar").css({top: 0});
	$("#showToolbar").animate({top: "44px"}, 200).fadeOut(200);
	$("#toolbar").animate({marginTop: "0px"}, 200);

	stretchStatusForToolbar("open");
}
function stretchStatusForToolbar(toolbarState){
	// closed = up
	if (toolbarState == "close") {
		$(".status").css({
			"font-size": "+125%"
		});
	}

	// open = down
	if (toolbarState == "open") {
		$(".status").css({
			"font-size": "-125%"
		});
	}
}

var querystring = getQueryParms();
// var serverSettings = getServerSettings();
var browserSettings = getBrowserSettings(browserStorage);

function Dropdown(el) {
	this.ddmenuitem = 0;

	this.$el = $(el);
	var that = this;

	$(document).click(function() { that.close(); });
}
Dropdown.prototype.close = function () {
	if (this.ddmenuitem) {
		this.ddmenuitem.css('visibility', 'hidden');
		this.ddmenuitem = 0;
	}
};
Dropdown.prototype.open = function (e) {
	this.close();
	this.ddmenuitem = $(this.$el).css('visibility', 'visible');
	e.stopPropagation();
};

$("#drawerToggle").click(function(event) {
	if(drawerIsOpen) {
		closeDrawer();
		drawerIsOpen = false;
	}  else {
		openDrawer();
		drawerIsOpen = true;
	}
	event.preventDefault();
});

$("#notification").click(function(event) {
	closeNotification();
	event.preventDefault();
});

$("#hideToolbar").click(function(event) {
	if (drawerIsOpen) {
		closeDrawer(function() {
			closeToolbar();
		});
	} else {
		closeToolbar();
	}
	event.preventDefault();
});
$("#showToolbar").find("a").click(function(event) {
	openToolbar();
	event.preventDefault();
});

$("input#save").click(function() {
	storeInBrowser({
		"units": $("input:radio[name=units-browser]:checked").val(),
		"alarmHigh": $("#alarmhigh-browser").prop("checked"),
		"alarmLow": $("#alarmlow-browser").prop("checked"),
		"nightMode": $("#nightmode-browser").prop("checked"),
		"customTitle": $("input#customTitle").prop("value")
	}, browserStorage);

	storeOnServer({
		//"units": $("input:radio[name=units-server]:checked").val()
	});

	event.preventDefault();

	// reload for changes to take effect
	// -- strip '#' so form submission does not fail
	var url = window.location.href;
	url = url.replace(/#$/, "");
	window.location = url;
});

$(function() {
	// Tooltips can remain in the way on touch screens.
	var notTouchScreen = (!isTouch());
	if (notTouchScreen) {
		$(".tip").tipsy();
	} else {
		// Drawer info tips should be displayed on touchscreens.
		$("#drawer").find(".tip").tipsy();
	}
	$.fn.tipsy.defaults = {
		fade: true,
		gravity: "n",
		opacity: 0.75
	}

	if (querystring.notify) {
		showNotification(querystring.notify, querystring.notifytype);
	}

	if (querystring.drawer) {
		openDrawer();
	} else {
		// drawer=true cancels out toolbar=false
		if (querystring.toolbar == "false") {
			closeToolbar();
		}
	}

	setTimeout(function(){$("#loader").fadeOut(1500)}, 2000);
});
<commit_msg>Loading screen, remove 2 sec delay<commit_after>var drawerIsOpen = false;
var browserStorage = $.localStorage;
var defaultSettings = {
	"units": "mg/dl",
	"alarmHigh": true,
	"alarmLow": true,
	"nightMode": false
}

var app = {};
$.ajax("/api/v1/status.json", {
	success: function (xhr) {
		app = {
			"name": xhr.name,
			"version": xhr.version,
			"apiEnabled": xhr.apiEnabled
		}
	}
}).done(function() {
	$(".appName").text(app.name);
	$(".version").text(app.version);
	if (app.apiEnabled) {
		$(".serverSettings").show();
	}
});

function getBrowserSettings(storage) {
	var json = {
		"units": storage.get("units"),
		"alarmHigh": storage.get("alarmHigh"),
		"alarmLow": storage.get("alarmLow"),
		"nightMode": storage.get("nightMode"),
		"customTitle": storage.get("customTitle")
	};

	// Default browser units to server units if undefined.
	json.units = setDefault(json.units, serverSettings.units);
	if (json.units == "mmol") {
		$("#mmol-browser").prop("checked", true);
	} else {
		$("#mgdl-browser").prop("checked", true);
	}

	json.alarmHigh = setDefault(json.alarmHigh, defaultSettings.alarmHigh);
	$("#alarmhigh-browser").prop("checked", json.alarmHigh);
	json.alarmLow = setDefault(json.alarmLow, defaultSettings.alarmLow);
	$("#alarmlow-browser").prop("checked", json.alarmLow);

	json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode);
	$("#nightmode-browser").prop("checked", json.nightMode);

	if (json.customTitle) {
		$("h1.customTitle").html(json.customTitle);
		$("input#customTitle").prop("value", json.customTitle);
		document.title = "Nightscout: " + json.customTitle;
	}

	return json;
}
function getServerSettings() {
	var json = {
		"units": Object()
	};

	json.units = setDefault(json.units, defaultSettings.units);
	//console.log("serverSettings.units: " + json.units);
	if (json.units == "mmol") {
		$("#mmol-server").prop("checked", true);
	} else {
		$("#mgdl-server").prop("checked", true);
	}

	return json;
}
function setDefault(variable, defaultValue) {
	if (typeof(variable) === "object") {
		return defaultValue;
	}
	return variable;
}
function jsonIsNotEmpty(json) {
	var jsonAsString = JSON.stringify(json);
	jsonAsString.replace(/\s/g, "");
	return (jsonAsString != "{}")
}
function storeInBrowser(json, storage) {
	if (json.units) storage.set("units", json.units);
	if (json.alarmHigh == true) {
		storage.set("alarmHigh", true)
	} else {
		storage.set("alarmHigh", false)
	}
	if (json.alarmLow == true) {
		storage.set("alarmLow", true)
	} else {
		storage.set("alarmLow", false)
	}
	if (json.nightMode == true) {
		storage.set("nightMode", true)
	} else {
		storage.set("nightMode", false)
	}
	if (json.customTitle) storage.set("customTitle", json.customTitle);
	event.preventDefault();
}
function storeOnServer(json) {
	if (jsonIsNotEmpty(json)) {
		alert("TO DO: add storeOnServer() logic.");
		// reference: http://code.tutsplus.com/tutorials/submit-a-form-without-page-refresh-using-jquery--net-59
		//var dataString = "name="+ name + "&email=" + email + "&phone=" + phone;
		//alert (dataString);return false;
		/* $.ajax({
		  type: "POST",
		  url: "/api/v1/settings",
		  data: json
		});
		*/
	}
}

function getQueryParms() {
	params = {};
	if (location.search) {
		location.search.substr(1).split("&").forEach(function(item) {
			params[item.split("=")[0]] = item.split("=")[1].replace(/[_\+]/g, " ");
		});
	}
	return params;
}

function isTouch() {
	try{ document.createEvent("TouchEvent"); return true; }
	catch(e){ return false; }
}

function closeDrawer(callback) {
	$("#container").animate({marginLeft: "0px"}, 300, callback);
	$("#chartContainer").animate({marginLeft: "0px"}, 300);
	$("#drawer").animate({right: "-200px"}, 300, function() {
		$("#drawer").css("display", "none");
	});
	drawerIsOpen = false;
}
function openDrawer()  {
	drawerIsOpen = true;
	$("#container").animate({marginLeft: "-200px"}, 300);
	$("#chartContainer").animate({marginLeft: "-200px"}, 300);
	$("#drawer").css("display", "block");
	$("#drawer").animate({right: "0"}, 300);
}

function closeNotification() {
	var notify = $("#notification");
	notify.hide();
	notify.find("span").html("");
}
function showNotification(note, type)  {
	var notify = $("#notification");
	notify.hide();

	// Notification types: "info", "warn", "success", "urgent".
	// - default: "urgent"
	notify.removeClass("info warn urgent");
	notify.addClass(type ? type : "urgent");

	notify.find("span").html(note);
	notify.css("left", "calc(50% - " + ($("#notification").width() / 2) + "px)");
	notify.show();
}

function closeToolbar() {
	stretchStatusForToolbar("close");

	$("#showToolbar").css({top: "44px"});
	$("#showToolbar").fadeIn(50, function() {
		$("#showToolbar").animate({top: 0}, 200);
		$("#toolbar").animate({marginTop: "-44px"}, 200);
	});
}
function openToolbar() {
	$("#showToolbar").css({top: 0});
	$("#showToolbar").animate({top: "44px"}, 200).fadeOut(200);
	$("#toolbar").animate({marginTop: "0px"}, 200);

	stretchStatusForToolbar("open");
}
function stretchStatusForToolbar(toolbarState){
	// closed = up
	if (toolbarState == "close") {
		$(".status").css({
			"font-size": "+125%"
		});
	}

	// open = down
	if (toolbarState == "open") {
		$(".status").css({
			"font-size": "-125%"
		});
	}
}

var querystring = getQueryParms();
// var serverSettings = getServerSettings();
var browserSettings = getBrowserSettings(browserStorage);

function Dropdown(el) {
	this.ddmenuitem = 0;

	this.$el = $(el);
	var that = this;

	$(document).click(function() { that.close(); });
}
Dropdown.prototype.close = function () {
	if (this.ddmenuitem) {
		this.ddmenuitem.css('visibility', 'hidden');
		this.ddmenuitem = 0;
	}
};
Dropdown.prototype.open = function (e) {
	this.close();
	this.ddmenuitem = $(this.$el).css('visibility', 'visible');
	e.stopPropagation();
};

$("#drawerToggle").click(function(event) {
	if(drawerIsOpen) {
		closeDrawer();
		drawerIsOpen = false;
	}  else {
		openDrawer();
		drawerIsOpen = true;
	}
	event.preventDefault();
});

$("#notification").click(function(event) {
	closeNotification();
	event.preventDefault();
});

$("#hideToolbar").click(function(event) {
	if (drawerIsOpen) {
		closeDrawer(function() {
			closeToolbar();
		});
	} else {
		closeToolbar();
	}
	event.preventDefault();
});
$("#showToolbar").find("a").click(function(event) {
	openToolbar();
	event.preventDefault();
});

$("input#save").click(function() {
	storeInBrowser({
		"units": $("input:radio[name=units-browser]:checked").val(),
		"alarmHigh": $("#alarmhigh-browser").prop("checked"),
		"alarmLow": $("#alarmlow-browser").prop("checked"),
		"nightMode": $("#nightmode-browser").prop("checked"),
		"customTitle": $("input#customTitle").prop("value")
	}, browserStorage);

	storeOnServer({
		//"units": $("input:radio[name=units-server]:checked").val()
	});

	event.preventDefault();

	// reload for changes to take effect
	// -- strip '#' so form submission does not fail
	var url = window.location.href;
	url = url.replace(/#$/, "");
	window.location = url;
});

$(function() {
	// Tooltips can remain in the way on touch screens.
	var notTouchScreen = (!isTouch());
	if (notTouchScreen) {
		$(".tip").tipsy();
	} else {
		// Drawer info tips should be displayed on touchscreens.
		$("#drawer").find(".tip").tipsy();
	}
	$.fn.tipsy.defaults = {
		fade: true,
		gravity: "n",
		opacity: 0.75
	}

	if (querystring.notify) {
		showNotification(querystring.notify, querystring.notifytype);
	}

	if (querystring.drawer) {
		openDrawer();
	} else {
		// drawer=true cancels out toolbar=false
		if (querystring.toolbar == "false") {
			closeToolbar();
		}
	}

	//setTimeout(function(){$("#loader").fadeOut(1500)}, 2000);
	$("#loader").fadeOut(1500);
});
<|endoftext|>


<commit_before>var lp;    // Luisterpaal object
var sk;    // Session key
var np;    // 'Now Playing' url
var su;    // Submission url
var track; // Currently playing track
var np_to; // 'Now Playing' timeout

// TODO Add a div with status messages.

$(function() {
    $('button[name=yes]').click(function(){
        $('#content').fadeOut("normal", function(){ $(this).hide() });
        $('#luisterpaal').show();
    });

    $('button[name=no]').click(function(){
        eraseCookie("session");
        window.location.href = '.'; // Reload
    });

    // Initialize luisterpaal
    var token = getSessionToken();

    if (token == undefined) return;
    // else

    // TODO Get a new token when the handshake fails
    $.getJSON("?" + $.param(token), onHandshake)
});

function onHandshake(response) {
    if (response.error != undefined) {
        alert("Ah verdorie, er ging iets mis. (" + response.error + ")");
        return;
    } // else

    var handshake = response.handshake;
    sk = handshake[0];
    np = handshake[1].replace('http://', '');
    su = handshake[2].replace('http://', '');

    swfobject.embedSWF("http://download.omroep.nl/vpro/luisterpaal/"+
                       "widgets/LuisterpaalEvents.swf?oninit=onLPLoad",
                       "luisterpaal","240","320","8", false,
                       {}, {allowscriptaccess: "always"}, {});
}

function getSessionToken() {
    var token = readCookie("session");
    if (token) {
        var session = token.replace(/"/g,'').split(':');
        return { user: session[0], key: session[1] }
    }
}

function onLPLoad() {
   lp = (typeof window["luisterpaal"] != "undefined")
      ? window["luisterpaal"]
      : document["luisterpaal"];

   // Listen to all events
   lp.addLPEventListener("START",  "start");
   lp.addLPEventListener("STOP",   "stop");
   lp.addLPEventListener("PAUSE",  "pause");
   lp.addLPEventListener("RESUME", "resume");
}

function start(e) {
    // A start is an implicit stop of the previous track
    stop();

    var t = e.track;

    track = { a: decodeURIComponent(t.artist)
            , t: decodeURIComponent(t.name)
            , b: decodeURIComponent(t.album)
            , l: t.duration
            , n: t.trackNumber
            , i: now()
            , paused: 0
            , paused_since: undefined
            }

    unvariousArtist()

    // Clear the call, mainly to prevent submitting data too soon (because if
    // 'track' updated in the mean time that's okay).
    clearTimeout(np_to);

    np_to = setTimeout(function() {
        // TODO Check response
        $.post("proxy/" + np
              , { s: sk
                , a: track.a
                , t: track.t
                , b: track.b
                , l: track.l
                , n: track.n
                , m: ""
                }
              );
    }, 10000); // Set now playing info after 10 seconds.
}

function stop() {
    if (! track) return;
    // else

    // If now playing info was not yet send, don't do it
    clearTimeout(np_to);

    // Don't scrobble tracks that are too short
    if (track.l < 30) return;
    // else

    // Check if the track was paused
    resume();

    var played_for = now() - track.i - track.paused;
    // Played too short
    if (played_for < 240 && played_for < track.l / 2) return;
    // else

    // TODO Check response
    $.post("proxy/" + su
          , { "s"   : sk
            , "a[0]": track.a
            , "t[0]": track.t
            , "i[0]": track.i
            , "o[0]": "P"
            , "r[0]": ""
            , "b[0]": track.b
            , "l[0]": track.l
            , "n[0]": track.n
            , "m[0]": ""
            }
          );
}

function pause() {
    if (! track) return;
    // else
    track.paused_since = now();
}

function resume() {
    if (! track || ! track.paused_since) return;
    // else
    track.paused += now() - track.paused_since;
    track.paused_since = undefined;
}

function now() {
    return Math.round(new Date().getTime() / 1000);
}

function unvariousArtist() {
    if (track.a.match(/diverse artiesten|various artists/i) != null) {
        track.a = track.t.split(' - ')[0];
        track.t = track.t.split(' - ').slice(1).join(' - ');
    }
}

// From: PPK, http://www.quirksmode.org/js/cookies.html#doccookie
function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name) {
    var date = new Date();
    date.setTime(date.getTime() - 3600);
    document.cookie = name+"="+";expires="+date.toGMTString()+"; path=/";
}
<commit_msg>Support more kinds of dashes<commit_after>var lp;    // Luisterpaal object
var sk;    // Session key
var np;    // 'Now Playing' url
var su;    // Submission url
var track; // Currently playing track
var np_to; // 'Now Playing' timeout

// TODO Add a div with status messages.

$(function() {
    $('button[name=yes]').click(function(){
        $('#content').fadeOut("normal", function(){ $(this).hide() });
        $('#luisterpaal').show();
    });

    $('button[name=no]').click(function(){
        eraseCookie("session");
        window.location.href = '.'; // Reload
    });

    // Initialize luisterpaal
    var token = getSessionToken();

    if (token == undefined) return;
    // else

    // TODO Get a new token when the handshake fails
    $.getJSON("?" + $.param(token), onHandshake)
});

function onHandshake(response) {
    if (response.error != undefined) {
        alert("Ah verdorie, er ging iets mis. (" + response.error + ")");
        return;
    } // else

    var handshake = response.handshake;
    sk = handshake[0];
    np = handshake[1].replace('http://', '');
    su = handshake[2].replace('http://', '');

    swfobject.embedSWF("http://download.omroep.nl/vpro/luisterpaal/"+
                       "widgets/LuisterpaalEvents.swf?oninit=onLPLoad",
                       "luisterpaal","240","320","8", false,
                       {}, {allowscriptaccess: "always"}, {});
}

function getSessionToken() {
    var token = readCookie("session");
    if (token) {
        var session = token.replace(/"/g,'').split(':');
        return { user: session[0], key: session[1] }
    }
}

function onLPLoad() {
   lp = (typeof window["luisterpaal"] != "undefined")
      ? window["luisterpaal"]
      : document["luisterpaal"];

   // Listen to all events
   lp.addLPEventListener("START",  "start");
   lp.addLPEventListener("STOP",   "stop");
   lp.addLPEventListener("PAUSE",  "pause");
   lp.addLPEventListener("RESUME", "resume");
}

function start(e) {
    // A start is an implicit stop of the previous track
    stop();

    var t = e.track;

    track = { a: decodeURIComponent(t.artist)
            , t: decodeURIComponent(t.name)
            , b: decodeURIComponent(t.album)
            , l: t.duration
            , n: t.trackNumber
            , i: now()
            , paused: 0
            , paused_since: undefined
            }

    unvariousArtist()

    // Clear the call, mainly to prevent submitting data too soon (because if
    // 'track' updated in the mean time that's okay).
    clearTimeout(np_to);

    np_to = setTimeout(function() {
        // TODO Check response
        $.post("proxy/" + np
              , { s: sk
                , a: track.a
                , t: track.t
                , b: track.b
                , l: track.l
                , n: track.n
                , m: ""
                }
              );
    }, 10000); // Set now playing info after 10 seconds.
}

function stop() {
    if (! track) return;
    // else

    // If now playing info was not yet send, don't do it
    clearTimeout(np_to);

    // Don't scrobble tracks that are too short
    if (track.l < 30) return;
    // else

    // Check if the track was paused
    resume();

    var played_for = now() - track.i - track.paused;
    // Played too short
    if (played_for < 240 && played_for < track.l / 2) return;
    // else

    // TODO Check response
    $.post("proxy/" + su
          , { "s"   : sk
            , "a[0]": track.a
            , "t[0]": track.t
            , "i[0]": track.i
            , "o[0]": "P"
            , "r[0]": ""
            , "b[0]": track.b
            , "l[0]": track.l
            , "n[0]": track.n
            , "m[0]": ""
            }
          );
}

function pause() {
    if (! track) return;
    // else
    track.paused_since = now();
}

function resume() {
    if (! track || ! track.paused_since) return;
    // else
    track.paused += now() - track.paused_since;
    track.paused_since = undefined;
}

function now() {
    return Math.round(new Date().getTime() / 1000);
}

function unvariousArtist() {
    if (track.a.match(/diverse artiesten|various artists/i) != null) {
        track.a = track.t.split(/ - | – /)[0];
        track.t = track.t.split(/ - | – /).slice(1).join(' - ');
    }
}

// From: PPK, http://www.quirksmode.org/js/cookies.html#doccookie
function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name) {
    var date = new Date();
    date.setTime(date.getTime() - 3600);
    document.cookie = name+"="+";expires="+date.toGMTString()+"; path=/";
}
<|endoftext|>


<commit_before><commit_msg>handle tagGroups on server side in gatsby node<commit_after><|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

/**
  @class

  A ManyArray is used to map an array of record ids back to their
  record objects which will be materialized from the owner store on demand.

  Whenever you create a toMany() relationship, the value returned from the
  property will be an instance of ManyArray.  You can generally customize the
  behavior of ManyArray by passing settings to the toMany() helper.

  @extends SC.Enumerable
  @extends SC.Array
  @since SproutCore 1.0
*/

SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
  /** @scope SC.ManyArray.prototype */ {

  /**
    recordType will tell what type to transform the record to when
    materializing the record.

    @property {String}
  */
  recordType: null,

  /**
    If set, the record will be notified whenever the array changes so that
    it can change its own state

    @property {SC.Record}
  */
  record: null,

  /**
    If set will be used by the many array to get an editable version of the
    storeIds from the owner.

    @property {String}
  */
  propertyName: null,

  /**
    The ManyAttribute that created this array.

    @property {SC.ManyAttribute}
  */
  manyAttribute: null,

  /**
    The store that owns this record array.  All record arrays must have a
    store to function properly.

    @property {SC.Store}
  */
  store: function() {
    return this.get('record').get('store');
  }.property('record').cacheable(),

  /**
    The storeKey for the parent record of this many array.  Editing this
    array will place the parent record into a READY_DIRTY state.

    @property {Number}
  */
  storeKey: function() {
    return this.get('record').get('storeKey');
  }.property('record').cacheable(),

  /**
    Returns the storeIds in read only mode.  Avoids modifying the record
    unnecessarily.

    @property {SC.Array}
  */
  readOnlyStoreIds: function() {
    return this.get('record').readAttribute(this.get('propertyName'));
  }.property(),

  /**
    Returns an editable array of storeIds.  Marks the owner records as
    modified.

    @property {SC.Array}
  */
  editableStoreIds: function() {
    var store    = this.get('store'),
        storeKey = this.get('storeKey'),
        pname    = this.get('propertyName'),
        ret, hash;

    ret = store.readEditableProperty(storeKey, pname);
    if (!ret) {
      hash = store.readEditableDataHash(storeKey);
      ret = hash[pname] = [];
    }

    if (ret !== this._prevStoreIds) this.recordPropertyDidChange();
    return ret ;
  }.property(),

  // ..........................................................
  // COMPUTED FROM OWNER
  //

  /**
    Computed from owner many attribute

    @property {Boolean}
  */
  isEditable: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('isEditable') : NO;
  }.property('manyAttribute').cacheable(),

  /**
    Computed from owner many attribute

    @property {String}
  */
  inverse: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('inverse') : null;
  }.property('manyAttribute').cacheable(),

  /**
    Computed from owner many attribute

    @property {Boolean}
  */
  isMaster: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('isMaster') : null;
  }.property("manyAttribute").cacheable(),

  /**
    Computed from owner many attribute

    @property {Array}
  */
  orderBy: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('orderBy') : null;
  }.property("manyAttribute").cacheable(),

  // ..........................................................
  // ARRAY PRIMITIVES
  //

  /** @private
    Returned length is a pass-through to the storeIds array.

    @property {Number}
  */
  length: function() {
    var storeIds = this.get('readOnlyStoreIds');
    return storeIds ? storeIds.get('length') : 0;
  }.property('readOnlyStoreIds').cacheable(),

  /** @private
    Looks up the store id in the store ids array and materializes a
    records.
  */
  objectAt: function(idx) {
    var recs      = this._records,
        storeIds  = this.get('readOnlyStoreIds'),
        store     = this.get('store'),
        recordType = this.get('recordType'),
        storeKey, ret, storeId ;

    if (!storeIds || !store) return undefined; // nothing to do
    if (recs && (ret=recs[idx])) return ret ; // cached

    // not in cache, materialize
    if (!recs) this._records = recs = [] ; // create cache
    storeId = storeIds.objectAt(idx);
    if (storeId) {

      // if record is not loaded already, then ask the data source to
      // retrieve it
      storeKey = store.storeKeyFor(recordType, storeId);

      if (store.readStatus(storeKey) === SC.Record.EMPTY) {
        store.retrieveRecord(recordType, null, storeKey);
      }

      recs[idx] = ret = store.materializeRecord(storeKey);
    }
    return ret ;
  },

  /** @private
    Pass through to the underlying array.  The passed in objects must be
    records, which can be converted to storeIds.
  */
  replace: function(idx, amt, recs) {

    if (!this.get('isEditable')) {
      throw "%@.%@[] is not editable".fmt(this.get('record'), this.get('propertyName'));
    }

    var storeIds = this.get('editableStoreIds'),
        len      = recs ? (recs.get ? recs.get('length') : recs.length) : 0,
        record   = this.get('record'),
        pname    = this.get('propertyName'),
        i, keys, ids, toRemove, inverse, attr, inverseRecord;

    // map to store keys
    ids = [] ;
    for(i=0;i<len;i++) ids[i] = recs.objectAt(i).get('id');

    // if we have an inverse - collect the list of records we are about to
    // remove
    inverse = this.get('inverse');
    if (inverse && amt>0) {
      toRemove = SC.ManyArray._toRemove;
      if (toRemove) SC.ManyArray._toRemove = null; // reuse if possible
      else toRemove = [];

      for(i=0;i<amt;i++) toRemove[i] = this.objectAt(i);
    }

    // pass along - if allowed, this should trigger the content observer
    storeIds.replace(idx, amt, ids);

    // ok, notify records that were removed then added; this way reordered
    // objects are added and removed
    if (inverse) {

      // notive removals
      for(i=0;i<amt;i++) {
        inverseRecord = toRemove[i];
        attr = inverseRecord ? inverseRecord[inverse] : null;
        if (attr && attr.inverseDidRemoveRecord) {
          attr.inverseDidRemoveRecord(inverseRecord, inverse, record, pname);
        }
      }

      if (toRemove) {
        toRemove.length = 0; // cleanup
        if (!SC.ManyArray._toRemove) SC.ManyArray._toRemove = toRemove;
      }

      // notify additions
      for(i=0;i<len;i++) {
        inverseRecord = recs.objectAt(i);
        attr = inverseRecord ? inverseRecord[inverse] : null;
        if (attr && attr.inverseDidAddRecord) {
          attr.inverseDidAddRecord(inverseRecord, inverse, record, pname);
        }
      }

    }

    // only mark record dirty if there is no inverse or we are master
    if (record && (!inverse || this.get('isMaster'))) {
      record.recordDidChange(pname);
    }

    return this;
  },

  // ..........................................................
  // INVERSE SUPPORT
  //

  /**
    Called by the ManyAttribute whenever a record is removed on the inverse
    of the relationship.

    @param {SC.Record} inverseRecord the record that was removed
    @returns {SC.ManyArray} receiver
  */
  removeInverseRecord: function(inverseRecord) {

    if (!inverseRecord) return this; // nothing to do
    var id = inverseRecord.get('id'),
        storeIds = this.get('editableStoreIds'),
        idx      = (storeIds && id) ? storeIds.indexOf(id) : -1,
        record;

    if (idx >= 0) {
      storeIds.removeAt(idx);
      if (this.get('isMaster') && (record = this.get('record'))) {
        record.recordDidChange(this.get('propertyName'));
      }
    }

    return this;
  },

  /**
    Called by the ManyAttribute whenever a record is added on the inverse
    of the relationship.

    @param {SC.Record} record the record this array is a part of
    @param {String} key the key this array represents
    @param {SC.Record} inverseRecord the record that was removed
    @param {String} inverseKey the name of inverse that was changed
    @returns {SC.ManyArray} receiver
  */
  addInverseRecord: function(inverseRecord) {

    if (!inverseRecord) return this;
    var id = inverseRecord.get('id'),
        storeIds = this.get('editableStoreIds'),
        orderBy  = this.get('orderBy'),
        len      = storeIds.get('length'),
        idx, record;

    // find idx to insert at.
    if (orderBy) {
      idx = this._findInsertionLocation(inverseRecord, 0, len, orderBy);
    } else idx = len;

    storeIds.insertAt(idx, inverseRecord.get('id'));
    if (this.get('isMaster') && (record = this.get('record'))) {
      record.recordDidChange(this.get('propertyName'));
    }

    return this;
  },

  // binary search to find insertion location
  _findInsertionLocation: function(rec, min, max, orderBy) {
    var idx   = min+Math.floor((max-min)/2),
        cur   = this.objectAt(idx),
        order = this._compare(rec, cur, orderBy);
    if (order < 0) {
      if (idx===0) return idx;
      else return this._findInsertionLocation(rec, 0, idx, orderBy);
    } else if (order > 0) {
      if (idx >= max) return idx;
      else return this._findInsertionLocation(rec, idx, max, orderBy);
    } else return idx;
  },

  _compare: function(a, b, orderBy) {
    var t = SC.typeOf(orderBy),
        ret, idx, len;

    if (t === SC.T_FUNCTION) ret = orderBy(a, b);
    else if (t === SC.T_STRING) ret = SC.compare(a,b);
    else {
      len = orderBy.get('length');
      ret = 0;
      for(idx=0;(ret===0) && (idx<len);idx++) ret = SC.compare(a,b);
    }

    return ret ;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  /** @private
    Invoked whenever the storeIds array changes.  Observes changes.
  */
  recordPropertyDidChange: function(keys) {

    if (keys && !keys.contains(this.get('propertyName'))) return this;

    var storeIds = this.get('readOnlyStoreIds');
    var prev = this._prevStoreIds, f = this._storeIdsContentDidChange;

    if (storeIds === prev) return this; // nothing to do

    if (prev) prev.removeObserver('[]', this, f);
    this._prevStoreIds = storeIds;
    if (storeIds) storeIds.addObserver('[]', this, f);

    var rev = (storeIds) ? storeIds.propertyRevision : -1 ;
    this._storeIdsContentDidChange(storeIds, '[]', storeIds, rev);

  },

  /** @private
    Invoked whenever the content of the storeIds array changes.  This will
    dump any cached record lookup and then notify that the enumerable content
    has changed.
  */
  _storeIdsContentDidChange: function(target, key, value, rev) {
    this._records = null ; // clear cache
    this.enumerableContentDidChange();
  },

  /** @private */
  unknownProperty: function(key, value) {
    var ret = this.reducedProperty(key, value);
    return ret === undefined ? sc_super() : ret;
  },

  /** @private */
  init: function() {
    sc_super();
    this.recordPropertyDidChange();
  }

}) ;<commit_msg>Remove cacheable on the length property of the many array<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

/**
  @class

  A ManyArray is used to map an array of record ids back to their
  record objects which will be materialized from the owner store on demand.

  Whenever you create a toMany() relationship, the value returned from the
  property will be an instance of ManyArray.  You can generally customize the
  behavior of ManyArray by passing settings to the toMany() helper.

  @extends SC.Enumerable
  @extends SC.Array
  @since SproutCore 1.0
*/

SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
  /** @scope SC.ManyArray.prototype */ {

  /**
    recordType will tell what type to transform the record to when
    materializing the record.

    @property {String}
  */
  recordType: null,

  /**
    If set, the record will be notified whenever the array changes so that
    it can change its own state

    @property {SC.Record}
  */
  record: null,

  /**
    If set will be used by the many array to get an editable version of the
    storeIds from the owner.

    @property {String}
  */
  propertyName: null,

  /**
    The ManyAttribute that created this array.

    @property {SC.ManyAttribute}
  */
  manyAttribute: null,

  /**
    The store that owns this record array.  All record arrays must have a
    store to function properly.

    @property {SC.Store}
  */
  store: function() {
    return this.get('record').get('store');
  }.property('record').cacheable(),

  /**
    The storeKey for the parent record of this many array.  Editing this
    array will place the parent record into a READY_DIRTY state.

    @property {Number}
  */
  storeKey: function() {
    return this.get('record').get('storeKey');
  }.property('record').cacheable(),

  /**
    Returns the storeIds in read only mode.  Avoids modifying the record
    unnecessarily.

    @property {SC.Array}
  */
  readOnlyStoreIds: function() {
    return this.get('record').readAttribute(this.get('propertyName'));
  }.property(),

  /**
    Returns an editable array of storeIds.  Marks the owner records as
    modified.

    @property {SC.Array}
  */
  editableStoreIds: function() {
    var store    = this.get('store'),
        storeKey = this.get('storeKey'),
        pname    = this.get('propertyName'),
        ret, hash;

    ret = store.readEditableProperty(storeKey, pname);
    if (!ret) {
      hash = store.readEditableDataHash(storeKey);
      ret = hash[pname] = [];
    }

    if (ret !== this._prevStoreIds) this.recordPropertyDidChange();
    return ret ;
  }.property(),

  // ..........................................................
  // COMPUTED FROM OWNER
  //

  /**
    Computed from owner many attribute

    @property {Boolean}
  */
  isEditable: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('isEditable') : NO;
  }.property('manyAttribute').cacheable(),

  /**
    Computed from owner many attribute

    @property {String}
  */
  inverse: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('inverse') : null;
  }.property('manyAttribute').cacheable(),

  /**
    Computed from owner many attribute

    @property {Boolean}
  */
  isMaster: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('isMaster') : null;
  }.property("manyAttribute").cacheable(),

  /**
    Computed from owner many attribute

    @property {Array}
  */
  orderBy: function() {
    // NOTE: can't use get() b/c manyAttribute looks like a computed prop
    var attr = this.manyAttribute;
    return attr ? attr.get('orderBy') : null;
  }.property("manyAttribute").cacheable(),

  // ..........................................................
  // ARRAY PRIMITIVES
  //

  /** @private
    Returned length is a pass-through to the storeIds array.

    @property {Number}
  */
  length: function() {
    var storeIds = this.get('readOnlyStoreIds');
    return storeIds ? storeIds.get('length') : 0;
  }.property('readOnlyStoreIds'),

  /** @private
    Looks up the store id in the store ids array and materializes a
    records.
  */
  objectAt: function(idx) {
    var recs      = this._records,
        storeIds  = this.get('readOnlyStoreIds'),
        store     = this.get('store'),
        recordType = this.get('recordType'),
        storeKey, ret, storeId ;

    if (!storeIds || !store) return undefined; // nothing to do
    if (recs && (ret=recs[idx])) return ret ; // cached

    // not in cache, materialize
    if (!recs) this._records = recs = [] ; // create cache
    storeId = storeIds.objectAt(idx);
    if (storeId) {

      // if record is not loaded already, then ask the data source to
      // retrieve it
      storeKey = store.storeKeyFor(recordType, storeId);

      if (store.readStatus(storeKey) === SC.Record.EMPTY) {
        store.retrieveRecord(recordType, null, storeKey);
      }

      recs[idx] = ret = store.materializeRecord(storeKey);
    }
    return ret ;
  },

  /** @private
    Pass through to the underlying array.  The passed in objects must be
    records, which can be converted to storeIds.
  */
  replace: function(idx, amt, recs) {

    if (!this.get('isEditable')) {
      throw "%@.%@[] is not editable".fmt(this.get('record'), this.get('propertyName'));
    }

    var storeIds = this.get('editableStoreIds'),
        len      = recs ? (recs.get ? recs.get('length') : recs.length) : 0,
        record   = this.get('record'),
        pname    = this.get('propertyName'),
        i, keys, ids, toRemove, inverse, attr, inverseRecord;

    // map to store keys
    ids = [] ;
    for(i=0;i<len;i++) ids[i] = recs.objectAt(i).get('id');

    // if we have an inverse - collect the list of records we are about to
    // remove
    inverse = this.get('inverse');
    if (inverse && amt>0) {
      toRemove = SC.ManyArray._toRemove;
      if (toRemove) SC.ManyArray._toRemove = null; // reuse if possible
      else toRemove = [];

      for(i=0;i<amt;i++) toRemove[i] = this.objectAt(i);
    }

    // pass along - if allowed, this should trigger the content observer
    storeIds.replace(idx, amt, ids);

    // ok, notify records that were removed then added; this way reordered
    // objects are added and removed
    if (inverse) {

      // notive removals
      for(i=0;i<amt;i++) {
        inverseRecord = toRemove[i];
        attr = inverseRecord ? inverseRecord[inverse] : null;
        if (attr && attr.inverseDidRemoveRecord) {
          attr.inverseDidRemoveRecord(inverseRecord, inverse, record, pname);
        }
      }

      if (toRemove) {
        toRemove.length = 0; // cleanup
        if (!SC.ManyArray._toRemove) SC.ManyArray._toRemove = toRemove;
      }

      // notify additions
      for(i=0;i<len;i++) {
        inverseRecord = recs.objectAt(i);
        attr = inverseRecord ? inverseRecord[inverse] : null;
        if (attr && attr.inverseDidAddRecord) {
          attr.inverseDidAddRecord(inverseRecord, inverse, record, pname);
        }
      }

    }

    // only mark record dirty if there is no inverse or we are master
    if (record && (!inverse || this.get('isMaster'))) {
      record.recordDidChange(pname);
    }

    return this;
  },

  // ..........................................................
  // INVERSE SUPPORT
  //

  /**
    Called by the ManyAttribute whenever a record is removed on the inverse
    of the relationship.

    @param {SC.Record} inverseRecord the record that was removed
    @returns {SC.ManyArray} receiver
  */
  removeInverseRecord: function(inverseRecord) {

    if (!inverseRecord) return this; // nothing to do
    var id = inverseRecord.get('id'),
        storeIds = this.get('editableStoreIds'),
        idx      = (storeIds && id) ? storeIds.indexOf(id) : -1,
        record;

    if (idx >= 0) {
      storeIds.removeAt(idx);
      if (this.get('isMaster') && (record = this.get('record'))) {
        record.recordDidChange(this.get('propertyName'));
      }
    }

    return this;
  },

  /**
    Called by the ManyAttribute whenever a record is added on the inverse
    of the relationship.

    @param {SC.Record} record the record this array is a part of
    @param {String} key the key this array represents
    @param {SC.Record} inverseRecord the record that was removed
    @param {String} inverseKey the name of inverse that was changed
    @returns {SC.ManyArray} receiver
  */
  addInverseRecord: function(inverseRecord) {

    if (!inverseRecord) return this;
    var id = inverseRecord.get('id'),
        storeIds = this.get('editableStoreIds'),
        orderBy  = this.get('orderBy'),
        len      = storeIds.get('length'),
        idx, record;

    // find idx to insert at.
    if (orderBy) {
      idx = this._findInsertionLocation(inverseRecord, 0, len, orderBy);
    } else idx = len;

    storeIds.insertAt(idx, inverseRecord.get('id'));
    if (this.get('isMaster') && (record = this.get('record'))) {
      record.recordDidChange(this.get('propertyName'));
    }

    return this;
  },

  // binary search to find insertion location
  _findInsertionLocation: function(rec, min, max, orderBy) {
    var idx   = min+Math.floor((max-min)/2),
        cur   = this.objectAt(idx),
        order = this._compare(rec, cur, orderBy);
    if (order < 0) {
      if (idx===0) return idx;
      else return this._findInsertionLocation(rec, 0, idx, orderBy);
    } else if (order > 0) {
      if (idx >= max) return idx;
      else return this._findInsertionLocation(rec, idx, max, orderBy);
    } else return idx;
  },

  _compare: function(a, b, orderBy) {
    var t = SC.typeOf(orderBy),
        ret, idx, len;

    if (t === SC.T_FUNCTION) ret = orderBy(a, b);
    else if (t === SC.T_STRING) ret = SC.compare(a,b);
    else {
      len = orderBy.get('length');
      ret = 0;
      for(idx=0;(ret===0) && (idx<len);idx++) ret = SC.compare(a,b);
    }

    return ret ;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  /** @private
    Invoked whenever the storeIds array changes.  Observes changes.
  */
  recordPropertyDidChange: function(keys) {

    if (keys && !keys.contains(this.get('propertyName'))) return this;

    var storeIds = this.get('readOnlyStoreIds');
    var prev = this._prevStoreIds, f = this._storeIdsContentDidChange;

    if (storeIds === prev) return this; // nothing to do

    if (prev) prev.removeObserver('[]', this, f);
    this._prevStoreIds = storeIds;
    if (storeIds) storeIds.addObserver('[]', this, f);

    var rev = (storeIds) ? storeIds.propertyRevision : -1 ;
    this._storeIdsContentDidChange(storeIds, '[]', storeIds, rev);

  },

  /** @private
    Invoked whenever the content of the storeIds array changes.  This will
    dump any cached record lookup and then notify that the enumerable content
    has changed.
  */
  _storeIdsContentDidChange: function(target, key, value, rev) {
    this._records = null ; // clear cache
    this.enumerableContentDidChange();
  },

  /** @private */
  unknownProperty: function(key, value) {
    var ret = this.reducedProperty(key, value);
    return ret === undefined ? sc_super() : ret;
  },

  /** @private */
  init: function() {
    sc_super();
    this.recordPropertyDidChange();
  }

}) ;<|endoftext|>


<commit_before>
// Google Map
var map;

// markers for map
var markers = [];

// info window
var info = new google.maps.InfoWindow();

// execute when the DOM is fully loaded
$(function() {

    // styles for map
    // https://developers.google.com/maps/documentation/javascript/styling
    var styles = [

        // hide Google's labels
        {
            featureType: "all",
            elementType: "labels",
            stylers: [
                {visibility: "on"}
            ]
        },

        // hide roads
        {
            featureType: "road",
            elementType: "geometry",
            stylers: [
                {visibility: "on"}
            ]
        }

    ];

    // options for map
    // https://developers.google.com/maps/documentation/javascript/reference#MapOptions
    var options = {
        center: {lat: 39.8282, lng: -98.5795}, // Stanford, California
        disableDefaultUI: true,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        maxZoom: 14,
        panControl: true,
        styles: styles,
        zoom: 4,
        zoomControl: true
    };

    // get DOM node in which map will be instantiated
    var canvas = $("#map-canvas").get(0);

    // instantiate map
    map = new google.maps.Map(canvas, options);

    // configure UI once Google Map is idle (i.e., loaded)
    google.maps.event.addListenerOnce(map, "idle", configure);

});

/**
* Adds marker for college to map.
*/
function addMarker(college)
{
    // get latitude and longitude of college
    var myLatlng = new google.maps.LatLng(college["LATITUDE"], college["LONGITUDE"]);

    // make markers
    var marker = new google.maps.Marker({
        position: myLatlng,
        // label: college["INSTNM"]
    });

    // add markers to list markers
    markers.push(marker);

    var info = "
" +college["INSTNM"]+ "
";

    // marker.addListener("click", function(){
    //     showInfo(marker, info)
    //     console.log("hello world")
    // });
    // listen for click event
    google.maps.event.addListener(marker, 'click', function() {

        // make an html string for each article and link
        var info = "
" +college["INSTNM"]+ "
";
        // var info = "hello, world!"
        // make window display html articles (hyperlinked)
        showInfo(marker, info);
    });

    // render map with markers
    marker.setMap(map);
};

/**
 * Configures application.
 */
function configure()
{
    // update UI after map has been dragged
    google.maps.event.addListener(map, "dragend", function() {

        // if info window isn't open
        // http://stackoverflow.com/a/12410385
        if (!info.getMap || !info.getMap())
        {
            update();
        }
    });

    // update UI after zoom level changes
    google.maps.event.addListener(map, "zoom_changed", function() {
        update();
    });

    // configure typeahead
    $("#q").typeahead({
        highlight: false,
        minLength: 1
    },
    {
        display: function(suggestion) { return null; },
        limit: 10,
        source: search,
        templates: {
            suggestion: Handlebars.compile(
                "
" +
                "{{place_name}}, {{admin_code1}}, {{postal_code}}" +
                "
"
            )
        }
    });

    // re-center map after place is selected from drop-down
    $("#q").on("typeahead:selected", function(eventObject, suggestion, name) {

        // set map's center
        map.setCenter({lat: parseFloat(suggestion.latitude), lng: parseFloat(suggestion.longitude)});
        map.setZoom(11);

        // update UI
        update();
    });

    // hide info window when text box has focus
    $("#q").focus(function(eventData) {
        info.close();
    });

    // re-enable ctrl- and right-clicking (and thus Inspect Element) on Google Map
    // https://chrome.google.com/webstore/detail/allow-right-click/hompjdfbfmmmgflfjdlnkohcplmboaeo?hl=en
    document.addEventListener("contextmenu", function(event) {
        event.returnValue = true;
        event.stopPropagation && event.stopPropagation();
        event.cancelBubble && event.cancelBubble();
    }, true);

    // update UI
    update();

    // give focus to text box
    $("#q").focus();
}

/**
* Removes markers from map.
*/
function removeMarkers()
{
    // iterate through markers and remove them from map
    for (marker in markers) {
        markers[marker].setMap(null);
    }

    // empty list of markers
    markers = [];
}

/**
 * Searches database for typeahead's suggestions.
 */
function search(query, syncResults, asyncResults)
{
    // get places matching query (asynchronously)
    var parameters = {
        q: query
    };
    $.getJSON(Flask.url_for("search"), parameters)
    .done(function(data, textStatus, jqXHR) {

        // call typeahead's callback with search results (i.e., places)
        asyncResults(data);
    })
    .fail(function(jqXHR, textStatus, errorThrown) {

        // log error to browser's console
        console.log(errorThrown.toString());

        // call typeahead's callback with no results
        asyncResults([]);
    });
}

/**
* Shows info window at marker with content.
*/
function showInfo(marker, content)
{
    // start div
    var div = "
";
    if (typeof(content) == "undefined")
    {
        // http://www.ajaxload.info/
        div += "";
    }
    else
    {
        div += content;
    }

    // end div
    div += "
";

    // set info window's content
    info.setContent(div);

//     // open info window (if not already open)
    info.open(map, marker);
}

/**
* Updates UI's markers.
*/
function update()
{
    // get map's bounds
    var bounds = map.getBounds();
    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();

    // get places within bounds (asynchronously)
    var parameters = {
        ne: ne.lat() + "," + ne.lng(),
        q: $("#q").val(),
        sw: sw.lat() + "," + sw.lng()
    };
    $.getJSON(Flask.url_for("update"), parameters)
    .done(function(data, textStatus, jqXHR) {

      // remove old markers from map
      removeMarkers();

      // add new markers to map
      for (var i = 0; i < data.length; i++)
      {
          addMarker(data[i]);
      }
    })
    .fail(function(jqXHR, textStatus, errorThrown) {

        // log error to browser's console
        console.log(errorThrown.toString());
    });
};<commit_msg>links on map work<commit_after>
// Google Map
var map;

// markers for map
var markers = [];

// info window
var info = new google.maps.InfoWindow();

// execute when the DOM is fully loaded
$(function() {

    // styles for map
    // https://developers.google.com/maps/documentation/javascript/styling
    var styles = [

        // hide Google's labels
        {
            featureType: "all",
            elementType: "labels",
            stylers: [
                {visibility: "on"}
            ]
        },

        // hide roads
        {
            featureType: "road",
            elementType: "geometry",
            stylers: [
                {visibility: "on"}
            ]
        }

    ];

    // options for map
    // https://developers.google.com/maps/documentation/javascript/reference#MapOptions
    var options = {
        center: {lat: 39.8282, lng: -98.5795}, // Stanford, California
        disableDefaultUI: true,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        maxZoom: 14,
        panControl: true,
        styles: styles,
        zoom: 4,
        zoomControl: true
    };

    // get DOM node in which map will be instantiated
    var canvas = $("#map-canvas").get(0);

    // instantiate map
    map = new google.maps.Map(canvas, options);

    // configure UI once Google Map is idle (i.e., loaded)
    google.maps.event.addListenerOnce(map, "idle", configure);

});

/**
* Adds marker for college to map.
*/
function addMarker(college)
{
    // get latitude and longitude of college
    var myLatlng = new google.maps.LatLng(college["LATITUDE"], college["LONGITUDE"]);

    // make markers
    var marker = new google.maps.Marker({
        position: myLatlng,
        // label: college["INSTNM"]
    });

    // add markers to list markers
    markers.push(marker);

    // var info = "
" +college["INSTNM"]+ "
";

    // marker.addListener("click", function(){
    //     showInfo(marker, info)
    //     console.log("hello world")
    // });
    // listen for click event
    google.maps.event.addListener(marker, 'click', function() {

        // make an html string for each article and link
        var info = "
" +college["INSTNM"]+ "
";
        console.log(info);
        // var info = "hello, world!"
        // make window display html articles (hyperlinked)
        showInfo(marker, info);
    });

    // render map with markers
    marker.setMap(map);
};

/**
 * Configures application.
 */
function configure()
{
    // update UI after map has been dragged
    google.maps.event.addListener(map, "dragend", function() {

        // if info window isn't open
        // http://stackoverflow.com/a/12410385
        if (!info.getMap || !info.getMap())
        {
            update();
        }
    });

    // update UI after zoom level changes
    google.maps.event.addListener(map, "zoom_changed", function() {
        update();
    });

    // configure typeahead
    $("#q").typeahead({
        highlight: false,
        minLength: 1
    },
    {
        display: function(suggestion) { return null; },
        limit: 10,
        source: search,
        templates: {
            suggestion: Handlebars.compile(
                "
" +
                "{{place_name}}, {{admin_code1}}, {{postal_code}}" +
                "
"
            )
        }
    });

    // re-center map after place is selected from drop-down
    $("#q").on("typeahead:selected", function(eventObject, suggestion, name) {

        // set map's center
        map.setCenter({lat: parseFloat(suggestion.latitude), lng: parseFloat(suggestion.longitude)});
        map.setZoom(11);

        // update UI
        update();
    });

    // hide info window when text box has focus
    $("#q").focus(function(eventData) {
        info.close();
    });

    // re-enable ctrl- and right-clicking (and thus Inspect Element) on Google Map
    // https://chrome.google.com/webstore/detail/allow-right-click/hompjdfbfmmmgflfjdlnkohcplmboaeo?hl=en
    document.addEventListener("contextmenu", function(event) {
        event.returnValue = true;
        event.stopPropagation && event.stopPropagation();
        event.cancelBubble && event.cancelBubble();
    }, true);

    // update UI
    update();

    // give focus to text box
    $("#q").focus();
}

/**
* Removes markers from map.
*/
function removeMarkers()
{
    // iterate through markers and remove them from map
    for (marker in markers) {
        markers[marker].setMap(null);
    }

    // empty list of markers
    markers = [];
}

/**
 * Searches database for typeahead's suggestions.
 */
function search(query, syncResults, asyncResults)
{
    // get places matching query (asynchronously)
    var parameters = {
        q: query
    };
    $.getJSON(Flask.url_for("search"), parameters)
    .done(function(data, textStatus, jqXHR) {

        // call typeahead's callback with search results (i.e., places)
        asyncResults(data);
    })
    .fail(function(jqXHR, textStatus, errorThrown) {

        // log error to browser's console
        console.log(errorThrown.toString());

        // call typeahead's callback with no results
        asyncResults([]);
    });
}

/**
* Shows info window at marker with content.
*/
function showInfo(marker, content)
{
    // start div
    var div = "
";
    if (typeof(content) == "undefined")
    {
        // http://www.ajaxload.info/
        div += "";
    }
    else
    {
        div += content;
    }

    // end div
    div += "
";

    // set info window's content
    info.setContent(div);

//     // open info window (if not already open)
    info.open(map, marker);
}

/**
* Updates UI's markers.
*/
function update()
{
    // get map's bounds
    var bounds = map.getBounds();
    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();

    // get places within bounds (asynchronously)
    var parameters = {
        ne: ne.lat() + "," + ne.lng(),
        q: $("#q").val(),
        sw: sw.lat() + "," + sw.lng()
    };
    $.getJSON(Flask.url_for("update"), parameters)
    .done(function(data, textStatus, jqXHR) {

      // remove old markers from map
      removeMarkers();

      // add new markers to map
      for (var i = 0; i < data.length; i++)
      {
          addMarker(data[i]);
      }
    })
    .fail(function(jqXHR, textStatus, errorThrown) {

        // log error to browser's console
        console.log(errorThrown.toString());
    });
};<|endoftext|>


<commit_before>const fs = require('fs-extra');
const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');

exports.onCreateNode = ({ node, getNode, boundActionCreators }) => {
  const { createNodeField } = boundActionCreators;

  if (node.internal.type === 'MarkdownRemark') {
    const slug = createFilePath({ node, getNode, basePath: 'pages' });
    createNodeField({
      node,
      name: 'slug',
      value: slug,
    });
  }
};

exports.onPostBootstrap = () => {
  console.log('Copying locales'); // eslint-disable-line no-console
  fs.copySync(path.join(__dirname, '/src/locales'), path.join(__dirname, '/public/locales'));
};

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators;

  return new Promise((resolve) => {
    graphql(`
      {
        allMarkdownRemark {
          edges {
            node {
              fields {
                slug
              }
            }
          }
        }
      }
    `).then(({ data }) => {
      data.allMarkdownRemark.edges.forEach(({ node }) => {
        createPage({
          path: node.fields.slug,
          component: path.resolve('./src/templates/blog-post.jsx'),
          context: {
            // Data passed to context is available in page queries as GraphQL variables
            slug: node.fields.slug,
          },
        });
      });

      resolve();
    });
  });
};
<commit_msg>Fix broken locale copying mechanism<commit_after>const fs = require('fs-extra');
const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');

exports.onCreateNode = ({ node, getNode, boundActionCreators }) => {
  const { createNodeField } = boundActionCreators;

  if (node.internal.type === 'MarkdownRemark') {
    const slug = createFilePath({ node, getNode, basePath: 'pages' });
    createNodeField({
      node,
      name: 'slug',
      value: slug,
    });
  }
};

exports.onPreBootstrap = () => {
  console.log('Copying locales'); // eslint-disable-line no-console
  fs.copySync(path.join(__dirname, '/src/locales'), path.join(__dirname, '/public/locales'));
};

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators;

  return new Promise((resolve) => {
    graphql(`
      {
        allMarkdownRemark {
          edges {
            node {
              fields {
                slug
              }
            }
          }
        }
      }
    `).then(({ data }) => {
      data.allMarkdownRemark.edges.forEach(({ node }) => {
        createPage({
          path: node.fields.slug,
          component: path.resolve('./src/templates/blog-post.jsx'),
          context: {
            // Data passed to context is available in page queries as GraphQL variables
            slug: node.fields.slug,
          },
        });
      });

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


<commit_before>Hero = function(game, characterName, team, isLocal, initX, initY, textureName) {
    Phaser.Sprite.call(this, game, initX, initY, textureName);

    this.receivedServerData = false;

    this.game = game;
    this.characterName = characterName;
    this.team = team;
    this.isLocal = isLocal;
    this.isAttacking = false;
    this.selectedSpellContainer = $('.js-selected-spell');

    // If local player, listen for keys.
    if (this.isLocal) {
        //game.input.keyboard.onDownCallback(this.handleKeyDown.bind(this));
        this.moveDirectionKeys = {
            up: this.game.input.keyboard.addKey(Phaser.Keyboard.W),
            left: this.game.input.keyboard.addKey(Phaser.Keyboard.A),
            down: this.game.input.keyboard.addKey(Phaser.Keyboard.S),
            right: this.game.input.keyboard.addKey(Phaser.Keyboard.D)
        };

        this.actionDirectionKeys = this.game.input.keyboard.createCursorKeys();

        if(this.characterName === 'jbateson') {
            // Joe needs the Q key to change spells because he's a special snowflake.
            this.actionSwitchKey = this.game.input.keyboard.addKey(Phaser.Keyboard.Q);
        } else {
            this.actionSwitchKey = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
        }

        // Track all keys that were pressed between frames to prevent key presses being lost.
        // Make a list of ALL KEYS and gives them each a callback when pressed for any duration
        // which adds them to this.pressedKeys, a list of all keys pressed between frames.
        this.pressedKeys = [];
        this.allKeys = [];
        for (var key in this.moveDirectionKeys) {
            this.allKeys.push(this.moveDirectionKeys[key]);
        }
        for (var key in this.actionDirectionKeys) {
            this.allKeys.push(this.actionDirectionKeys[key]);
        }

        var addPressedKey = function(event) {
            this.pressedKeys.push(event);
        }.bind(this);

        for(var i = 0; i < this.allKeys.length; i++) {
            this.allKeys[i].onDown.add(addPressedKey)
        }
    }

    this.lastPos = {
        x: -1,
        y: -1
    }

    this.vel = {
        x: 0,
        y: 0
    }

    this.health = this.maxHealth;
    this.hitFlashFrame = 0;
    this.maxHitFlashFrame = 15;
    this.actionCooldown = 0;
    this.moveDelay = 0;
    this.currentAction = 1;
    this.lastDeath = -1;

    this.animations.add('UP', [9, 10, 11]);
    this.animations.add('DOWN', [0, 1, 2]);
    this.animations.add('LEFT', [3, 4, 5]);
    this.animations.add('RIGHT', [6, 7, 8]);
    this.animations.play('DOWN', 5, true);
    this.anchor.set(0.5, 0.5);

    // Init collision detection stuff
    game.add.existing(this);

    if (this.team === 'red') {
        this.nameStyleFillDefault = '#FF0000';
    } else {
        this.nameStyleFillDefault = '#0000FF';
    }
    this.nameStyle = {
        font: "12px Arial",
        align: "center",
        fill: this.nameStyleFillDefault
    };

    // Name text
    this.nameText = game.add.text(this.x - 8, this.y + 8, this.characterName, this.nameStyle);
    this.nameText.x = this.x - this.nameText.width / 2;

    // Health bar
    this.healthBar = new HealthBar(game, this.x - 12, this.y - 16, 24);

    game.physics.enable(this, Phaser.Physics.ARCADE);

    this.body.collideWorldBounds = true;

    this.bringToTop();
};

Hero.prototype = Object.create(Phaser.Sprite.prototype);
Hero.prototype.constructor = Hero;

Hero.prototype.updateTo = function() {
    if (this.moveDelay === 0) {
        var moveMessage = {
            type: 'FE_HERO_MOVE',
            content: {
                name: this.characterName,
                speed: 8,
                direction: ''
            }
        };

        if (this.isKeyDown(this.moveDirectionKeys.left)) {
            moveMessage.content.direction = 'LEFT'
            this.animations.play('LEFT', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.right)) {
            moveMessage.content.direction = 'RIGHT'
            this.animations.play('RIGHT', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.up)) {
            moveMessage.content.direction = 'UP'
            this.animations.play('UP', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.down)) {
            moveMessage.content.direction = 'DOWN'
            this.animations.play('DOWN', 5, true);
        } else {
            this.animations.stop();
        }

        if (moveMessage.content.direction !== '') {
            socket.send(JSON.stringify(moveMessage));
        }

        this.moveDelay = this.maxMoveDelay;
    } else {
        this.moveDelay--;
    }

    if (this.isKeyDown(this.actionSwitchKey) && this.actionSwitchKey.duration < 0.015) {
        if (this.currentAction === 1) {
            this.currentAction = 2;
        } else {
            this.currentAction = 1;
        }
        this.isAttacking = false;
    }

    this.selectedSpellContainer.html(this.actions[this.currentAction].display_name);

    var actionMessage = {
        type: 'FE_HERO_SPELL',
        content: {
            position_x: Math.floor(this.x),
            position_y: Math.floor(this.y),
            spell_type: this.actions[this.currentAction].id,
            direction: ''
        }
    }

    if (this.isKeyDown(this.actionDirectionKeys.left)) {
        actionMessage.content.direction = 'LEFT'
    } else if (this.isKeyDown(this.actionDirectionKeys.right)) {
        actionMessage.content.direction = 'RIGHT'
    } else if (this.isKeyDown(this.actionDirectionKeys.up)) {
        actionMessage.content.direction = 'UP'
    } else if (this.isKeyDown(this.actionDirectionKeys.down)) {
        actionMessage.content.direction = 'DOWN'
    }

    if (!this.isAttacking && actionMessage.content.direction !== '') {
        this.setCoolDown(this.actions[this.currentAction].id);
        socket.send(JSON.stringify(actionMessage));
    }

    //this.pressedKeys = [];
}

Hero.prototype.updateHitFlash = function() {
    if(this.hitFlashFrame > 0) {
        this.alpha = Math.floor(this.hitFlashFrame/2) % 2;
        this.hitFlashFrame--;
    } else {
        this.alpha = 1;
    }
}

Hero.prototype.isKeyDown = function(key) {
    var keyPressed = false;
    for (var i = 0; i < this.pressedKeys.length; i++) {
        var pressedKey = this.pressedKeys[i];
        if(key.keyCode === pressedKey.keyCode) {
            keyPressed = true;
            // Tried to to this.pressedKeys = [] at the end of updateTo but it caused
            // this.pressedKeys to be emptied at the wrong time. This is an ugly hack
            // but at least it works...
            this.pressedKeys.splice(i,1);
            break;
        }
    }
    return key.isDown || keyPressed;
}

//OVERRIDE THIS ONE
Hero.prototype.setCoolDown = function(){
}

Hero.prototype.destroyHero = function() {
    this.nameText.destroy();
    this.healthBar.destroy();
    this.destroy();
}

Hero.prototype.receiveMessage = function(message) {
    var newX = message['position']['x'] * 16;
    var newY = message['position']['y'] * 16;
    if(!this.receivedServerData) {
        this.x = newX;
        this.y = newY;

        this.nameText.x = newX - this.nameText.width / 2;
        this.nameText.y = newY + 8;

        this.healthBar.x = newX - 12;
        this.healthBar.y = newY - 12;

        this.receivedServerData = true;
    } else {
        var tweenDelay = 1000/60 * this.maxMoveDelay;
        var tween = game.add.tween(this).to({
            x : newX,
            y : newY
        }, tweenDelay).start();

        var nameTextTween = game.add.tween(this.nameText).to({
            x : newX - this.nameText.width / 2,
            y : newY + 8
        }, tweenDelay).start();

        var healthBarTween = game.add.tween(this.healthBar).to({
            x : newX - 12,
            y : newY - 12
        }, tweenDelay).start();
    }

    // Check if the player just died.
    if(this.lastDeath < 0) {
        this.lastDeath = message['last_death'];
    } else if(message['last_death'] > this.lastDeath) {
        // Player is dead. Great sadness.
        var bloodCenter = new Blood(game, this.x - 8, this.y - 8);
        var bloodLeft = new Blood(game, this.x - 24, this.y - 8);
        var bloodRight = new Blood(game, this.x + 8, this.y - 8);
        var bloodTop = new Blood(game, this.x - 8, this.y - 24);
        var bloodBottom = new Blood(game, this.x - 8, this.y + 8);
        this.lastDeath = message['last_death'];
    }

    this.lastPos.x = newX;
    this.lastPos.y = newY;

    if (this.health > message['hp']) {
        this.hitFlashFrame = this.maxHitFlashFrame;
    }
    this.health = message['hp'];
    this.maxHealth = message['MAX_HP'];
    this.healthBar.updateHealthBar(this.health, this.maxHealth);
}

Hero.prototype.update_smooth = function() {
    if (this.moveDelay === 0) {
        this.vel.x = 0;
        this.vel.y = 0;

        if (this.moveDirectionKeys.left.isDown) {
            this.vel.x = -8;
        } else if (this.moveDirectionKeys.right.isDown) {
            this.vel.x = 8;
        } else if (this.moveDirectionKeys.up.isDown) {
            this.vel.y = -8;
        } else if (this.moveDirectionKeys.down.isDown) {
            this.vel.y = 8;
        }

        this.x += this.vel.x;
        this.y += this.vel.y;

        // Check if there's been a change
        if (this.x !== this.lastPos.x || this.y !== this.lastPos.y) {
            /*this.messageCallback({
             type: 'FE_HERO_POSITION',
             content: {
             name: this.characterName,
             x: this.pos.x,
             y: this.pos.y
             }
             })*/

            this.moveDelay = this.maxMoveDelay;

            this.lastPos.x = this.x;
            this.lastPos.y = this.y;
        }
    } else {
        this.moveDelay--;
    }
}<commit_msg>When player sends spells, rounds to nearest tile, not pixels.<commit_after>Hero = function(game, characterName, team, isLocal, initX, initY, textureName) {
    Phaser.Sprite.call(this, game, initX, initY, textureName);

    this.receivedServerData = false;

    this.game = game;
    this.characterName = characterName;
    this.team = team;
    this.isLocal = isLocal;
    this.isAttacking = false;
    this.selectedSpellContainer = $('.js-selected-spell');

    // If local player, listen for keys.
    if (this.isLocal) {
        //game.input.keyboard.onDownCallback(this.handleKeyDown.bind(this));
        this.moveDirectionKeys = {
            up: this.game.input.keyboard.addKey(Phaser.Keyboard.W),
            left: this.game.input.keyboard.addKey(Phaser.Keyboard.A),
            down: this.game.input.keyboard.addKey(Phaser.Keyboard.S),
            right: this.game.input.keyboard.addKey(Phaser.Keyboard.D)
        };

        this.actionDirectionKeys = this.game.input.keyboard.createCursorKeys();

        if(this.characterName === 'jbateson') {
            // Joe needs the Q key to change spells because he's a special snowflake.
            this.actionSwitchKey = this.game.input.keyboard.addKey(Phaser.Keyboard.Q);
        } else {
            this.actionSwitchKey = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
        }

        // Track all keys that were pressed between frames to prevent key presses being lost.
        // Make a list of ALL KEYS and gives them each a callback when pressed for any duration
        // which adds them to this.pressedKeys, a list of all keys pressed between frames.
        this.pressedKeys = [];
        this.allKeys = [];
        for (var key in this.moveDirectionKeys) {
            this.allKeys.push(this.moveDirectionKeys[key]);
        }
        for (var key in this.actionDirectionKeys) {
            this.allKeys.push(this.actionDirectionKeys[key]);
        }

        var addPressedKey = function(event) {
            this.pressedKeys.push(event);
        }.bind(this);

        for(var i = 0; i < this.allKeys.length; i++) {
            this.allKeys[i].onDown.add(addPressedKey)
        }
    }

    this.lastPos = {
        x: -1,
        y: -1
    }

    this.vel = {
        x: 0,
        y: 0
    }

    this.health = this.maxHealth;
    this.hitFlashFrame = 0;
    this.maxHitFlashFrame = 15;
    this.actionCooldown = 0;
    this.moveDelay = 0;
    this.currentAction = 1;
    this.lastDeath = -1;

    this.animations.add('UP', [9, 10, 11]);
    this.animations.add('DOWN', [0, 1, 2]);
    this.animations.add('LEFT', [3, 4, 5]);
    this.animations.add('RIGHT', [6, 7, 8]);
    this.animations.play('DOWN', 5, true);
    this.anchor.set(0.5, 0.5);

    // Init collision detection stuff
    game.add.existing(this);

    if (this.team === 'red') {
        this.nameStyleFillDefault = '#FF0000';
    } else {
        this.nameStyleFillDefault = '#0000FF';
    }
    this.nameStyle = {
        font: "12px Arial",
        align: "center",
        fill: this.nameStyleFillDefault
    };

    // Name text
    this.nameText = game.add.text(this.x - 8, this.y + 8, this.characterName, this.nameStyle);
    this.nameText.x = this.x - this.nameText.width / 2;

    // Health bar
    this.healthBar = new HealthBar(game, this.x - 12, this.y - 16, 24);

    game.physics.enable(this, Phaser.Physics.ARCADE);

    this.body.collideWorldBounds = true;

    this.bringToTop();
};

Hero.prototype = Object.create(Phaser.Sprite.prototype);
Hero.prototype.constructor = Hero;

Hero.prototype.updateTo = function() {
    if (this.moveDelay === 0) {
        var moveMessage = {
            type: 'FE_HERO_MOVE',
            content: {
                name: this.characterName,
                speed: 8,
                direction: ''
            }
        };

        if (this.isKeyDown(this.moveDirectionKeys.left)) {
            moveMessage.content.direction = 'LEFT'
            this.animations.play('LEFT', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.right)) {
            moveMessage.content.direction = 'RIGHT'
            this.animations.play('RIGHT', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.up)) {
            moveMessage.content.direction = 'UP'
            this.animations.play('UP', 5, true);
        } else if (this.isKeyDown(this.moveDirectionKeys.down)) {
            moveMessage.content.direction = 'DOWN'
            this.animations.play('DOWN', 5, true);
        } else {
            this.animations.stop();
        }

        if (moveMessage.content.direction !== '') {
            socket.send(JSON.stringify(moveMessage));
        }

        this.moveDelay = this.maxMoveDelay;
    } else {
        this.moveDelay--;
    }

    if (this.isKeyDown(this.actionSwitchKey) && this.actionSwitchKey.duration < 0.015) {
        if (this.currentAction === 1) {
            this.currentAction = 2;
        } else {
            this.currentAction = 1;
        }
        this.isAttacking = false;
    }

    this.selectedSpellContainer.html(this.actions[this.currentAction].display_name);

    var actionMessage = {
        type: 'FE_HERO_SPELL',
        content: {
            position_x: Math.round(this.x/16),
            position_y: Math.round(this.y/16),
            spell_type: this.actions[this.currentAction].id,
            direction: ''
        }
    }

    if (this.isKeyDown(this.actionDirectionKeys.left)) {
        actionMessage.content.direction = 'LEFT'
    } else if (this.isKeyDown(this.actionDirectionKeys.right)) {
        actionMessage.content.direction = 'RIGHT'
    } else if (this.isKeyDown(this.actionDirectionKeys.up)) {
        actionMessage.content.direction = 'UP'
    } else if (this.isKeyDown(this.actionDirectionKeys.down)) {
        actionMessage.content.direction = 'DOWN'
    }

    if (!this.isAttacking && actionMessage.content.direction !== '') {
        this.setCoolDown(this.actions[this.currentAction].id);
        socket.send(JSON.stringify(actionMessage));
    }

    //this.pressedKeys = [];
}

Hero.prototype.updateHitFlash = function() {
    if(this.hitFlashFrame > 0) {
        this.alpha = Math.floor(this.hitFlashFrame/2) % 2;
        this.hitFlashFrame--;
    } else {
        this.alpha = 1;
    }
}

Hero.prototype.isKeyDown = function(key) {
    var keyPressed = false;
    for (var i = 0; i < this.pressedKeys.length; i++) {
        var pressedKey = this.pressedKeys[i];
        if(key.keyCode === pressedKey.keyCode) {
            keyPressed = true;
            // Tried to to this.pressedKeys = [] at the end of updateTo but it caused
            // this.pressedKeys to be emptied at the wrong time. This is an ugly hack
            // but at least it works...
            this.pressedKeys.splice(i,1);
            break;
        }
    }
    return key.isDown || keyPressed;
}

//OVERRIDE THIS ONE
Hero.prototype.setCoolDown = function(){
}

Hero.prototype.destroyHero = function() {
    this.nameText.destroy();
    this.healthBar.destroy();
    this.destroy();
}

Hero.prototype.receiveMessage = function(message) {
    var newX = message['position']['x'] * 16;
    var newY = message['position']['y'] * 16;
    if(!this.receivedServerData) {
        this.x = newX;
        this.y = newY;

        this.nameText.x = newX - this.nameText.width / 2;
        this.nameText.y = newY + 8;

        this.healthBar.x = newX - 12;
        this.healthBar.y = newY - 12;

        this.receivedServerData = true;
    } else {
        var tweenDelay = 1000/60 * this.maxMoveDelay;
        var tween = game.add.tween(this).to({
            x : newX,
            y : newY
        }, tweenDelay).start();

        var nameTextTween = game.add.tween(this.nameText).to({
            x : newX - this.nameText.width / 2,
            y : newY + 8
        }, tweenDelay).start();

        var healthBarTween = game.add.tween(this.healthBar).to({
            x : newX - 12,
            y : newY - 12
        }, tweenDelay).start();
    }

    // Check if the player just died.
    if(this.lastDeath < 0) {
        this.lastDeath = message['last_death'];
    } else if(message['last_death'] > this.lastDeath) {
        // Player is dead. Great sadness.
        var bloodCenter = new Blood(game, this.x - 8, this.y - 8);
        var bloodLeft = new Blood(game, this.x - 24, this.y - 8);
        var bloodRight = new Blood(game, this.x + 8, this.y - 8);
        var bloodTop = new Blood(game, this.x - 8, this.y - 24);
        var bloodBottom = new Blood(game, this.x - 8, this.y + 8);
        this.lastDeath = message['last_death'];
    }

    this.lastPos.x = newX;
    this.lastPos.y = newY;

    if (this.health > message['hp']) {
        this.hitFlashFrame = this.maxHitFlashFrame;
    }
    this.health = message['hp'];
    this.maxHealth = message['MAX_HP'];
    this.healthBar.updateHealthBar(this.health, this.maxHealth);
}

Hero.prototype.update_smooth = function() {
    if (this.moveDelay === 0) {
        this.vel.x = 0;
        this.vel.y = 0;

        if (this.moveDirectionKeys.left.isDown) {
            this.vel.x = -8;
        } else if (this.moveDirectionKeys.right.isDown) {
            this.vel.x = 8;
        } else if (this.moveDirectionKeys.up.isDown) {
            this.vel.y = -8;
        } else if (this.moveDirectionKeys.down.isDown) {
            this.vel.y = 8;
        }

        this.x += this.vel.x;
        this.y += this.vel.y;

        // Check if there's been a change
        if (this.x !== this.lastPos.x || this.y !== this.lastPos.y) {
            /*this.messageCallback({
             type: 'FE_HERO_POSITION',
             content: {
             name: this.characterName,
             x: this.pos.x,
             y: this.pos.y
             }
             })*/

            this.moveDelay = this.maxMoveDelay;

            this.lastPos.x = this.x;
            this.lastPos.y = this.y;
        }
    } else {
        this.moveDelay--;
    }
}<|endoftext|>


<commit_before><commit_msg>test deploy<commit_after><|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

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

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

var BLOCK_REGEXP = /^([^_\-\s]+)/g;
var ELEMENT_REGEXP = /__([^_\-\s]+)/g;
var MODIFIER_REGEXP = /\-\-([^_\-\s]+)/g;

var Bem = (function () {
  function Bem(_ref) {
    var block = _ref.block;
    var elements = _ref.elements;
    var modifiers = _ref.modifiers;

    _classCallCheck(this, Bem);

    this.block = block;
    this.elements = elements;
    this.modifiers = modifiers;
  }

  _createClass(Bem, [{
    key: 'append',
    value: function append(_ref2) {
      var _ref2$elements = _ref2.elements;
      var elements = _ref2$elements === undefined ? [] : _ref2$elements;
      var _ref2$modifiers = _ref2.modifiers;
      var modifiers = _ref2$modifiers === undefined ? [] : _ref2$modifiers;

      return new Bem({
        block: this.block,
        elements: this.elements.concat(elements),
        modifiers: this.modifiers.concat(modifiers)
      });
    }
  }, {
    key: 'toString',
    value: function toString() {
      var elementsAttached = this.elements.reduce(function (prev, element) {
        return prev.concat(['__' + element]);
      }, [this.block]).join('');

      var modifiersAttached = this.modifiers.reduce(function (prev, modifier) {
        return prev.concat([elementsAttached + '--' + modifier]);
      }, [elementsAttached]).join(' ');

      return modifiersAttached;
    }
  }], [{
    key: 'fromClassName',
    value: function fromClassName(className) {
      var block = extract(BLOCK_REGEXP, className)[0];
      var elements = extract(ELEMENT_REGEXP, className);
      var modifiers = extract(MODIFIER_REGEXP, className);

      return new Bem({ block: block, elements: elements, modifiers: modifiers });
    }
  }]);

  return Bem;
})();

var generateBuilder = function generateBuilder() {
  for (var _len = arguments.length, classNames = Array(_len), _key = 0; _key < _len; _key++) {
    classNames[_key] = arguments[_key];
  }

  var bems = classNames.filter(function (className) {
    return typeof className === 'string';
  }).reduce(function (prev, className) {
    return prev.concat(className.split(' '));
  }, []).filter(function (className) {
    return className.length > 0;
  }).map(function (className) {
    return Bem.fromClassName(className);
  });

  var builder = function builder(elements, modifiers) {
    elements = elements || '';
    modifiers = modifiers || {};

    if (typeof elements !== 'string') {
      throw new TypeError('elements expect a string or null.');
    }
    if (Object.prototype.toString.call(modifiers) !== '[object Object]') {
      throw new TypeError('modifiers expect a plain object or null.');
    }

    return bems.map(function (bem) {
      return bem.append({
        elements: parseElements(elements),
        modifiers: parseModifiers(modifiers)
      });
    }).map(function (bem) {
      return bem.toString();
    }).reduce(function (prev, className) {
      return prev.concat(className.split(' '));
    }, []).reduce(function (prev, className) {
      return prev.concat(prev.indexOf(className) > -1 ? [] : [className]);
    }, []).join(' ');
  };

  builder.clone = function () {
    var elements = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
    var modifiers = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

    var built = builder(elements, modifiers);

    return bemmer(built);
  };

  builder.bems = bems;

  return builder;
};

var extract = function extract(regexp, string) {
  var clonedRegexp = new RegExp(regexp);
  var extracted = [];

  while (true) {
    var result = clonedRegexp.exec(string);

    if (result === null) break;

    extracted.push(result[1]);
  }

  return extracted;
};

var parseElements = function parseElements(elements) {
  return elements.split('__').filter(function (element) {
    return element.length > 0;
  });
};

var parseModifiers = function parseModifiers(modifiers) {
  return Object.keys(modifiers).filter(function (modifier) {
    return !!modifiers[modifier];
  }).filter(function (modifier) {
    return modifier.length > 0;
  });
};

exports['default'] = generateBuilder;
module.exports = exports['default'];
<commit_msg>Re-build<commit_after>'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

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

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

var BLOCK_REGEXP = /^([^_\-\s]+)/g;
var ELEMENT_REGEXP = /__([^_\-\s]+)/g;
var MODIFIER_REGEXP = /\-\-([^_\-\s]+)/g;

var Bem = (function () {
  function Bem(_ref) {
    var block = _ref.block;
    var elements = _ref.elements;
    var modifiers = _ref.modifiers;

    _classCallCheck(this, Bem);

    this.block = block;
    this.elements = elements;
    this.modifiers = modifiers;
  }

  _createClass(Bem, [{
    key: 'append',
    value: function append(_ref2) {
      var _ref2$elements = _ref2.elements;
      var elements = _ref2$elements === undefined ? [] : _ref2$elements;
      var _ref2$modifiers = _ref2.modifiers;
      var modifiers = _ref2$modifiers === undefined ? [] : _ref2$modifiers;

      return new Bem({
        block: this.block,
        elements: this.elements.concat(elements),
        modifiers: this.modifiers.concat(modifiers)
      });
    }
  }, {
    key: 'toString',
    value: function toString() {
      var elementsAttached = this.elements.reduce(function (prev, element) {
        return prev.concat(['__' + element]);
      }, [this.block]).join('');

      var modifiersAttached = this.modifiers.reduce(function (prev, modifier) {
        return prev.concat([elementsAttached + '--' + modifier]);
      }, [elementsAttached]).join(' ');

      return modifiersAttached;
    }
  }], [{
    key: 'fromClassName',
    value: function fromClassName(className) {
      var block = extract(BLOCK_REGEXP, className)[0];
      var elements = extract(ELEMENT_REGEXP, className);
      var modifiers = extract(MODIFIER_REGEXP, className);

      return new Bem({ block: block, elements: elements, modifiers: modifiers });
    }
  }]);

  return Bem;
})();

var generateBuilder = function generateBuilder() {
  for (var _len = arguments.length, classNames = Array(_len), _key = 0; _key < _len; _key++) {
    classNames[_key] = arguments[_key];
  }

  var bems = classNames.filter(function (className) {
    return typeof className === 'string';
  }).reduce(function (prev, className) {
    return prev.concat(className.split(' '));
  }, []).filter(function (className) {
    return className.length > 0;
  }).map(function (className) {
    return Bem.fromClassName(className);
  });

  var builder = function builder(elements, modifiers) {
    elements = elements || '';
    modifiers = modifiers || {};

    if (typeof elements !== 'string') {
      throw new TypeError('elements expect a string or null.');
    }
    if (Object.prototype.toString.call(modifiers) !== '[object Object]') {
      throw new TypeError('modifiers expect a plain object or null.');
    }

    return bems.map(function (bem) {
      return bem.append({
        elements: parseElements(elements),
        modifiers: parseModifiers(modifiers)
      });
    }).map(function (bem) {
      return bem.toString();
    }).reduce(function (prev, className) {
      return prev.concat(className.split(' '));
    }, []).reduce(function (prev, className) {
      return prev.concat(prev.indexOf(className) > -1 ? [] : [className]);
    }, []).join(' ');
  };

  builder.bems = bems;

  return builder;
};

var extract = function extract(regexp, string) {
  var clonedRegexp = new RegExp(regexp);
  var extracted = [];

  while (true) {
    var result = clonedRegexp.exec(string);

    if (result === null) break;

    extracted.push(result[1]);
  }

  return extracted;
};

var parseElements = function parseElements(elements) {
  return elements.split('__').filter(function (element) {
    return element.length > 0;
  });
};

var parseModifiers = function parseModifiers(modifiers) {
  return Object.keys(modifiers).filter(function (modifier) {
    return !!modifiers[modifier];
  }).filter(function (modifier) {
    return modifier.length > 0;
  });
};

exports['default'] = generateBuilder;
module.exports = exports['default'];
<|endoftext|>


<commit_before><commit_msg>create our service tempplate in gatsby node<commit_after><|endoftext|>


<commit_before><commit_msg>Absolute Links<commit_after><|endoftext|>