<commit_before>/*
   GNU FM -- a free network service for sharing your music listening hab""s

   Copyright (C) 2009 Free Software Foundation, Inc

   @licstart  The following is the entire license notice for the
   JavaScript code in this page.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   @licend  The above is the entire license notice
   for the JavaScript code in this page.
*/

var scrobbled, now_playing;
var artist, album, track, trackpage, session_key, radio_key, ws_key;
var playlist = [], current_song = 0;
var player_ready = false;
var playable_songs = false;
var streaming = false;
var example_tags = "e.g. guitar, violin, female vocals, piano";

/**
 * Initialises the javascript player (player.tpl must also be included on the target page)
 *
 * @param array list A playlist in the form ([artist, album, track, trackurl, trackpage], [...]) or false if playing a radio stream
 * @param string sk Scrobble session key or false if the user isn't logged in
 * @param string rk Radio session key or false if streaming isn't required
 */
function playerInit(list, sk, ws, rk) {
	var audio = document.getElementById("audio");
	if (!list) {
		// We're playing a stream instead of a playlist
		streaming = true;
	}

	session_key = sk;
	ws_key = ws;
	radio_key = rk;

	if(typeof audio.duration == "undefined") {
		//Browser doesn't support <audio>
		if(streaming) {
			audio.replaceWith("
Sorry, you need a browser capable of using the HTML 5 <audio> element to enjoy the streaming service via the Javascript player.
");
		}
		return;
	}
	$("#fallbackembed").replaceWith(""); // Get rid of the fallback embed, otherwise some html5 browsers will play it in addition to the js player
	if (streaming) {
		// Get playlist from radio service
		getRadioPlaylist();
	} else {
		// Otherwise we have a static playlist
		playlist = list;
		playerReady();
	}
}

/**
 * Finishes the player initialisation when the playlist has been loaded
 */
function playerReady() {
	var audio = document.getElementById("audio");

	populatePlaylist();
	if(!playable_songs) {
		return;
	}
	loadSong(0);
	audio.pause();
	audio.addEventListener("ended", songEnded, false);
	updateProgress();
	$("#play").fadeTo("normal", 1);
	$("#pause").fadeTo("normal", 1);
	$("#pause").hide();
	$("#ban").fadeTo("normal", 1);
	$("#love").fadeTo("normal", 1);
	$("#open_tag").fadeTo("normal", 1);
	$("#progressbar").progressbar({ value: 0 });
	$("#player > #interface").show();
	$("#tags").placeholdr({placeholderText: example_tags});
	player_ready = true;
}

/**
 * Begins playback
 */
function play() {
	var audio = document.getElementById("audio");
	audio.play();
	if(!now_playing) {
		nowPlaying();
	}
	$("#play").hide();
	$("#pause").show();
	$("#seekforward").fadeTo("normal", 1);
	$("#seekback").fadeTo("normal", 1);
}

/**
 * Pauses playback
 */
function pause() {
	var audio = document.getElementById("audio");
	audio.pause();
	$("#play").show();
	$("#pause").hide();
	$("#seekforward").fadeTo("normal", 0.5);
	$("#seekback").fadeTo("normal", 0.5);
}

/**
 * Seeks backwards 10 seconds in the current song
 */
function seekBack() {
	try {
		var audio = document.getElementById("audio");
		audio.currentTime = audio.currentTime - 10;
	} catch (e) {}
}

/**
 * Seeks forwards 10 seconds in the current song
 */
function seekForward() {
	try {
		var audio = document.getElementById("audio");
		audio.currentTime = audio.currentTime + 10;
	} catch (e) {}
}

/**
 * Updates the progress bar every 900 milliseconds
 */
function updateProgress() {
	var audio = document.getElementById("audio");
	if (audio.duration > 0) {
		$("#progressbar").progressbar('option', 'value', (audio.currentTime / audio.duration) * 100);
		$("#duration").text(friendlyTime(audio.duration));
	} else {
		$("#duration").text(friendlyTime(0));
	}
	if (!scrobbled && audio.currentTime > audio.duration / 2) {
		scrobble();
	}
	$("#currenttime").text(friendlyTime(audio.currentTime));
	setTimeout("updateProgress()", 900)
}

/**
 * Called automatically when a song finished. Loads the next song if there is one
 */
function songEnded() {
	var audio = document.getElementById("audio");
	if(current_song == playlist.length - 1) {
		pause();
	} else {
		loadSong(current_song+1);
		play();
	}
}

/**
 * Outputs the HTML playlist
 */
function populatePlaylist() {
	var i, url;
	//Clear the list
	$("#playlist > #songs").text("");
	for(i = 0; i < playlist.length; i++) {
		url = playlist[i]["url"];
		// Remove non-streamable tracks
		if (url == "") {
			playlist.pop(song); // hur, pop song.
		} else {
			playable_songs = true;
		}
		$("#playlist > #songs").append("
" + playlist[i]["artist"] + " - " + playlist[i]["track"] + "
");
	}
	$("#song-" + current_song).css({fontWeight : "bold"});
}

/**
 * Shows/Hides the HTML playlist display
 */
function togglePlaylist() {
	$("#playlist").toggle(1000);
	$("#showplaylist").toggle();
	$("#hideplaylist").toggle();
}

/**
 * Submits a scrobble for the current song if a scrobble session key has been
 * provided. Makes use of a simple proxy to support installations where the
 * gnukebox installation is at a different domain/sub-domain to the nixtape
 * installation.
 */
function scrobble() {
	var timestamp;
	scrobbled = true;
	if(!session_key) {
		//Not authenticated
		return;
	}
	timestamp = Math.round(new Date().getTime() / 1000);
	$.post("/scrobble-proxy.php?method=scrobble", { "a[0]" : artist, "b[0]" : album, "t[0]" : track, "i[0]" : timestamp, "s" : session_key },
		      	function(data){
				if(data.substring(0, 2) == "OK") {
					$("#scrobbled").text("Scrobbled");
					$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
				} else {
					$("#scrobbled").text(data);
					$("#scrobbled").fadeIn(1000);
				}
		      	}, "text");
}

/**
 * Submits 'now playing' data to the gnukebox server. Like scrobble() this
 * makes use of a proxy.
 */
function nowPlaying() {
	var timestamp;
	var audio = document.getElementById("audio");
	now_playing = true;
	if(!session_key) {
		//Not authenticated
		return;
	}
	timestamp = Math.round(new Date().getTime() / 1000);
	$.post("/scrobble-proxy.php?method=nowplaying", { "a" : artist, "b" : album, "t" : track, "l" : audio.duration, "s" : session_key}, function(data) {}, "text");
}

/**
 * Loads a song and beings playing it.
 *
 * @param int song The song number in the playlist that should be played
 */
function playSong(song) {
	var audio = document.getElementById("audio");
	loadSong(song);
	play();
}

/**
 * Loads a song
 *
 * @param int song The song number in the playlist that should be loaded
 */
function loadSong(song) {
	var url = playlist[song]["url"];
	var audio = document.getElementById("audio");
	artist = playlist[song]["artist"];
	album = playlist[song]["album"];
	track = playlist[song]["track"];
	trackpage = playlist[song]["trackpage"];

	// Highlight current song in the playlist
	$("#song-" + current_song).css({fontWeight : "normal"});
	$("#song-" + song).css({fontWeight : "bold"});

	current_song = song;
	scrobbled = false;
	now_playing = false;
	audio.src = url;
	audio.load();

	if(streaming && current_song > playlist.length - 3) {
		//Update the playlist before the user reaches the end
		getRadioPlaylist();
	}

	if(current_song > 0) {
		$("#skipback").fadeTo("normal", 1.0);
	} else {
		$("#skipback").fadeTo("normal", 0.5);
	}

	if(current_song < playlist.length - 1) {
		$("#skipforward").fadeTo("normal", 1.0);
	} else {
		$("#skipforward").fadeTo("normal", 0.5);
	}

	$("#trackinfo > #artistname").text(artist);
	$("#trackinfo > #trackname").text(track);
	$("#ban").fadeTo("normal", 1);
	$("#love").fadeTo("normal", 1);

	if($("#flattrstream")) {
		$.getJSON('/2.0/', {'method' : 'artist.getflattr', 'artist' : artist, 'format' : 'json'}, updateFlattr);
	}
}

function updateFlattr(data) {
	var flattr_uid = data.flattr.flattr_uid;
	if (flattr_uid) {
		$("#flattr").empty();
		$("#flattr").html('' + artist + ' is making ' + track + ' freely available on Libre.fm for you to listen to, share and remix however you like.');
		FlattrLoader.setup();
		$("#flattrstream").show(1000);
	} else {
		$("#flattrstream").hide(1000);
	}
}

/**
 * Retrieves a playlist from the radio streaming service.
 * A radio session key must be supplied when initialising
 * the play for this to work.
 */
function getRadioPlaylist() {
	var tracks, artist, album, title, url, extension, trackpage_url, i;
	$.get("/2.0/", {'method' : 'radio.getPlaylist', 'sk' : radio_key}, function(data) {
			parser=new DOMParser();
		      	xmlDoc=parser.parseFromString(data,"text/xml");
			tracks = xmlDoc.getElementsByTagName("track")
			for(i = 0; i < tracks.length; i++) {
				try {
					artist = tracks[i].getElementsByTagName("creator")[0].childNodes[0].nodeValue;
					title = tracks[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
					album = tracks[i].getElementsByTagName("album")[0].childNodes[0].nodeValue;
					url = tracks[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
					trackpage_url = tracks[i].getElementsByTagName("trackpage")[0].childNodes[0].nodeValue;
					playlist.push({"artist" : artist, "album" : album, "track" : title, "url" : url, "trackpage" : trackpage_url});
				} catch(err) {
				}
			}
			if(!player_ready) {
				playerReady();
			} else {
				populatePlaylist();
				// Re-enable the skip forward button now that we have more tracks
				$("#skipforward").fadeTo("normal", 1.0);
			}
		}, "text");
}

/**
 * Plays the song previous to the current one in the playlist
 */
function skipBack() {
	playSong(current_song - 1);
}

/**
 * Plays the song after the current one in the playlist
 */
function skipForward() {
	playSong(current_song + 1);
}

/**
 * Converts a timestamp to "MM:SS" format.
 *
 * @param int timestamp A timestamp in seconds.
 * @return string The provided time in "MM:SS" format
 */
function friendlyTime(timestamp) {
	mins = Math.floor(timestamp / 60);
	sec = String(Math.floor(timestamp % 60));
	if(sec.length == 1) { sec = "0" + sec }
	return mins + ":" + sec
}

function love() {
	$.post("/2.0/", {'method' : 'track.love', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
	$("#love").fadeTo("normal", 0.5);
	$("#scrobbled").text("Loved");
	$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
}

function ban() {
	$.post("/2.0/", {'method' : 'track.ban', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
	$("#ban").fadeTo("normal", 0.5);
	skipForward();
}

function toggleTag() {
	$("#tag_input").toggle(500);
	$("#open_tag").toggle();
	$("#close_tag").toggle();
}

function tag() {
	var tags = $("#tags").val();
	if (tags != example_tags && tags != "") {
		$.post("/2.0/", {'method' : 'track.addtags', 'artist' : artist, 'track' : track, 'tags' : tags, 'sk' : ws_key}, function(data) {}, "text");
		toggleTag();
		$("#tags").val("");
	}
}
<commit_msg>Add volume control to html5 audio player<commit_after>/*
   GNU FM -- a free network service for sharing your music listening hab""s

   Copyright (C) 2009 Free Software Foundation, Inc

   @licstart  The following is the entire license notice for the
   JavaScript code in this page.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

   @licend  The above is the entire license notice
   for the JavaScript code in this page.
*/

var scrobbled, now_playing;
var artist, album, track, trackpage, session_key, radio_key, ws_key;
var playlist = [], current_song = 0;
var player_ready = false;
var playable_songs = false;
var streaming = false;
var example_tags = "e.g. guitar, violin, female vocals, piano";

/**
 * Initialises the javascript player (player.tpl must also be included on the target page)
 *
 * @param array list A playlist in the form ([artist, album, track, trackurl, trackpage], [...]) or false if playing a radio stream
 * @param string sk Scrobble session key or false if the user isn't logged in
 * @param string rk Radio session key or false if streaming isn't required
 */
function playerInit(list, sk, ws, rk) {
	var audio = document.getElementById("audio");
	if (!list) {
		// We're playing a stream instead of a playlist
		streaming = true;
	}

	session_key = sk;
	ws_key = ws;
	radio_key = rk;

	if(typeof audio.duration == "undefined") {
		//Browser doesn't support <audio>
		if(streaming) {
			audio.replaceWith("
Sorry, you need a browser capable of using the HTML 5 <audio> element to enjoy the streaming service via the Javascript player.
");
		}
		return;
	}
	$("#fallbackembed").replaceWith(""); // Get rid of the fallback embed, otherwise some html5 browsers will play it in addition to the js player
	if (streaming) {
		// Get playlist from radio service
		getRadioPlaylist();
	} else {
		// Otherwise we have a static playlist
		playlist = list;
		playerReady();
	}
}

/**
 * Finishes the player initialisation when the playlist has been loaded
 */
function playerReady() {
	var audio = document.getElementById("audio");

	populatePlaylist();
	if(!playable_songs) {
		return;
	}
	loadSong(0);
	audio.pause();
	audio.addEventListener("ended", songEnded, false);
	updateProgress();
	$("#play").fadeTo("normal", 1);
	$("#pause").fadeTo("normal", 1);
	$("#pause").hide();
	$("#ban").fadeTo("normal", 1);
	$("#love").fadeTo("normal", 1);
	$("#open_tag").fadeTo("normal", 1);
	$("#volume").fadeTo("normal", 1);
	$("#progressbar").progressbar({ value: 0 });
	$("#player > #interface").show();
	$("#tags").placeholdr({placeholderText: example_tags});
	$("#volume-slider").slider({range: "min", min: 0, max: 100, value: 60, slide: setVolume});
	loadVolume();
	player_ready = true;
}

/**
 * Begins playback
 */
function play() {
	var audio = document.getElementById("audio");
	audio.play();
	if(!now_playing) {
		nowPlaying();
	}
	$("#play").hide();
	$("#pause").show();
	$("#seekforward").fadeTo("normal", 1);
	$("#seekback").fadeTo("normal", 1);
}

/**
 * Pauses playback
 */
function pause() {
	var audio = document.getElementById("audio");
	audio.pause();
	$("#play").show();
	$("#pause").hide();
	$("#seekforward").fadeTo("normal", 0.5);
	$("#seekback").fadeTo("normal", 0.5);
}

/**
 * Seeks backwards 10 seconds in the current song
 */
function seekBack() {
	try {
		var audio = document.getElementById("audio");
		audio.currentTime = audio.currentTime - 10;
	} catch (e) {}
}

/**
 * Seeks forwards 10 seconds in the current song
 */
function seekForward() {
	try {
		var audio = document.getElementById("audio");
		audio.currentTime = audio.currentTime + 10;
	} catch (e) {}
}

/**
 * Updates the progress bar every 900 milliseconds
 */
function updateProgress() {
	var audio = document.getElementById("audio");
	if (audio.duration > 0) {
		$("#progressbar").progressbar('option', 'value', (audio.currentTime / audio.duration) * 100);
		$("#duration").text(friendlyTime(audio.duration));
	} else {
		$("#duration").text(friendlyTime(0));
	}
	if (!scrobbled && audio.currentTime > audio.duration / 2) {
		scrobble();
	}
	$("#currenttime").text(friendlyTime(audio.currentTime));
	setTimeout("updateProgress()", 900)
}

/**
 * Called automatically when a song finished. Loads the next song if there is one
 */
function songEnded() {
	var audio = document.getElementById("audio");
	if(current_song == playlist.length - 1) {
		pause();
	} else {
		loadSong(current_song+1);
		play();
	}
}

/**
 * Outputs the HTML playlist
 */
function populatePlaylist() {
	var i, url;
	//Clear the list
	$("#playlist > #songs").text("");
	for(i = 0; i < playlist.length; i++) {
		url = playlist[i]["url"];
		// Remove non-streamable tracks
		if (url == "") {
			playlist.pop(song); // hur, pop song.
		} else {
			playable_songs = true;
		}
		$("#playlist > #songs").append("
" + playlist[i]["artist"] + " - " + playlist[i]["track"] + "
");
	}
	$("#song-" + current_song).css({fontWeight : "bold"});
}

/**
 * Shows/Hides the HTML playlist display
 */
function togglePlaylist() {
	$("#playlist").toggle(1000);
	$("#showplaylist").toggle();
	$("#hideplaylist").toggle();
}

/**
 * Submits a scrobble for the current song if a scrobble session key has been
 * provided. Makes use of a simple proxy to support installations where the
 * gnukebox installation is at a different domain/sub-domain to the nixtape
 * installation.
 */
function scrobble() {
	var timestamp;
	scrobbled = true;
	if(!session_key) {
		//Not authenticated
		return;
	}
	timestamp = Math.round(new Date().getTime() / 1000);
	$.post("/scrobble-proxy.php?method=scrobble", { "a[0]" : artist, "b[0]" : album, "t[0]" : track, "i[0]" : timestamp, "s" : session_key },
		      	function(data){
				if(data.substring(0, 2) == "OK") {
					$("#scrobbled").text("Scrobbled");
					$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
				} else {
					$("#scrobbled").text(data);
					$("#scrobbled").fadeIn(1000);
				}
		      	}, "text");
}

/**
 * Submits 'now playing' data to the gnukebox server. Like scrobble() this
 * makes use of a proxy.
 */
function nowPlaying() {
	var timestamp;
	var audio = document.getElementById("audio");
	now_playing = true;
	if(!session_key) {
		//Not authenticated
		return;
	}
	timestamp = Math.round(new Date().getTime() / 1000);
	$.post("/scrobble-proxy.php?method=nowplaying", { "a" : artist, "b" : album, "t" : track, "l" : audio.duration, "s" : session_key}, function(data) {}, "text");
}

/**
 * Loads a song and beings playing it.
 *
 * @param int song The song number in the playlist that should be played
 */
function playSong(song) {
	var audio = document.getElementById("audio");
	loadSong(song);
	play();
}

/**
 * Loads a song
 *
 * @param int song The song number in the playlist that should be loaded
 */
function loadSong(song) {
	var url = playlist[song]["url"];
	var audio = document.getElementById("audio");
	artist = playlist[song]["artist"];
	album = playlist[song]["album"];
	track = playlist[song]["track"];
	trackpage = playlist[song]["trackpage"];

	// Highlight current song in the playlist
	$("#song-" + current_song).css({fontWeight : "normal"});
	$("#song-" + song).css({fontWeight : "bold"});

	current_song = song;
	scrobbled = false;
	now_playing = false;
	audio.src = url;
	audio.load();

	if(streaming && current_song > playlist.length - 3) {
		//Update the playlist before the user reaches the end
		getRadioPlaylist();
	}

	if(current_song > 0) {
		$("#skipback").fadeTo("normal", 1.0);
	} else {
		$("#skipback").fadeTo("normal", 0.5);
	}

	if(current_song < playlist.length - 1) {
		$("#skipforward").fadeTo("normal", 1.0);
	} else {
		$("#skipforward").fadeTo("normal", 0.5);
	}

	$("#trackinfo > #artistname").text(artist);
	$("#trackinfo > #trackname").text(track);
	$("#ban").fadeTo("normal", 1);
	$("#love").fadeTo("normal", 1);

	if($("#flattrstream")) {
		$.getJSON('/2.0/', {'method' : 'artist.getflattr', 'artist' : artist, 'format' : 'json'}, updateFlattr);
	}
}

function updateFlattr(data) {
	var flattr_uid = data.flattr.flattr_uid;
	if (flattr_uid) {
		$("#flattr").empty();
		$("#flattr").html('' + artist + ' is making ' + track + ' freely available on Libre.fm for you to listen to, share and remix however you like.');
		FlattrLoader.setup();
		$("#flattrstream").show(1000);
	} else {
		$("#flattrstream").hide(1000);
	}
}

/**
 * Retrieves a playlist from the radio streaming service.
 * A radio session key must be supplied when initialising
 * the play for this to work.
 */
function getRadioPlaylist() {
	var tracks, artist, album, title, url, extension, trackpage_url, i;
	$.get("/2.0/", {'method' : 'radio.getPlaylist', 'sk' : radio_key}, function(data) {
			parser=new DOMParser();
		      	xmlDoc=parser.parseFromString(data,"text/xml");
			tracks = xmlDoc.getElementsByTagName("track")
			for(i = 0; i < tracks.length; i++) {
				try {
					artist = tracks[i].getElementsByTagName("creator")[0].childNodes[0].nodeValue;
					title = tracks[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
					album = tracks[i].getElementsByTagName("album")[0].childNodes[0].nodeValue;
					url = tracks[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
					trackpage_url = tracks[i].getElementsByTagName("trackpage")[0].childNodes[0].nodeValue;
					playlist.push({"artist" : artist, "album" : album, "track" : title, "url" : url, "trackpage" : trackpage_url});
				} catch(err) {
				}
			}
			if(!player_ready) {
				playerReady();
			} else {
				populatePlaylist();
				// Re-enable the skip forward button now that we have more tracks
				$("#skipforward").fadeTo("normal", 1.0);
			}
		}, "text");
}

/**
 * Plays the song previous to the current one in the playlist
 */
function skipBack() {
	playSong(current_song - 1);
}

/**
 * Plays the song after the current one in the playlist
 */
function skipForward() {
	playSong(current_song + 1);
}

/**
 * Converts a timestamp to "MM:SS" format.
 *
 * @param int timestamp A timestamp in seconds.
 * @return string The provided time in "MM:SS" format
 */
function friendlyTime(timestamp) {
	mins = Math.floor(timestamp / 60);
	sec = String(Math.floor(timestamp % 60));
	if(sec.length == 1) { sec = "0" + sec }
	return mins + ":" + sec
}

function love() {
	$.post("/2.0/", {'method' : 'track.love', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
	$("#love").fadeTo("normal", 0.5);
	$("#scrobbled").text("Loved");
	$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
}

function ban() {
	$.post("/2.0/", {'method' : 'track.ban', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
	$("#ban").fadeTo("normal", 0.5);
	skipForward();
}

function toggleTag() {
	$("#tag_input").toggle(500);
	$("#open_tag").toggle();
	$("#close_tag").toggle();
}

function tag() {
	var tags = $("#tags").val();
	if (tags != example_tags && tags != "") {
		$.post("/2.0/", {'method' : 'track.addtags', 'artist' : artist, 'track' : track, 'tags' : tags, 'sk' : ws_key}, function(data) {}, "text");
		toggleTag();
		$("#tags").val("");
	}
}

/**
 * Toggle visibility of the volume slider
 */
function toggleVolume() {
	$("#volume-box").toggle(500);
}

/**
 * Set the player volume and store it in a cookie for future sessions
 */
function setVolume(event, vol) {
	audio.volume = parseFloat(vol.value / 100);
	document.cookie='volume=' + audio.volume;
}

/**
 * Load the player volume from a cookie
 */
function loadVolume() {
	volume = parseFloat(getCookie('volume'));
	$("#volume-slider").slider('value', volume * 100);
	audio.volume = volume;
}

/**
 * Retrieve the contents of a cookie
 */
function getCookie(c_name)
{
	var i,x,y,ARRcookies=document.cookie.split(";");
	for (i=0;i<ARRcookies.length;i++)
	{
		x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
		y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
		x=x.replace(/^\s+|\s+$/g,"");
		if (x==c_name)
		{
			return unescape(y);
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');
var States = require('./reqres_states');

function TChannelOutResponse(id, options) {
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.spanEvent = self.defineEvent('span');
    self.finishEvent = self.defineEvent('finish');

    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.span = options.span || null;
    self.streamed = false;
    self._argstream = null;
    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.codeString = null;
    self.message = null;

    self.finishEvent.on(self.onFinish);
}

inherits(TChannelOutResponse, EventEmitter);

TChannelOutResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutResponse.prototype._sendCallResponse = function _sendCallResponse(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponse'
    });
};

TChannelOutResponse.prototype._sendCallResponseCont = function _sendCallResponseCont(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponseCont'
    });
};

TChannelOutResponse.prototype._sendError = function _sendError(codeString, message) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendError'
    });
};

TChannelOutResponse.prototype.onFinish = function onFinish(_arg, self) {
    if (!self.end) self.end = self.timers.now();
    if (self.span) {
        self.spanEvent.emit(self, self.span);
    }
};

TChannelOutResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'arg parts',
                state: 'Done'
            }));
            break;
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self._sendCallResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response',
                state: 'Streaming'
            }));
            break;
        case States.Done:
        case States.Error:
            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response',
                state: self.state,
                method: 'sendCallResponseFrame',
                bufArg2: args[1].slice(0, 50),
                arg2: String(args[1]).slice(0, 50),
                bufArg3: args[2].slice(0, 50),
                arg3: String(args[2]).slice(0, 50)
            }));
    }
};

TChannelOutResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response continuation',
                state: 'Initial'
            }));
            break;
        case States.Streaming:
            self._sendCallResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response continuation',
                state: self.state,
                method: 'sendCallResponseContFrame'
            }));
    }
};

TChannelOutResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;
    if (self.state === States.Done || self.state === States.Error) {
        self.errorEvent.emit(self, errors.ResponseAlreadyDone({
            attempted: 'send error frame: ' + codeString + ': ' + message,
            currentState: self.state,
            method: 'sendError',
            codeString: codeString,
            errMessage: message
        }));
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;

        self.codeString = codeString;
        self.message = message;

        self._sendError(codeString, message);
        self.finishEvent.emit(self);
    }
};

TChannelOutResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        self.errorEvent.emit(self, errors.ResponseAlreadyStarted({
            state: self.state,
            method: 'setOk',
            ok: ok
        }));
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
};

TChannelOutResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.state === States.Error) {
        self.logger.error('cannot send application error, already sent error frame', {
            res1: res1,
            res2: res2
        });
    } else {
        self.setOk(false);
        self.send(res1, res2);
    }
};

TChannelOutResponse.prototype.send = function send(res1, res2) {
    var self = this;

    self.arg2 = res1;
    self.arg3 = res2;

    self.sendCallResponseFrame([self.arg1, res1, res2], true);
    self.finishEvent.emit(self);
    return self;
};

module.exports = TChannelOutResponse;
<commit_msg>out_response: fix null bug<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('./lib/event_emitter');
var inherits = require('util').inherits;

var errors = require('./errors');
var States = require('./reqres_states');

function TChannelOutResponse(id, options) {
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.spanEvent = self.defineEvent('span');
    self.finishEvent = self.defineEvent('finish');

    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.span = options.span || null;
    self.streamed = false;
    self._argstream = null;
    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.codeString = null;
    self.message = null;

    self.finishEvent.on(self.onFinish);
}

inherits(TChannelOutResponse, EventEmitter);

TChannelOutResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutResponse.prototype._sendCallResponse = function _sendCallResponse(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponse'
    });
};

TChannelOutResponse.prototype._sendCallResponseCont = function _sendCallResponseCont(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponseCont'
    });
};

TChannelOutResponse.prototype._sendError = function _sendError(codeString, message) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendError'
    });
};

TChannelOutResponse.prototype.onFinish = function onFinish(_arg, self) {
    if (!self.end) self.end = self.timers.now();
    if (self.span) {
        self.spanEvent.emit(self, self.span);
    }
};

TChannelOutResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'arg parts',
                state: 'Done'
            }));
            break;
        case States.Error:
            // TODO: log warn
            break;
    }
};

TChannelOutResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self._sendCallResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response',
                state: 'Streaming'
            }));
            break;
        case States.Done:
        case States.Error:
            var arg2 = args[1] || '';
            var arg3 = args[2] || '';

            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response',
                state: self.state,
                method: 'sendCallResponseFrame',
                bufArg2: arg2.slice(0, 50),
                arg2: String(arg2).slice(0, 50),
                bufArg3: arg3.slice(0, 50),
                arg3: String(arg3).slice(0, 50)
            }));
    }
};

TChannelOutResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response continuation',
                state: 'Initial'
            }));
            break;
        case States.Streaming:
            self._sendCallResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response continuation',
                state: self.state,
                method: 'sendCallResponseContFrame'
            }));
    }
};

TChannelOutResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;
    if (self.state === States.Done || self.state === States.Error) {
        self.errorEvent.emit(self, errors.ResponseAlreadyDone({
            attempted: 'send error frame: ' + codeString + ': ' + message,
            currentState: self.state,
            method: 'sendError',
            codeString: codeString,
            errMessage: message
        }));
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;

        self.codeString = codeString;
        self.message = message;

        self._sendError(codeString, message);
        self.finishEvent.emit(self);
    }
};

TChannelOutResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        self.errorEvent.emit(self, errors.ResponseAlreadyStarted({
            state: self.state,
            method: 'setOk',
            ok: ok
        }));
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
};

TChannelOutResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.state === States.Error) {
        self.logger.error('cannot send application error, already sent error frame', {
            res1: res1,
            res2: res2
        });
    } else {
        self.setOk(false);
        self.send(res1, res2);
    }
};

TChannelOutResponse.prototype.send = function send(res1, res2) {
    var self = this;

    self.arg2 = res1;
    self.arg3 = res2;

    self.sendCallResponseFrame([self.arg1, res1, res2], true);
    self.finishEvent.emit(self);
    return self;
};

module.exports = TChannelOutResponse;
<|endoftext|>


<commit_before>var t = 0;
const exec = require('child_process').exec;
exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}');
	t =1;
    return 1;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');
  return 0;
 }
});
exec('killall node',function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}');
	t =1;
    return;
  }
  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');
});
return t;
<commit_msg>Update testsA.js<commit_after>var t = 0;
const exec = require('child_process').exec;
exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}');
	t =1;
    return 1;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');
  return 0;
 }
});

<|endoftext|>


<commit_before>const Config = require("truffle-config");
const Web3 = require("web3");
const TruffleResolver = require("truffle-resolver");
const assert = require("assert");
const Ganache = require("ganache-core");
const ENS = require("../ens");
const path = require("path");
let ganacheOptions,
  config,
  options,
  server,
  ens,
  fromAddress,
  provider,
  workingDirectory,
  contractsBuildDirectory;

describe("ENS class", () => {
  beforeEach(done => {
    ganacheOptions = {
      mnemonic:
        "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat",
      total_accounts: 10,
      default_ether_balance: 100
    };
    workingDirectory = path.join(__dirname, "sources", "init");
    contractsBuildDirectory = path.join(workingDirectory, "build");
    config = Config.detect({
      working_directory: workingDirectory,
      contracts_build_directory: contractsBuildDirectory
    });
    server = Ganache.server(ganacheOptions);
    server.listen(8545, done);
    provider = new Web3.providers.HttpProvider("http://localhost:8545");
    options = {
      provider,
      resolver: new TruffleResolver(config)
    };
    ens = new ENS(options);
    fromAddress = "0x627306090abaB3A6e1400e9345bC60c78a8BEf57";
  });
  afterEach(done => {
    if (server) {
      server.close(() => {
        server = null;
        done();
      });
    }
  });

  describe("deployNewENSRegistry", () => {
    it("deploys a new registry and returns valid addresses", async () => {
      let {
        registryOwnerAddress,
        registryAddress
      } = await ens.deployNewENSRegistry(fromAddress);
      assert(Web3.utils.isAddress(registryOwnerAddress));
      assert(Web3.utils.isAddress(registryAddress));
    });
    it("returns addresses that are not 0x0", async () => {
      let {
        registryOwnerAddress,
        registryAddress
      } = await ens.deployNewENSRegistry(fromAddress);
      assert(registryAddress !== "0x0000000000000000000000000000000000000000");
      assert(
        registryOwnerAddress !== "0x0000000000000000000000000000000000000000"
      );
    });
  });
});
<commit_msg>Write a couple of tests for the ens utility<commit_after>const Config = require("truffle-config");
const Web3 = require("web3");
const TruffleResolver = require("truffle-resolver");
const assert = require("assert");
const Ganache = require("ganache-core");
const ENS = require("../ens");
const path = require("path");
const sinon = require("sinon");
const HDWalletProvider = require("truffle-hdwallet-provider");
let ganacheOptions,
  config,
  options,
  server,
  ens,
  fromAddress,
  provider,
  workingDirectory,
  contractsBuildDirectory,
  addressToSet,
  registryArtifact;

describe("ENS class", () => {
  before(() => {
    ganacheOptions = {
      mnemonic:
        "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat",
      total_accounts: 1,
      default_ether_balance: 100
    };
    server = Ganache.server(ganacheOptions);
    server.listen(8545, () => {});
  });
  after(done => {
    if (server) {
      server.close(() => {
        server = null;
        done();
      });
    }
  });
  beforeEach(() => {
    workingDirectory = path.join(__dirname, "sources", "init");
    contractsBuildDirectory = path.join(workingDirectory, "build", "contracts");
    config = Config.detect({
      working_directory: workingDirectory,
      contracts_build_directory: contractsBuildDirectory
    });
    provider = new HDWalletProvider(
      ganacheOptions.mnemonic,
      "http://localhost:8545"
    );
    options = {
      provider,
      resolver: new TruffleResolver(config)
    };
    registryArtifact = require(path.join(
      contractsBuildDirectory,
      "ENSRegistry.json"
    ));
    sinon
      .stub(options.resolver.sources[3], "require")
      .withArgs("@ensdomains/ens/ENSRegistry")
      .returns(registryArtifact);
    ens = new ENS(options);
    fromAddress = "0x627306090abaB3A6e1400e9345bC60c78a8BEf57";
  });
  afterEach(() => {
    options.resolver.sources[3].require.restore();
  });

  describe("deployNewENSRegistry", () => {
    it("deploys a new registry and returns valid addresses", async () => {
      let {
        registryOwnerAddress,
        registryAddress
      } = await ens.deployNewENSRegistry(fromAddress);
      assert(Web3.utils.isAddress(registryOwnerAddress));
      assert(Web3.utils.isAddress(registryAddress));
    });
    it("deploys a new registry and returns non 0x0 addresses", async () => {
      let {
        registryOwnerAddress,
        registryAddress
      } = await ens.deployNewENSRegistry(fromAddress);
      assert(registryAddress !== "0x0000000000000000000000000000000000000000");
      assert(
        registryOwnerAddress !== "0x0000000000000000000000000000000000000000"
      );
    });
  });

  describe("register(address, name, from)", () => {
    describe("when there is no registry deployed", () => {
      beforeEach(() => {
        sinon.spy(ens, "deployNewENSRegistry");
        sinon.stub();
        addressToSet = "0x1234567890123456789012345678901234567890";
      });
      afterEach(() => {
        ens.deployNewENSRegistry.restore();
      });

      it("calls deployNewENSRegistry", async () => {
        try {
          await ens.register(addressToSet, "namezzz", fromAddress);
        } catch (error) {
          const expectedMessageSnippet = `The default address or address provided in the "from"`;
          if (error.message.includes(expectedMessageSnippet)) {
            assert(ens.deployNewENSRegistry.called);
          } else {
            throw error;
          }
        }
      });
    });
    // describe("when there is a registry deployed", () => {
    //   it("registers a name and sets the resolver", () => {
    //
    //   });
    // });
  });
});
<|endoftext|>


<commit_before>// Copyright 2015-2016, Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This code is a mix of these three sample programs:
// https://github.com/spark/google-cloud-datastore-tutorial/blob/master/tutorial.js
// https://cloud.google.com/appengine/docs/flexible/nodejs/writing-and-responding-to-pub-sub-messages
// https://cloud.google.com/appengine/docs/flexible/nodejs/using-cloud-datastore

// [START app]
'use strict';

// [START setup]

var express = require('express');

var app = express();

// I'm not really sure if this is needed
app.enable('trust proxy');

// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GCLOUD_PROJECT environment variable. See
// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication
// These environment variables are set automatically on Google App Engine
var Datastore = require('@google-cloud/datastore');

// Instantiate a datastore client
var datastore = Datastore();

//By default, the client will authenticate using the service account file
//specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
//the project specified by the GCLOUD_PROJECT environment variable. See
//https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication
//These environment variables are set automatically on Google App Engine
var PubSub = require('@google-cloud/pubsub');

//Instantiate a pubsub client
var pubsub = PubSub();

//The following environment variables are set by app.yaml when running on GAE,
//but will need to be manually set when running locally.
var PUBSUB_VERIFICATION_TOKEN = process.env.PUBSUB_VERIFICATION_TOKEN;

var topic = pubsub.topic(process.env.PUBSUB_TOPIC);

var subscription = pubsub.subscription(process.env.PUBSUB_SUBSCRIPTION_NAME);

// [END setup]

// This code from here:
// https://github.com/spark/google-cloud-datastore-tutorial/blob/master/tutorial.js
function storeEvent(message) {
    var key = datastore.key('officedata');

    // You can uncomment some of the other things if you want to store them in the database
    var obj = {
		gc_pub_sub_id: message.id,
		device_id: message.attributes.device_id,
		//event: message.attributes.event,
		published_at: message.attributes.published_at,
	    	temperature: message.data
	}

    // Copy the data in message.data, the Particle event data, as top-level
    // elements in obj. This breaks the data out into separate columns.
    for (var prop in message.data) {
        if (message.data.hasOwnProperty(prop)) {
            obj[prop] = message.data[prop];
        }
    }

    datastore.save({
        key: key,
        data: obj
    }, function(err) {
		if(err) {
			console.log('There was an error storing the event', err);
		}
		console.log('stored in datastore', obj);
    });

};

subscription.on('message', function(message) {
	console.log('event received', message);
	// Called every time a message is received.
	// message.id = ID used to acknowledge its receival.
	// message.data = Contents of the message.
	// message.attributes = Attributes of the message.
	storeEvent(message);
	message.ack();
});

// [START listen]
var server = app.listen(process.env.PORT || 8080, function () {
  console.log('App listening on port %s', server.address().port);
  console.log('Press Ctrl+C to quit.');
});
// [END listen]
// [END app]

module.exports = app;
<commit_msg>Update app.js<commit_after>// Copyright 2015-2016, Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This code is a mix of these three sample programs:
// https://github.com/spark/google-cloud-datastore-tutorial/blob/master/tutorial.js
// https://cloud.google.com/appengine/docs/flexible/nodejs/writing-and-responding-to-pub-sub-messages
// https://cloud.google.com/appengine/docs/flexible/nodejs/using-cloud-datastore

// [START app]
'use strict';

// [START setup]

var express = require('express');

var app = express();

// I'm not really sure if this is needed
app.enable('trust proxy');

// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GCLOUD_PROJECT environment variable. See
// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication
// These environment variables are set automatically on Google App Engine
var Datastore = require('@google-cloud/datastore');

// Instantiate a datastore client
var datastore = Datastore();

//By default, the client will authenticate using the service account file
//specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
//the project specified by the GCLOUD_PROJECT environment variable. See
//https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication
//These environment variables are set automatically on Google App Engine
var PubSub = require('@google-cloud/pubsub');

//Instantiate a pubsub client
var pubsub = PubSub();

//The following environment variables are set by app.yaml when running on GAE,
//but will need to be manually set when running locally.
var PUBSUB_VERIFICATION_TOKEN = process.env.PUBSUB_VERIFICATION_TOKEN;

var topic = pubsub.topic(process.env.PUBSUB_TOPIC);

var subscription = pubsub.subscription(process.env.PUBSUB_SUBSCRIPTION_NAME);

// [END setup]

// This code from here:
// https://github.com/spark/google-cloud-datastore-tutorial/blob/master/tutorial.js
function storeEvent(message) {
    var key = datastore.key('officedata');

    // You can uncomment some of the other things if you want to store them in the database
    var obj = {
		gc_pub_sub_id: message.id,
		device_id: message.attributes.device_id,
		//event: message.attributes.event,
		published_at: message.attributes.published_at,
	    	temperature: message.data
	}

    // Copy the data in message.data, the Particle event data, as top-level
    // elements in obj. This breaks the data out into separate columns.
    //for (var prop in message.data) {
     //   if (message.data.hasOwnProperty(prop)) {
      //      obj[prop] = message.data[prop];
       // }
    //}

    datastore.save({
        key: key,
        data: obj
    }, function(err) {
		if(err) {
			console.log('There was an error storing the event', err);
		}
		console.log('stored in datastore', obj);
    });

};

subscription.on('message', function(message) {
	console.log('event received', message);
	// Called every time a message is received.
	// message.id = ID used to acknowledge its receival.
	// message.data = Contents of the message.
	// message.attributes = Attributes of the message.
	storeEvent(message);
	message.ack();
});

// [START listen]
var server = app.listen(process.env.PORT || 8080, function () {
  console.log('App listening on port %s', server.address().port);
  console.log('Press Ctrl+C to quit.');
});
// [END listen]
// [END app]

module.exports = app;
<|endoftext|>


<commit_before>/**
 * 2LinesAds - simple text ads system (without banners)
 *
 * Main script include it in your pages
 *
 * This is a simple ads system without banners that I've wrote long ago ...
 * It is in it's early stages of development. Feel free to fork and upgrade it.
 *
 *
 * @author    Marko Milost <mclion@gmail.com>
 * @copyright (c) 2006-2012 by Marko Milost / McLion
 * @license   http://opensource.org/licenses/mit-license.php MIT
 */

// URL of the installation
var serverUrl = "http://mclion.tuinzdaj.net/2linesads/";

/**
 * Util functions
 */

// Doing styles this way because of the pseudo classes
function addCss(sel, css) {
	try {
		// this breaks in Opera/FF if HTML has external CSS rules
		styl = document.styleSheets[document.styleSheets.length - 1];
		r = (styl.cssRules !== undefined) ? styl.cssRules: styl.rules;
	} catch(e) {
		// So we don't have local CSS, let's create one
		var head = document.getElementsByTagName('head')[0];
		var s = document.createElement('style');
		s.setAttribute('type', 'text/css');
		head.appendChild(s);

		styl = document.styleSheets[document.styleSheets.length - 1];
		r = (styl.cssRules !== undefined) ? styl.cssRules: styl.rules;
	}

    if (styl.insertRule) {
		styl.insertRule(sel + '{' + css + '}', r.length);
    } else if (styl.addRule) {
		styl.addRule(sel, css, r.length);
    }

}

// Nice touch device test from http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
function isTouchDevice() {
  return !!('ontouchstart' in window) || !!('onmsgesturechange' in window);
}

// Init AJAX
function createRequestObject() {
	if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
		return new XMLHttpRequest();
	} else {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}

// Send request
function getPhrases() {
    http.open("GET", serverUrl + "2linesads_loader.php", false);
    http.send();
    if(http.readyState == 4 && http.status == 200) {
			return http.responseText;
	}

}

function addCounter(ctype, userID, adword) {
	http.open("GET", serverUrl + ctype + ".php?id=" + userID + "&adword=" + adword, true);
	http.send();
}

function getRealTop(oElement) {
	var iReturnValue = 0;
	while(oElement !== null) {
		iReturnValue += oElement.offsetTop;
		oElement = oElement.offsetParent;
	}
	return iReturnValue;
}

function getRealLeft(oElement) {
	var iReturnValue = 0;
	while(oElement !== null) {
		iReturnValue += oElement.offsetLeft;
		oElement = oElement.offsetParent;
	}
	return iReturnValue;
}

// Just for IE
function arrayIndexOf(arrVar, strVar) {
	if(arrVar.indexOf) {
		if(arrVar.indexOf(strVar) != -1) {
			return true;
		} else {
			return false;
		}
	}

	for(i = 0; i < arrVar.length; i++) {
		if(arrVar[i] == strVar) {
			return true;
		}
	}
	return false;
}

function resetTimeout() {
	try {
		if(mID) {
			window.clearTimeout(mID);
			delete mID; // Works because it was not declared with a value
		}
	} catch(ex) {}
}

function startTimeout(timeOut) {
	if(mID <= 0) {
		//debugger;
	} else {
		window.clearTimeout(mID);
		mID = window.setTimeout("document.getElementById(\"adBox\").style.visibility=\"hidden\";", 2000);
	}
}

// Adds functions
function doHighlight(bodyText, searchTerm, highlightStartTag, highlightEndTag, userID) {
	var newText = "";
	var i = -1;
	var loop = 0;
	var counter = 0;

	if(arrayIndexOf(basket, userID) === true) {
		return bodyText;
	}

	var searchString = new RegExp("([\\s])(" + searchTerm.toLowerCase() + "[a-z0-9]*)([\\s\\S])", "i");

	newText = bodyText.replace(searchString, "$1" + highlightStartTag + "$2" + highlightEndTag + "$3");
	if(newText.length > bodyText.length) {
		basket = basket.concat(userID);
		counter++;

		tmpCount += counter;
		return newText;
	} else {
		return bodyText;
	}

}

// Setup the elements
function highlightSearchTerms(searchText, bannerTitle, bannerDesc, bannerURL, bannerPicture, userID) {

	highlightEndTag = "";

	// Change with the element id you wish to scan
	if(document.getElementById("body_content")) {
		var bodyText = document.getElementById("body_content").innerHTML + ' '; // the space is needed for searching for the last element
		if(searchText.indexOf("|") > 0) {
			var searchLoop = searchText.split("|");
			for(var xx = 0; xx < searchLoop.length; xx++) {
				adBoxID = "adBoxT_" + encodeURI(searchLoop[xx].toLowerCase());
				highlightStartTag = '';
				bodyText = doHighlight(bodyText, searchLoop[xx], highlightStartTag, highlightEndTag, userID);
				addCounter("cs",userID,searchLoop[xx]); // add to keywords underline counter
			}
		} else {
			adBoxID = "adBoxT_" + encodeURI(searchText.toLowerCase());
			highlightStartTag = '';
			bodyText = doHighlight(bodyText, searchText, highlightStartTag, highlightEndTag, userID);
		}

		document.getElementById("body_content").innerHTML = bodyText;

		return true;
	} else {
		return false;
	}
}

// Run the highlightsearch for every ad
function searchPhrases(searchArray) {
	for (var key in searchArray) {
		var obj = searchArray[key];
		highlightSearchTerms(obj.keywords, obj.title, obj.description, obj.url, obj.picture, obj.id);
	}
}

// This "draws" the ad
function dotxtad(adID, adPicture, adTitle, adText, adURL, adword, userID) {
	// create DIV
	var linkID = document.getElementById(adID);
	var boxID = document.getElementById("adBox");
	var humanURL, tmpHtml;

	boxID.style.left = 10 + "px";
	boxID.style.top = 10 + "px";
	boxID.style.width = 250 + "px";
	boxID.style.visibility = ""; // I think it's an old IE hack, with hidden it does not always work.

	adTitle = unescape(adTitle);
	adText = unescape(adText);

	boxID.style.left = getRealLeft(linkID) - 5 + "px";

	boxID.style.top = getRealTop(linkID) + 33 + "px"; // put it on the bottom

	humanURL = unescape(adURL.replace(/.*url=(.*)/, "$1"));
	humanURL = humanURL.replace(/http:\/\/([a-z0-9\.\-]*).*/i, "$1");

	tmpHtml = '
';
	tmpHtml += '
' + adTitle + '
';
	tmpHtml += '
' ;

	if(adPicture !== null && adPicture !== false && adPicture !== "") {
		tmpHtml += '';
	}
	tmpHtml += adText + "
";
	tmpHtml += '

' + humanURL + '
What is this?';
	tmpHtml += "
";
	tmpHtml += "
";
	boxID.innerHTML = tmpHtml;
	addCounter("cv", userID, adword); // add to adviews counter
}

function addTheBox(divId) {
	var newDiv = document.createElement("div");
	newDiv.id = "adBox";
	newDiv.onmouseout = startTimeout(1000);
	newDiv.oncontextmenu = false;
	newDiv.onmouseover = resetTimeout();

	newDiv.style["visibility"] = "hidden";

	myDiv = document.getElementById(divId);
	document.body.insertBefore(newDiv, myDiv);

	addCss('#adBox','position:absolute;padding:8px;color:#333;background:#ebf1f4;border:2px solid #fff;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;-moz-box-shadow: 3px 3px 4px #ccc;-webkit-box-shadow: 3px 3px 4px #ccc;box-shadow: 3px 3px 4px #ccc;-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color=\'#ccc000\')";filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color=\'#ccc000\');-moz-opacity:0.95;opacity:0.95;filter:alpha(opacity=95);z-index:1000000;');

	// arrow
	addCss('#adBox:after','content:"";position:absolute;border-top:20px solid transparent;border-left: 20px solid #ebf1f4;top:-20px;left:15px;display:block;width:0;');

	// shadow of the arrow
	addCss('#adBox:before','content:"";position:absolute;border-top:22px solid transparent;border-left: 24px solid #fff;top:-22px;left:13px;display:block;width:0;');

}

function init() {
	addTheBox("2linesads"); // initialize box

	var data = getPhrases();
	if (window.JSON && window.JSON.parse) {
        data = window.JSON.parse(data);
        searchPhrases(data);
	} else {
		return false; // We have no JSON, so we won't display any ads
	}
}

/* Here it starts ... */
var http = createRequestObject(); // Create AJAX object

var mID; // timeout id
var tmpCount = 0; // temp counter
var basket = []; // better than new Array();

init();<commit_msg>Rewrite pseudo CSS writer. Didn't work on mobile.<commit_after>/**
 * 2LinesAds - simple text ads system (without banners)
 *
 * Main script include it in your pages
 *
 * This is a simple ads system without banners that I've wrote long ago ...
 * It is in it's early stages of development. Feel free to fork and upgrade it.
 *
 *
 * @author    Marko Milost <mclion@gmail.com>
 * @copyright (c) 2006-2012 by Marko Milost / McLion
 * @license   http://opensource.org/licenses/mit-license.php MIT
 */

// URL of the installation
var serverUrl = "http://mclion.tuinzdaj.net/2linesads/";

/**
 * Util functions
 */

// Doing styles this way because of the pseudo classes
function addCss(sel, css) {
	// This has to be set
	if (set_css === false) {
		var head = document.getElementsByTagName('head')[0];
		var s = document.createElement('style');
		s.setAttribute('type', 'text/css');
		head.appendChild(s);

		set_css = true;
	}

	styl = document.styleSheets[document.styleSheets.length - 1];
	r = (styl.cssRules !== undefined) ? styl.cssRules: styl.rules;

    if (styl.insertRule) {
		styl.insertRule(sel + '{' + css + '}', r.length);
    } else if (styl.addRule) {
		styl.addRule(sel, css, r.length);
    }

}

// Nice touch device test from http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
function isTouchDevice() {
  return !!('ontouchstart' in window) || !!('onmsgesturechange' in window);
}

// Init AJAX
function createRequestObject() {
	if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
		return new XMLHttpRequest();
	} else {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}

// Send request
function getPhrases() {
    http.open("GET", serverUrl + "2linesads_loader.php", false);
    http.send();
    if(http.readyState == 4 && http.status == 200) {
			return http.responseText;
	}

}

function addCounter(ctype, userID, adword) {
	http.open("GET", serverUrl + ctype + ".php?id=" + userID + "&adword=" + adword, true);
	http.send();
}

function getRealTop(oElement) {
	var iReturnValue = 0;
	while(oElement !== null) {
		iReturnValue += oElement.offsetTop;
		oElement = oElement.offsetParent;
	}
	return iReturnValue;
}

function getRealLeft(oElement) {
	var iReturnValue = 0;
	while(oElement !== null) {
		iReturnValue += oElement.offsetLeft;
		oElement = oElement.offsetParent;
	}
	return iReturnValue;
}

// Just for IE
function arrayIndexOf(arrVar, strVar) {
	if(arrVar.indexOf) {
		if(arrVar.indexOf(strVar) != -1) {
			return true;
		} else {
			return false;
		}
	}

	for(i = 0; i < arrVar.length; i++) {
		if(arrVar[i] == strVar) {
			return true;
		}
	}
	return false;
}

function resetTimeout() {
	try {
		if(mID) {
			window.clearTimeout(mID);
			delete mID; // Works because it was not declared with a value
		}
	} catch(ex) {}
}

function startTimeout(timeOut) {
	if(mID <= 0) {
		//debugger;
	} else {
		window.clearTimeout(mID);
		mID = window.setTimeout("document.getElementById(\"adBox\").style.visibility=\"hidden\";", 2000);
	}
}

// Adds functions
function doHighlight(bodyText, searchTerm, highlightStartTag, highlightEndTag, userID) {
	var newText = "";
	var i = -1;
	var loop = 0;
	var counter = 0;

	if(arrayIndexOf(basket, userID) === true) {
		return bodyText;
	}

	var searchString = new RegExp("([\\s])(" + searchTerm.toLowerCase() + "[a-z0-9]*)([\\s\\S])", "i");

	newText = bodyText.replace(searchString, "$1" + highlightStartTag + "$2" + highlightEndTag + "$3");
	if(newText.length > bodyText.length) {
		basket = basket.concat(userID);
		counter++;

		tmpCount += counter;
		return newText;
	} else {
		return bodyText;
	}

}

// Setup the elements
function highlightSearchTerms(searchText, bannerTitle, bannerDesc, bannerURL, bannerPicture, userID) {

	highlightEndTag = "";

	// Change with the element id you wish to scan
	if(document.getElementById("body_content")) {
		var bodyText = document.getElementById("body_content").innerHTML + ' '; // the space is needed for searching for the last element
		if(searchText.indexOf("|") > 0) {
			var searchLoop = searchText.split("|");
			for(var xx = 0; xx < searchLoop.length; xx++) {
				adBoxID = "adBoxT_" + encodeURI(searchLoop[xx].toLowerCase());
				highlightStartTag = '';
				bodyText = doHighlight(bodyText, searchLoop[xx], highlightStartTag, highlightEndTag, userID);
				addCounter("cs",userID,searchLoop[xx]); // add to keywords underline counter
			}
		} else {
			adBoxID = "adBoxT_" + encodeURI(searchText.toLowerCase());
			highlightStartTag = '';
			bodyText = doHighlight(bodyText, searchText, highlightStartTag, highlightEndTag, userID);
		}

		document.getElementById("body_content").innerHTML = bodyText;

		return true;
	} else {
		return false;
	}
}

// Run the highlightsearch for every ad
function searchPhrases(searchArray) {
	for (var key in searchArray) {
		var obj = searchArray[key];
		highlightSearchTerms(obj.keywords, obj.title, obj.description, obj.url, obj.picture, obj.id);
	}
}

// This "draws" the ad
function dotxtad(adID, adPicture, adTitle, adText, adURL, adword, userID) {
	// create DIV
	var linkID = document.getElementById(adID);
	var boxID = document.getElementById("adBox");
	var humanURL, tmpHtml;

	boxID.style.left = 10 + "px";
	boxID.style.top = 10 + "px";
	boxID.style.width = 250 + "px";
	boxID.style.visibility = ""; // I think it's an old IE hack, with hidden it does not always work.

	adTitle = unescape(adTitle);
	adText = unescape(adText);

	boxID.style.left = getRealLeft(linkID) - 5 + "px";

	boxID.style.top = getRealTop(linkID) + 33 + "px"; // put it on the bottom

	humanURL = unescape(adURL.replace(/.*url=(.*)/, "$1"));
	humanURL = humanURL.replace(/http:\/\/([a-z0-9\.\-]*).*/i, "$1");

	tmpHtml = '
';
	tmpHtml += '
' + adTitle + '
';
	tmpHtml += '
' ;

	if(adPicture !== null && adPicture !== false && adPicture !== "") {
		tmpHtml += '';
	}
	tmpHtml += adText + "
";
	tmpHtml += '

' + humanURL + '
What is this?';
	tmpHtml += "
";
	tmpHtml += "
";
	boxID.innerHTML = tmpHtml;
	addCounter("cv", userID, adword); // add to adviews counter
}

function addTheBox(divId) {
	var newDiv = document.createElement("div");
	newDiv.id = "adBox";
	newDiv.onmouseout = startTimeout(1000);
	newDiv.oncontextmenu = false;
	newDiv.onmouseover = resetTimeout();

	newDiv.style["visibility"] = "hidden";

	myDiv = document.getElementById(divId);
	document.body.insertBefore(newDiv, myDiv);

	addCss('#adBox','position:absolute;padding:8px;color:#333;background:#ebf1f4;border:2px solid #fff;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;-moz-box-shadow: 3px 3px 4px #ccc;-webkit-box-shadow: 3px 3px 4px #ccc;box-shadow: 3px 3px 4px #ccc;-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color=\'#ccc000\')";filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color=\'#ccc000\');-moz-opacity:0.95;opacity:0.95;filter:alpha(opacity=95);z-index:1000000;');

	// arrow
	addCss('#adBox:after','content:"";position:absolute;border-top:20px solid transparent;border-left: 20px solid #ebf1f4;top:-20px;left:15px;display:block;width:0;');

	// shadow of the arrow
	addCss('#adBox:before','content:"";position:absolute;border-top:22px solid transparent;border-left: 24px solid #fff;top:-22px;left:13px;display:block;width:0;');

}

function init() {
	addTheBox("2linesads"); // initialize box

	var data = getPhrases();
	if (window.JSON && window.JSON.parse) {
        data = window.JSON.parse(data);
        searchPhrases(data);
	} else {
		return false; // We have no JSON, so we won't display any ads
	}
}

/* Here it starts ... */
var http = createRequestObject(); // Create AJAX object

var mID; // timeout id
var tmpCount = 0; // temp counter
var basket = []; // better than new Array();
var set_css = false; // global for checking style creation

init();<|endoftext|>


<commit_before>//Time Merger v2.0
window.ExternalScripts = true;
var Intervalstatistics = setInterval(CellTimer, 1000);

function CellTimer() {
    if (!window.legendmod5.optimizedMass && window.ExternalScripts) {
        myCells = [];
        for (var i = 0; i < window.legendmod.playerCells.length; i++) {
            //legendmod.cells[i].historyMass->window.playerCellsId[legendmod.cells[i].id].historyMass

            if (window.playerCellsId && window.legendmod.playerCells[i] && window.legendmod.playerCells[i].id && window.playerCellsId[legendmod.playerCells[i].id] &&
                window.playerCellsId[legendmod.playerCells[i].id].historyMass &&
                window.playerCellsId[legendmod.playerCells[i].id].historyMass[window.legendmod2.fps] > window.playerCellsId[legendmod.playerCells[i].id].historyMass[0] * 1.4) {
					console.log("Mass Merge Timer started with mass: " + window.playerCellsId[legendmod.playerCells[i].id].historyMass[window.legendmod2.fps]);
                var j = i;
                var x = 0;

                MergeCells(j, x);

            } else {
                if (window.playerCellsId && window.legendmod.playerCells[i] && window.legendmod.playerCells[i].id && window.playerCellsId[legendmod.playerCells[i].id] &&
                    window.playerCellsId[legendmod.playerCells[i].id].historyMass) {
                    window.playerCellsId[legendmod.playerCells[i].id].mergeTime = null;
                }
            }

        }
    }
}

function MergeCells(j, x) {
    x++;
    if (window.legendmod.playerCells.length > 1 && window.playerCellsId && window.legendmod.playerCells[j] && window.legendmod.playerCells[j].id && window.playerCellsId[legendmod.playerCells[j].id]) {
        //window.playerCellsId[legendmod.playerCells[j].id].mergeTime = 29 + (7 / 300) * window.playerCellsId[legendmod.playerCells[j].id].historyMass[0] - x;
		window.playerCellsId[legendmod.playerCells[j].id].mergeTime = 29 + (8 / 300) * window.playerCellsId[legendmod.playerCells[j].id].historyMass[0] - x;
        //
        if (window.playerCellsId[legendmod.playerCells[j].id].mergeTime > -20) {
            setTimeout(function() {
                MergeCells(j, x);
				console.log("Mass Merge: " + j, x, window.playerCellsId[legendmod.playerCells[j].id].historyMass[0]);
            }, 1000);
        }

    }
	else {
		console.log("Mass Merge Timer ended: " + j, x);
                if (window.playerCellsId && window.legendmod.playerCells[j] && window.legendmod.playerCells[j].id && window.playerCellsId[legendmod.playerCells[j].id] &&
                    window.playerCellsId[legendmod.playerCells[j].id].historyMass) {
						window.playerCellsId[legendmod.playerCells[j].id].mergeTime = null;
					}
    }
    return j, x;
}
<commit_msg>Update mergetimer.js<commit_after>//Time Merger v1.9
window.ExternalScripts = true;
var Intervalstatistics = setInterval(CellTimer, 1000);

function CellTimer() {
    if (!window.legendmod5.optimizedMass && window.ExternalScripts) {
        myCells = [];
        for (var i = 0; i < window.legendmod.playerCells.length; i++) {
            //legendmod.cells[i].historyMass->window.playerCellsId[legendmod.cells[i].id].historyMass

            if (window.playerCellsId && window.legendmod.playerCells[i] && window.legendmod.playerCells[i].id && window.playerCellsId[legendmod.playerCells[i].id] &&
                window.playerCellsId[legendmod.playerCells[i].id].historyMass &&
                window.playerCellsId[legendmod.playerCells[i].id].historyMass[window.legendmod2.fps] > window.playerCellsId[legendmod.playerCells[i].id].historyMass[0] * 1.4) {
					//console.log("Mass Merge Timer started with mass: " + window.playerCellsId[legendmod.playerCells[i].id].historyMass[window.legendmod2.fps]);
                var j = i;
                var x = 0;

                MergeCells(j, x);

            } else {
                if (window.playerCellsId && window.legendmod.playerCells[i] && window.legendmod.playerCells[i].id && window.playerCellsId[legendmod.playerCells[i].id] &&
                    window.playerCellsId[legendmod.playerCells[i].id].historyMass) {
                    window.playerCellsId[legendmod.playerCells[i].id].mergeTime = null;
                }
            }

        }
    }
}

function MergeCells(j, x) {
    x++;
    if (window.legendmod.playerCells.length > 1 && window.playerCellsId && window.legendmod.playerCells[j] && window.legendmod.playerCells[j].id && window.playerCellsId[legendmod.playerCells[j].id]) {
        //window.playerCellsId[legendmod.playerCells[j].id].mergeTime = 29 + (7 / 300) * window.playerCellsId[legendmod.playerCells[j].id].historyMass[0] - x;
		window.playerCellsId[legendmod.playerCells[j].id].mergeTime = 29 + (8 / 300) * window.playerCellsId[legendmod.playerCells[j].id].historyMass[0] - x;
        //
        if (window.playerCellsId[legendmod.playerCells[j].id].mergeTime > -20) {
            setTimeout(function() {
                MergeCells(j, x);
				//console.log("Mass Merge: " + j, x, window.playerCellsId[legendmod.playerCells[j].id].historyMass[0]);
            }, 1000);
        }

    }
	else {
		//console.log("Mass Merge Timer ended: " + j, x);
                if (window.playerCellsId && window.legendmod.playerCells[j] && window.legendmod.playerCells[j].id && window.playerCellsId[legendmod.playerCells[j].id] &&
                    window.playerCellsId[legendmod.playerCells[j].id].historyMass) {
						window.playerCellsId[legendmod.playerCells[j].id].mergeTime = null;
					}
    }
    return j, x;
}
<|endoftext|>