<commit_before>var files = [];
var curidx = 0;

var playing = false;

var msgs = ['', '', '', '', ''];

function set_msg(str) {
    msgs[0] = msgs[1];
    msgs[1] = msgs[2];
    msgs[2] = msgs[3];
    msgs[3] = msgs[4];
    msgs[4] = str;
    document.getElementById('msg1').firstChild.nodeValue = msgs[0];
    document.getElementById('msg2').firstChild.nodeValue = msgs[1];
    document.getElementById('msg3').firstChild.nodeValue = msgs[2];
    document.getElementById('msg4').firstChild.nodeValue = msgs[3];
    document.getElementById('msg5').firstChild.nodeValue = msgs[4];
}

/* 場面に応じた画面を表示する。
 */
function screen_step(step)
{
    var div0 = document.getElementById('scanning');
    var div1 = document.getElementById('main');
    var div2 = document.getElementById('list');
    var div3 = document.getElementById('control');
    switch (step) {
    case 0:
	div0.style.display = 'block';
	div1.style.display = 'none';
	div2.style.display = 'none';
	div3.style.display = 'none';
	break;
    case 1:
	div0.style.display = 'none';
	div1.style.display = 'block';
	div2.style.display = 'none';
	div3.style.display = 'block';
	break;
    case 2:
	div0.style.display = 'none';
	div1.style.display = 'none';
	div2.style.display = 'block';
	div3.style.display = 'block';
	break;
    }
}

function cmp_files(f1, f2) {
    if (f1.name < f2.name)
	return -1;
    if (f1.name > f2.name)
	return 1;
    return 0;
}

var storage = navigator.getDeviceStorage('music');

/* curidx を local storage に保存。
 */
function save_cur() {
    localStorage.setItem('curidx', '' + curidx);
}

/* curidx を local storage から読み出す。
 */
function restore_cur() {
    var idx = localStorage.getItem('curidx');
    if (idx)
	curidx = idx * 1;	// "*1": 数値に変換
}

restore_cur();

/* そのまま再生。
 */
function play() {
    var audio = document.getElementById('audio');
    audio.play();
    playing = true;
}

/* curidx で示される曲を最初から再生。
 */
function play_cur() {
    if (files.length <= 0) {
	set_msg('No audio files.');
	alert('No audio files.');
	return;
    }

    if (curidx < 0 || curidx >= files.length) {
	set_msg('No such idx.' + curidx);
	curidx = 0;
    }

    var audio = document.getElementById('audio');
    set_msg('' + audio);
    audio.src = window.URL.createObjectURL(files[curidx]);
    set_msg('' + audio.src);
    audio.play();
    playing = true;
    audio.addEventListener('ended', play_next);

    save_cur();
}

function play_seek() {
    set_msg('play_seek: 0');
    var audio = document.getElementById('audio');

    set_msg('play_seek: 1: ' + this.value);
    audio.currentTime = this.value;
}

/* 前の曲を再生。
 */
function play_prev() {
    if (--curidx < 0)
	curidx = files.length - 1;
    play_cur();
}

/* 次の曲を再生。
 */
function play_next() {
    if (++curidx >= files.length)
	curidx = 0;
    play_cur();
}

function mrc_play() {
    set_msg('mrc play');
}

function mrc_pause() {
    set_msg('mrc pause');
}

function mrc_playpause() {
    set_msg('mrc playpause');
}

function mrc_updateplaystatus(e) {
    set_msg('mrc updateplaystatus: ' + e.detail['command']);
    if (playing)
	pause();
    else
	play();
}

function mrc_updatemetadata(e) {
    set_msg('mrc updatemetadata: ' + e.detail['command']);
    if (playing)
	pause();
}

/* 一時停止
 */
function pause() {
set_msg('stop1');
    var audio = document.getElementById('audio');
set_msg('stop2');
    audio.pause();
    playing = false;
set_msg('stop3');
}

var radio = navigator.mozFMRadio;

/* イヤホン挿抜で再生/停止。
 */
function play_or_stop() {
set_msg('r1');
    if (radio.antennaAvailable) {
set_msg('r2');
	play_cur();
set_msg('r3');
    } else {
set_msg('r4');
	pause();
set_msg('r5');
    }
}

radio.addEventListener('antennaavailablechange', play_or_stop);

/* 曲リストからファイルを選択すると、再生開始して
 * 画面を main に戻す。…ような関数を返す。
 * closure を使ってるので、ちょっと解りにくい。
 */
function play_on_click(id) {
    var mid = id;
    return function() {
	curidx = mid;
	play_cur();
	screen_step(1);
    }
}

/* 曲リストからディレクトリを選択すると、
 * そのディレクトリを展開/省略する。
 */
function expand_or_coarse_on_click(div) {
    var this_div = div;
    return function() {
	if (this_div.style.display == 'none') {
	    this_div.style.display = 'block';
	} else {
	    this_div.style.display = 'none';
	}
    }
}

/*
 * parent:
ノード or
 ノード
 * prefix: /.../ の文字列
 * idx: files[idx]
 */
function make_select_screen_iter(parent, prefix, idx)
{
    set_msg('make_select_screen_iter: 0');
    while (idx < files.length) {
	set_msg('make_select_screen_iter: idx=' + idx);

	if (files[idx].name.lastIndexOf(prefix, 0) != 0)	// if startsWith(prefix)
	    return idx;
	set_msg('make_select_screen_iter: prefix matches.');

	var slash = files[idx].name.indexOf('/', prefix.length);
	set_msg('make_select_screen_iter: slash=' + slash);
	if (slash == -1) {
	    // これ以上 '/' がない。
	    set_msg('make_select_screen_iter: 1');

	    var li = document.createElement("li");
	    parent.appendChild(li);

	    var a = document.createElement("a");
	    li.appendChild(a);
	    a.addEventListener('click', play_on_click(idx));

	    var fname = document.createTextNode(files[idx].name.substring(prefix.length));
	    a.appendChild(fname);

	    var br1 = document.createElement("br");
	    a.appendChild(br1);

	    var title = document.createTextNode('title');
	    a.appendChild(title);

	    var br2 = document.createElement("br");
	    a.appendChild(br2);

	    var artist = document.createTextNode('artist');
	    a.appendChild(artist);

	    idx++;
	    set_msg('make_select_screen_iter: 2');
	} else {
	    // '/' を発見。
	    set_msg('make_select_screen_iter: 3');

	    /* 以下のような感じに作る。
	     *
  directory name
	     *

	     *

	     *

	     *

	     */

	    var new_pfx = files[idx].name.substring(0, slash + 1);

	    var li = document.createElement("li");
	    parent.appendChild(li);

	    var a = document.createElement("a");
	    li.appendChild(a);

	    var txt = document.createTextNode(files[idx].name.slice(prefix.length, new_pfx.length - 1));
	    a.appendChild(txt);

	    var new_ul = document.createElement("ul");
	    parent.appendChild(new_ul);

	    var new_div = document.createElement("div");
	    new_ul.appendChild(new_div);
	    new_div.style.display = 'none';
	    a.addEventListener('click',
			       expand_or_coarse_on_click(new_div));

	    idx = make_select_screen_iter(new_div, new_pfx, idx);
	    set_msg('make_select_screen_iter: 4');
	}
	set_msg('make_select_screen_iter: 5');
    }
}

/* 曲選択画面を作る。
 */
function make_select_screen() {
    set_msg('make_select_screen: start.');
    set_msg('make_select_screen: 0.');

    // 削除
    var list = document.getElementById('list');
    set_msg('make_select_screen: 1.');
    var ul = list.getElementsByTagName('ul');
    set_msg('make_select_screen: 2.');
    if (ul && ul[0])
	list.removeChild(ul[0]);
    set_msg('make_select_screen: 3.');

    // 作成
    ul = document.createElement("ul");
    make_select_screen_iter(ul, '/sdcard/Music/', 0);
    document.getElementById("list").appendChild(ul);

    screen_step(2);
    set_msg('make_select_screen: done.');
}

/* 曲選択画面から戻る。
 */
function cancel_select_screen() {
    set_msg('cancel_select_screen: start.');
    screen_step(1);
    set_msg('cancel_select_screen: done.');
}

window.onload = function() {
    set_msg('onload0');
    var seekbar = document.getElementById('seekbar');
    set_msg('onload1');
    seekbar.addEventListener('change', play_seek, false);
    set_msg('onload2');

    var audio = document.getElementById('audio');
    audio.addEventListener('timeupdate', function() {
	seekbar.value = audio.currentTime;
    });
    audio.addEventListener('loadedmetadata', function() {
	seekbar.max = audio.duration;
    });

    set_msg('onload0');
    var sel = document.getElementById('prev')
    set_msg('onload1');
    sel.addEventListener('click', play_prev, false);
    set_msg('onload2');

    set_msg('onload0');
    var sel = document.getElementById('play')
    set_msg('onload1');
    sel.addEventListener('click', play, false);
    set_msg('onload2');

    set_msg('onload0');
    var sel = document.getElementById('pause')
    set_msg('onload1');
    sel.addEventListener('click', pause, false);
    set_msg('onload2');

    set_msg('onload3');
    var sel = document.getElementById('next')
    set_msg('onload4');
    sel.addEventListener('click', play_next, false);
    set_msg('onload5');

    set_msg('onload6');
    var sel = document.getElementById('select')
    set_msg('onload7');
    sel.addEventListener('click', make_select_screen, false);
    set_msg('onload8');

    set_msg('onload9');
    var sel = document.getElementById('select_cancel')
    set_msg('onload10');
    sel.addEventListener('click', cancel_select_screen, false);
    set_msg('onload11');

    var mrc = new MediaRemoteControls();
    set_msg('onload12');
    mrc.addCommandListener('play', mrc_play);
    mrc.addCommandListener('pause', mrc_pause);
    mrc.addCommandListener('playpause', mrc_playpause);
    mrc.addCommandListener('updateplaystatus', mrc_updateplaystatus);
    mrc.addCommandListener('updatemetadata', mrc_updatemetadata);
    mrc.start();
    set_msg('onload13');

    if (storage) {
	var cursor = storage.enumerate();
	cursor.onsuccess = function() {
	    if (this.result) {
		var file = this.result;
		files.push(file);
		this.continue();
	    } else {
		set_msg('sort');
		files.sort(cmp_files);
		set_msg('done.');

		// audio の src をセット
		play_cur();
		pause();

		screen_step(1);
	    }
	}
	cursor.onerror = function() {
	    set_msg('enumerate error.');
	    alert('enumerate error.');
	}
    } else {
	set_msg('No music storage.');
	alert('No music storage.');
    }
};
<commit_msg><audio> でなく new Audio() に移行。<commit_after>var files = [];
var curidx = 0;
var audio;

var playing = false;

var msgs = ['', '', '', '', ''];

function set_msg(str) {
    msgs[0] = msgs[1];
    msgs[1] = msgs[2];
    msgs[2] = msgs[3];
    msgs[3] = msgs[4];
    msgs[4] = str;
    document.getElementById('msg1').firstChild.nodeValue = msgs[0];
    document.getElementById('msg2').firstChild.nodeValue = msgs[1];
    document.getElementById('msg3').firstChild.nodeValue = msgs[2];
    document.getElementById('msg4').firstChild.nodeValue = msgs[3];
    document.getElementById('msg5').firstChild.nodeValue = msgs[4];
}

/* 場面に応じた画面を表示する。
 */
function screen_step(step)
{
    var div0 = document.getElementById('scanning');
    var div1 = document.getElementById('main');
    var div2 = document.getElementById('list');
    var div3 = document.getElementById('control');
    switch (step) {
    case 0:
	div0.style.display = 'block';
	div1.style.display = 'none';
	div2.style.display = 'none';
	div3.style.display = 'none';
	break;
    case 1:
	div0.style.display = 'none';
	div1.style.display = 'block';
	div2.style.display = 'none';
	div3.style.display = 'block';
	break;
    case 2:
	div0.style.display = 'none';
	div1.style.display = 'none';
	div2.style.display = 'block';
	div3.style.display = 'block';
	break;
    }
}

function cmp_files(f1, f2) {
    if (f1.name < f2.name)
	return -1;
    if (f1.name > f2.name)
	return 1;
    return 0;
}

var storage = navigator.getDeviceStorage('music');

/* curidx を local storage に保存。
 */
function save_cur() {
    localStorage.setItem('curidx', '' + curidx);
}

/* curidx を local storage から読み出す。
 */
function restore_cur() {
    var idx = localStorage.getItem('curidx');
    if (idx)
	curidx = idx * 1;	// "*1": 数値に変換
}

restore_cur();

/* そのまま再生。
 */
function play() {
    audio.play();
    playing = true;
}

/* curidx で示される曲を最初から再生。
 */
function play_cur() {
    if (files.length <= 0) {
	set_msg('No audio files.');
	alert('No audio files.');
	return;
    }

    if (curidx < 0 || curidx >= files.length) {
	set_msg('No such idx.' + curidx);
	curidx = 0;
    }

    set_msg('' + audio);
    audio.src = window.URL.createObjectURL(files[curidx]);
    set_msg('' + audio.src);
    audio.play();
    playing = true;
    audio.addEventListener('ended', play_next);

    save_cur();
}

function play_seek() {
    set_msg('play_seek: 0');

    set_msg('play_seek: 1: ' + this.value);
    audio.currentTime = this.value;
}

/* 前の曲を再生。
 */
function play_prev() {
    if (--curidx < 0)
	curidx = files.length - 1;
    play_cur();
}

/* 次の曲を再生。
 */
function play_next() {
    if (++curidx >= files.length)
	curidx = 0;
    play_cur();
}

function mrc_play() {
    set_msg('mrc play');
}

function mrc_pause() {
    set_msg('mrc pause');
}

function mrc_playpause() {
    set_msg('mrc playpause');
}

function mrc_updateplaystatus(e) {
    set_msg('mrc updateplaystatus: ' + e.detail['command']);
    if (playing)
	pause();
    else
	play();
}

function mrc_updatemetadata(e) {
    set_msg('mrc updatemetadata: ' + e.detail['command']);
    if (playing)
	pause();
}

/* 一時停止
 */
function pause() {
set_msg('stop1');
set_msg('stop2');
    audio.pause();
    playing = false;
set_msg('stop3');
}

var radio = navigator.mozFMRadio;

/* イヤホン挿抜で再生/停止。
 */
function play_or_stop() {
set_msg('r1');
    if (radio.antennaAvailable) {
set_msg('r2');
	play_cur();
set_msg('r3');
    } else {
set_msg('r4');
	pause();
set_msg('r5');
    }
}

radio.addEventListener('antennaavailablechange', play_or_stop);

/* 曲リストからファイルを選択すると、再生開始して
 * 画面を main に戻す。…ような関数を返す。
 * closure を使ってるので、ちょっと解りにくい。
 */
function play_on_click(id) {
    var mid = id;
    return function() {
	curidx = mid;
	play_cur();
	screen_step(1);
    }
}

/* 曲リストからディレクトリを選択すると、
 * そのディレクトリを展開/省略する。
 */
function expand_or_coarse_on_click(div) {
    var this_div = div;
    return function() {
	if (this_div.style.display == 'none') {
	    this_div.style.display = 'block';
	} else {
	    this_div.style.display = 'none';
	}
    }
}

/*
 * parent:
ノード or
 ノード
 * prefix: /.../ の文字列
 * idx: files[idx]
 */
function make_select_screen_iter(parent, prefix, idx)
{
    set_msg('make_select_screen_iter: 0');
    while (idx < files.length) {
	set_msg('make_select_screen_iter: idx=' + idx);

	if (files[idx].name.lastIndexOf(prefix, 0) != 0)	// if startsWith(prefix)
	    return idx;
	set_msg('make_select_screen_iter: prefix matches.');

	var slash = files[idx].name.indexOf('/', prefix.length);
	set_msg('make_select_screen_iter: slash=' + slash);
	if (slash == -1) {
	    // これ以上 '/' がない。
	    set_msg('make_select_screen_iter: 1');

	    var li = document.createElement("li");
	    parent.appendChild(li);

	    var a = document.createElement("a");
	    li.appendChild(a);
	    a.addEventListener('click', play_on_click(idx));

	    var fname = document.createTextNode(files[idx].name.substring(prefix.length));
	    a.appendChild(fname);

	    var br1 = document.createElement("br");
	    a.appendChild(br1);

	    var title = document.createTextNode('title');
	    a.appendChild(title);

	    var br2 = document.createElement("br");
	    a.appendChild(br2);

	    var artist = document.createTextNode('artist');
	    a.appendChild(artist);

	    idx++;
	    set_msg('make_select_screen_iter: 2');
	} else {
	    // '/' を発見。
	    set_msg('make_select_screen_iter: 3');

	    /* 以下のような感じに作る。
	     *
  directory name
	     *

	     *

	     *

	     *

	     */

	    var new_pfx = files[idx].name.substring(0, slash + 1);

	    var li = document.createElement("li");
	    parent.appendChild(li);

	    var a = document.createElement("a");
	    li.appendChild(a);

	    var txt = document.createTextNode(files[idx].name.slice(prefix.length, new_pfx.length - 1));
	    a.appendChild(txt);

	    var new_ul = document.createElement("ul");
	    parent.appendChild(new_ul);

	    var new_div = document.createElement("div");
	    new_ul.appendChild(new_div);
	    new_div.style.display = 'none';
	    a.addEventListener('click',
			       expand_or_coarse_on_click(new_div));

	    idx = make_select_screen_iter(new_div, new_pfx, idx);
	    set_msg('make_select_screen_iter: 4');
	}
	set_msg('make_select_screen_iter: 5');
    }
}

/* 曲選択画面を作る。
 */
function make_select_screen() {
    set_msg('make_select_screen: start.');
    set_msg('make_select_screen: 0.');

    // 削除
    var list = document.getElementById('list');
    set_msg('make_select_screen: 1.');
    var ul = list.getElementsByTagName('ul');
    set_msg('make_select_screen: 2.');
    if (ul && ul[0])
	list.removeChild(ul[0]);
    set_msg('make_select_screen: 3.');

    // 作成
    ul = document.createElement("ul");
    make_select_screen_iter(ul, '/sdcard/Music/', 0);
    document.getElementById("list").appendChild(ul);

    screen_step(2);
    set_msg('make_select_screen: done.');
}

/* 曲選択画面から戻る。
 */
function cancel_select_screen() {
    set_msg('cancel_select_screen: start.');
    screen_step(1);
    set_msg('cancel_select_screen: done.');
}

window.onload = function() {
    set_msg('onload0');
    var seekbar = document.getElementById('seekbar');
    set_msg('onload1');
    seekbar.addEventListener('change', play_seek, false);
    set_msg('onload2');

    audio = new Audio();
    audio.mozAudioChannelType = 'content';
    audio.addEventListener('timeupdate', function() {
	seekbar.value = audio.currentTime;
    });
    audio.addEventListener('loadedmetadata', function() {
	seekbar.max = audio.duration;
    });

    set_msg('onload0');
    var sel = document.getElementById('prev')
    set_msg('onload1');
    sel.addEventListener('click', play_prev, false);
    set_msg('onload2');

    set_msg('onload0');
    var sel = document.getElementById('play')
    set_msg('onload1');
    sel.addEventListener('click', play, false);
    set_msg('onload2');

    set_msg('onload0');
    var sel = document.getElementById('pause')
    set_msg('onload1');
    sel.addEventListener('click', pause, false);
    set_msg('onload2');

    set_msg('onload3');
    var sel = document.getElementById('next')
    set_msg('onload4');
    sel.addEventListener('click', play_next, false);
    set_msg('onload5');

    set_msg('onload6');
    var sel = document.getElementById('select')
    set_msg('onload7');
    sel.addEventListener('click', make_select_screen, false);
    set_msg('onload8');

    set_msg('onload9');
    var sel = document.getElementById('select_cancel')
    set_msg('onload10');
    sel.addEventListener('click', cancel_select_screen, false);
    set_msg('onload11');

    var mrc = new MediaRemoteControls();
    set_msg('onload12');
    mrc.addCommandListener('play', mrc_play);
    mrc.addCommandListener('pause', mrc_pause);
    mrc.addCommandListener('playpause', mrc_playpause);
    mrc.addCommandListener('updateplaystatus', mrc_updateplaystatus);
    mrc.addCommandListener('updatemetadata', mrc_updatemetadata);
    mrc.start();
    set_msg('onload13');

    if (storage) {
	var cursor = storage.enumerate();
	cursor.onsuccess = function() {
	    if (this.result) {
		var file = this.result;
		files.push(file);
		this.continue();
	    } else {
		set_msg('sort');
		files.sort(cmp_files);
		set_msg('done.');

		// audio の src をセット
		play_cur();
		pause();

		screen_step(1);
	    }
	}
	cursor.onerror = function() {
	    set_msg('enumerate error.');
	    alert('enumerate error.');
	}
    } else {
	set_msg('No music storage.');
	alert('No music storage.');
    }
};
<|endoftext|>


<commit_before>/* Minecraft Server Status Checker V2.2

Copyright (c) 2014 Jeremy Lam (JLChnToZ)

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. */
$(function() {
  var allmodes = [
    ["legacy_ping", "ping"],
    ["full_query", "basic_query"]
  ],
    done = 0,
    lang = new Lang('en'),
    searchquery = location.search;

  function onSubmit(form, newstate) {
    if (history.pushState && newstate) {
      var host = $("#id_host").val(),
        port = $("#id_port").val();
      var _state = {
        host: host,
        port: port
      };
      if(!_.isEqual(history.state, _state))
        history.pushState(_state, 'request: ' + host + ':' + port, '?' + host + ':' + port);
    }
    $("#querybutton").button('loading');
    var called = false;
    $(".info").fadeOut("slow", function() {
      if (!called) called = true;
      else return;
      $(".val, #players, #pluginscontent").empty();
      $("#servericon, .nfo, #infoplayers, #pluginscontent0, #pluginscontent1, #pluginscontent2").hide();
      $("#noplugins, #noplayers").show();
      done = 0;
      tryRequest(form.serialize(), 0, 0);
      setTimeout(function() {
        tryRequest(form.serialize(), 1, 0);
      }, 2500);
    });
  }

  function tryRequest(form, mode, trial) {
    $.getJSON("json.php", form + "&mode=" + allmodes[mode][trial], function(x, h, r) {
      if (x.err || x == false) return;
      $(".info").each(function(i) {
        $(this).delay(i * 250).fadeIn("slow");
      });
      $("#infotitle").text((x.ip ? x.ip : $("#id_host").val()) + ":" + $("#id_port").val());
      showcontent("#motd", x.motd, 0);
      showcontent("#sversion", x.server_version, -1);
      showcontent("#latency", x.latency, -1);
      showcontent("#map", x.map, -1);
      showcontent("#gametype", x.gametype, -1);
      if (x.plugins && x.plugins.length > 0) {
        $("#noplugins").hide();
        $("#pluginscontent").show();
        var arr = x.plugins.split(";");
        for (var i = 0; i < arr.length; i++)
        $("#pluginscontent").append($("

").addClass("col-xs-12 col-sm-6 col-lg-4").text(arr[i]).hide().delay(i * 100).fadeIn("slow"));
      }
      if (x.icon && x.icon.length > 0) $("#servericon").attr("src", x.icon).fadeIn("slow");
      if (x.player_count || x.player_max || x.player_count === 0 || x.player_max === 0) {
        $("#infoplayers").show();
        $("#pmax").toggle(x.player_count >= x.player_max);
        $("#pcount").toggle(x.player_count < x.player_max).text(x.player_count ? x.player_count : '?');
        $("#pcountmax").text(x.player_max ? x.player_max : '?');
      }
      if (x.players && x.players.length > 0) {
        $("#noplayers").hide();
        $("#players").fadeOut("fast").empty().fadeIn("fast", function() {
          for (var i = 0; i < x.players.length; i++) {
            var skin = $("

").addClass("mc-skin").attr("data-minecraft-username", x.players[i]),
              name = $("").addClass("label label-default").text(x.players[i]).minecraftFormat(15),
              playerdiv = $("

").addClass("player").append(skin).append(name).hide().delay(i * 100).fadeIn("slow");
            $("#players").append(playerdiv);
          }
          $(".mc-skin").minecraftSkin({
            scale: 2,
            hat: true
          });
        });
      }
    }).complete(function(x, s) {
      if (trial + 1 < allmodes[mode].length) setTimeout(function() {
        tryRequest(form, mode, trial + 1);
      }, 5000);
      else callDone();
    });
  }

  function callDone() {
    done++;
    if (done >= allmodes.length) $("#querybutton").button('reset');
  }

  function showcontent(id, content, formatColor) {
    var $target = $(id);
    var $child = $target.children(".val");
    if (content && content.toString().length > 0) {
      $target.show();
      $child.text(content);
      if (formatColor >= 0) $child.minecraftFormat(formatColor);
    }
    return $child;
  }

  function autoload(query) {
    if (typeof(query) == "string" && query.length > 0) {
      var q = query.split(":");
      query = {
        host: q[0],
        port: q[1] ? q[1] : 25565
      };
    } else if (!query) return;
    $("#id_host").val(query['host']);
    $("#id_port").val(query['port']);
    onSubmit($("#requestform"), false);
    return query;
  }

  $("#requestform").submit(function(e) {
    e.preventDefault();
    onSubmit($(this), true);
  });

  $(".changelang").each(function() {
    var $this = $(this), langcode = $this.attr("href").substring(1);
    if(lang.defaultLang != langcode)
      lang.dynamic(langcode, $this.attr("data-lang-path"));
  }).click(function(e) {
    e.preventDefault();
    lang.change($(this).attr("href").substring(1));
  });

  window.onpopstate = function(e) {
    autoload(e.state);
  };

  if (searchquery && searchquery.length > 1) {
    var q = autoload(searchquery.substring(1));
    if(history.replaceState)
      history.replaceState(q, 'request: ' + q.host + ':' + q.port, '?' + q.host + ':' + q.port);
  }
});<commit_msg>Minor fixes<commit_after>/* Minecraft Server Status Checker V2.2

Copyright (c) 2014 Jeremy Lam (JLChnToZ)

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. */
$(function() {
  var allmodes = [
    ["legacy_ping", "ping"],
    ["full_query", "basic_query"]
  ],
    done = 0,
    lang = new Lang('en'),
    searchquery = location.search;

  function onSubmit(form, newstate) {
    if (history.pushState && newstate) {
      var host = $("#id_host").val(),
        port = $("#id_port").val();
      var _state = {
        host: host,
        port: port
      };
      if(!_.isEqual(history.state, _state))
        history.pushState(_state, 'request: ' + host + ':' + port, '?' + host + ':' + port);
    }
    $("#querybutton").button('loading');
    var called = false;
    $(".info").fadeOut("slow", function() {
      if (!called) called = true;
      else return;
      $(".val, #players, #pluginscontent").empty();
      $("#servericon, .nfo, #infoplayers, #pluginscontent").hide();
      $("#noplugins, #noplayers").show();
      done = 0;
      tryRequest(form.serialize(), 0, 0);
      setTimeout(function() {
        tryRequest(form.serialize(), 1, 0);
      }, 2500);
    });
  }

  function tryRequest(form, mode, trial) {
    $.getJSON("json.php", form + "&mode=" + allmodes[mode][trial], function(x, h, r) {
      if (x.err || x == false) return;
      $(".info").each(function(i) {
        $(this).delay(i * 250).fadeIn("slow");
      });
      $("#infotitle").text((x.ip ? x.ip : $("#id_host").val()) + ":" + $("#id_port").val());
      showcontent("#motd", x.motd, 0);
      showcontent("#sversion", x.server_version, -1);
      showcontent("#latency", x.latency, -1);
      showcontent("#map", x.map, -1);
      showcontent("#gametype", x.gametype, -1);
      if (x.plugins && x.plugins.length > 0) {
        $("#noplugins").hide();
        $("#pluginscontent").show();
        var arr = x.plugins.split(";");
        for (var i = 0; i < arr.length; i++)
          $("#pluginscontent").append($("

").addClass("col-xs-12 col-sm-6 col-lg-4").text(arr[i])
            .hide().delay(i * 100).fadeIn("slow"));
      }
      if (x.icon && x.icon.length > 0) $("#servericon").attr("src", x.icon).fadeIn("slow");
      if (x.player_count || x.player_max || x.player_count === 0 || x.player_max === 0) {
        $("#infoplayers").show();
        $("#pmax").toggle(x.player_count >= x.player_max);
        $("#pcount").toggle(x.player_count < x.player_max).text(x.player_count ? x.player_count : '?');
        $("#pcountmax").text(x.player_max ? x.player_max : '?');
      }
      if (x.players && x.players.length > 0) {
        $("#noplayers").hide();
        $("#players").fadeOut("fast").empty().fadeIn("fast", function() {
          for (var i = 0; i < x.players.length; i++)
            $("#players").append(
              $("

").addClass("player").append(
                $("

").addClass("mc-skin").attr("data-minecraft-username", x.players[i])
              ).append(
                $("").addClass("label label-default").text(x.players[i]).minecraftFormat(15)
              ).hide().delay(i * 100).fadeIn("slow")
            );
          $(".mc-skin").minecraftSkin({
            scale: 2,
            hat: true
          });
        });
      }
    }).complete(function(x, s) {
      if (trial + 1 < allmodes[mode].length) setTimeout(function() {
        tryRequest(form, mode, trial + 1);
      }, 5000);
      else callDone();
    });
  }

  function callDone() {
    done++;
    if (done >= allmodes.length) $("#querybutton").button('reset');
  }

  function showcontent(id, content, formatColor) {
    var $target = $(id);
    var $child = $target.children(".val");
    if (content && content.toString().length > 0) {
      $target.show();
      $child.text(content);
      if (formatColor >= 0) $child.minecraftFormat(formatColor);
    }
    return $child;
  }

  function autoload(query) {
    if (typeof(query) == "string" && query.length > 0) {
      var q = query.split(":");
      query = {
        host: q[0],
        port: q[1] ? q[1] : 25565
      };
    } else if (!query) return;
    $("#id_host").val(query['host']);
    $("#id_port").val(query['port']);
    onSubmit($("#requestform"), false);
    return query;
  }

  $("#requestform").submit(function(e) {
    e.preventDefault();
    onSubmit($(this), true);
  });

  $(".changelang").each(function() {
    var $this = $(this), langcode = $this.attr("href").substring(1);
    if(lang.defaultLang != langcode)
      lang.dynamic(langcode, $this.attr("data-lang-path"));
  }).click(function(e) {
    e.preventDefault();
    lang.change($(this).attr("href").substring(1));
  });

  window.onpopstate = function(e) {
    autoload(e.state);
  };

  if (searchquery && searchquery.length > 1) {
    var q = autoload(searchquery.substring(1));
    if(history.replaceState)
      history.replaceState(q, 'request: ' + q.host + ':' + q.port, '?' + q.host + ':' + q.port);
  }
});<|endoftext|>


<commit_before>var play_state = {

    /**
     * Creates the game world using the preloaded sprites
     *
     * @return {undefined}
     */
    create: function() {
        this.game.physics.startSystem(Phaser.Physics.ARCADE);
        this.game.add.sprite(0, 0, 'sky');

        this.platforms = game.add.group();
        this.platforms.enableBody = true;

        this.createFloor();

        this.createLargePlatform(600, 300);
        this.createSmallPlatform(230, 240);
        this.createSmallPlatform(100, 400);

        // Stars to collect
        this.stars = game.add.group();
        this.stars.enableBody = true;

        this.starBurst();

        // My player
        this.player = game.add.sprite(32, game.world.height - 150, 'dude');
        this.game.physics.arcade.enable(this.player);

        // Giving him some bounce
        this.player.body.bounce.y = 0.4;
        this.player.body.gravity.y = 300;
        this.player.body.collideWorldBounds = true;

        // He's ALIVE (animation)!
        // Note: Lookup flipping sprites
        this.player.animations.add('left', [0, 1, 2, 3], 10, true);
        this.player.animations.add('right', [5, 6, 7, 8], 10, true);

        // The crazy sphere
        this.sphere = game.add.sprite(32, game.world.height - 250, 'sphere');
        this.game.physics.enable(this.sphere, Phaser.Physics.ARCADE);
        this.sphere.body.velocity.x = 100;
        this.sphere.body.velocity.y = 100;
        this.sphere.body.collideWorldBounds = true;
        this.sphere.body.bounce.set(1);

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

        this.scoreText = game.add.text(16, 16, 'score: 0', {fontSize: '32px', fill: '#000'});

        this.music = game.add.audio('awesome');
        this.music.play('', 0, 1, true);
    },

    /**
     * Game drawhandler that gets updated at regular intervals
     * @return {undefined}
     */
    update: function() {
        this.game.physics.arcade.collide(this.player, this.platforms);

        // We need this or the stars just go falling through the floor - funny but not useful
        this.game.physics.arcade.collide(this.stars, this.platforms);

        // Bouncy sphere
        this.game.physics.arcade.collide(this.sphere, this.platforms);
        this.game.physics.arcade.collide(this.sphere, this.player, this.sphereTouch, null, this);

        // Make the guy stay still when nowts being pressed
        this.player.body.velocity.x = 0;

        // Enables player to collect stars "collectStar" is the callback function
        this.game.physics.arcade.overlap(this.player, this.stars, this.collectStar, null, this);

        // The sphere will start eating stars after it has been hit twice
        this.game.physics.arcade.collide(this.sphere, this.stars, this.eatStar, null, this);

        // Sorting out left, right and stop
        if (this.cursors.left.isDown){
            this.player.body.velocity.x = -150;
            this.player.animations.play('left');
        }else if(this.cursors.right.isDown){
            this.player.body.velocity.x = 150;
            this.player.animations.play('right');
        }else{
            this.player.animations.stop();
            this.player.frame = 4;
        }

        // JUMP!
        if(this.cursors.up.isDown && this.player.body.touching.down){
            this.player.body.velocity.y = -350;
        }

    },

    /**
     * Event handler for when the player touches a star - collecting it.
     * Will update the score globally and the scoreboard on screen.
     *
     * @param  {object} player  sprite
     * @param  {object} star    sprite
     * @return {undefined}
     */
    collectStar: function(player, star){
        star.kill();

        score++;
        if (score >= 10) {
            this.game.state.start('win');
        }
        this.scoreText.text = 'Score: ' + score;
    },

    /**
     * Event handler for when the sphere/orb touches a star. Checks if its been
     *  hit by player more than 5 times and if it has then it will eat the
     * star, turning red to show its blood thirsty nature.
     *
     * @param  {object} sphere sprite
     * @param  {object} star   sprite
     * @return {undefined}
     */
    eatStar: function(sphere, star){
        if(sphereHit >= 5){
            sphere.tint = 0xff0000;
            star.kill();
            console.log('Eating stars?');
            score--;
            this.scoreText.text = 'Score: ' + score;
        }
    },

    /**
     * Event handler for when the sphere/globe is touched by player. This will
     * cause a burst of stars and increment sphereHit counter.
     *
     * @param  {object} sphere sprite
     * @param  {object} player sprite
     * @return {undefined}
     */
    sphereTouch: function(sphere, player){
        sphereHit++;
        this.starBurst();
    },

    /**
     * Drops 12 stars from the top of the level screen
     *
     * @return {undefined}
     */
    starBurst: function(){
        // Stars to collect
        for (var i = 0; i < 12; i++) {
            this.star = this.stars.create(i * 70, 0, 'star');
            // Let them fall is a lot easier than placing them so as to avoid being
            // put inside objects I guess?
            this.star.body.gravity.y = 300;

            this.star.body.bounce.y = 0.7 + Math.random() * 0.2;
        }
    },

    createFloor: function() {
        var i = 0;
        for(i=0;i<7;i++){
            this.ground = this.platforms.create((128*i), game.world.height - 64, 'ground1');
            this.ground.scale.setTo(1, 1);
            this.ground.body.immovable = true;
        }
    },

    createSmallPlatform: function(x, y) {
        this.ledge = this.platforms.create(x, y, 'platforml');
        this.setScaleAndSolid(this.ledge);

        this.ledge = this.platforms.create(x+60, y, 'platformr');
        this.setScaleAndSolid(this.ledge);
    },

    createLargePlatform: function(x, y) {
        this.ledge = this.platforms.create(x, y, 'platform');
        this.setScaleAndSolid(this.ledge);
        this.ledge = this.platforms.create((x+60), y, 'platformr');
        this.setScaleAndSolid(this.ledge);
        this.ledge = this.platforms.create((x-60), y, 'platforml');
        this.setScaleAndSolid(this.ledge);
    },

    setScaleAndSolid: function(thing, scale){
        if(!scale){
            scale = 0.5;
        }
        thing.scale.setTo(scale, scale);
        thing.body.immovable = true;
    }
};<commit_msg>Changign scale setting to default parameter method<commit_after>var play_state = {

    /**
     * Creates the game world using the preloaded sprites
     *
     * @return {undefined}
     */
    create: function() {
        this.game.physics.startSystem(Phaser.Physics.ARCADE);
        this.game.add.sprite(0, 0, 'sky');

        this.platforms = game.add.group();
        this.platforms.enableBody = true;

        this.createFloor();

        this.createLargePlatform(600, 300);
        this.createSmallPlatform(230, 240);
        this.createSmallPlatform(100, 400);

        // Stars to collect
        this.stars = game.add.group();
        this.stars.enableBody = true;

        this.starBurst();

        // My player
        this.player = game.add.sprite(32, game.world.height - 150, 'dude');
        this.game.physics.arcade.enable(this.player);

        // Giving him some bounce
        this.player.body.bounce.y = 0.4;
        this.player.body.gravity.y = 300;
        this.player.body.collideWorldBounds = true;

        // He's ALIVE (animation)!
        // Note: Lookup flipping sprites
        this.player.animations.add('left', [0, 1, 2, 3], 10, true);
        this.player.animations.add('right', [5, 6, 7, 8], 10, true);

        // The crazy sphere
        this.sphere = game.add.sprite(32, game.world.height - 250, 'sphere');
        this.game.physics.enable(this.sphere, Phaser.Physics.ARCADE);
        this.sphere.body.velocity.x = 100;
        this.sphere.body.velocity.y = 100;
        this.sphere.body.collideWorldBounds = true;
        this.sphere.body.bounce.set(1);

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

        this.scoreText = game.add.text(16, 16, 'score: 0', {fontSize: '32px', fill: '#000'});

        this.music = game.add.audio('awesome');
        this.music.play('', 0, 1, true);
    },

    /**
     * Game drawhandler that gets updated at regular intervals
     * @return {undefined}
     */
    update: function() {
        this.game.physics.arcade.collide(this.player, this.platforms);

        // We need this or the stars just go falling through the floor - funny but not useful
        this.game.physics.arcade.collide(this.stars, this.platforms);

        // Bouncy sphere
        this.game.physics.arcade.collide(this.sphere, this.platforms);
        this.game.physics.arcade.collide(this.sphere, this.player, this.sphereTouch, null, this);

        // Make the guy stay still when nowts being pressed
        this.player.body.velocity.x = 0;

        // Enables player to collect stars "collectStar" is the callback function
        this.game.physics.arcade.overlap(this.player, this.stars, this.collectStar, null, this);

        // The sphere will start eating stars after it has been hit twice
        this.game.physics.arcade.collide(this.sphere, this.stars, this.eatStar, null, this);

        // Sorting out left, right and stop
        if (this.cursors.left.isDown){
            this.player.body.velocity.x = -150;
            this.player.animations.play('left');
        }else if(this.cursors.right.isDown){
            this.player.body.velocity.x = 150;
            this.player.animations.play('right');
        }else{
            this.player.animations.stop();
            this.player.frame = 4;
        }

        // JUMP!
        if(this.cursors.up.isDown && this.player.body.touching.down){
            this.player.body.velocity.y = -350;
        }

    },

    /**
     * Event handler for when the player touches a star - collecting it.
     * Will update the score globally and the scoreboard on screen.
     *
     * @param  {object} player  sprite
     * @param  {object} star    sprite
     * @return {undefined}
     */
    collectStar: function(player, star){
        star.kill();

        score++;
        if (score >= 10) {
            this.game.state.start('win');
        }
        this.scoreText.text = 'Score: ' + score;
    },

    /**
     * Event handler for when the sphere/orb touches a star. Checks if its been
     *  hit by player more than 5 times and if it has then it will eat the
     * star, turning red to show its blood thirsty nature.
     *
     * @param  {object} sphere sprite
     * @param  {object} star   sprite
     * @return {undefined}
     */
    eatStar: function(sphere, star){
        if(sphereHit >= 5){
            sphere.tint = 0xff0000;
            star.kill();
            console.log('Eating stars?');
            score--;
            this.scoreText.text = 'Score: ' + score;
        }
    },

    /**
     * Event handler for when the sphere/globe is touched by player. This will
     * cause a burst of stars and increment sphereHit counter.
     *
     * @param  {object} sphere sprite
     * @param  {object} player sprite
     * @return {undefined}
     */
    sphereTouch: function(sphere, player){
        sphereHit++;
        this.starBurst();
    },

    /**
     * Drops 12 stars from the top of the level screen
     *
     * @return {undefined}
     */
    starBurst: function(){
        // Stars to collect
        for (var i = 0; i < 12; i++) {
            this.star = this.stars.create(i * 70, 0, 'star');
            // Let them fall is a lot easier than placing them so as to avoid being
            // put inside objects I guess?
            this.star.body.gravity.y = 300;

            this.star.body.bounce.y = 0.7 + Math.random() * 0.2;
        }
    },

    createFloor: function() {
        var i = 0;
        for(i=0;i<7;i++){
            this.ground = this.platforms.create((128*i), game.world.height - 64, 'ground1');
            this.ground.scale.setTo(1, 1);
            this.ground.body.immovable = true;
        }
    },

    createSmallPlatform: function(x, y) {
        this.ledge = this.platforms.create(x, y, 'platforml');
        this.setScaleAndSolid(this.ledge);

        this.ledge = this.platforms.create(x+60, y, 'platformr');
        this.setScaleAndSolid(this.ledge);
    },

    createLargePlatform: function(x, y) {
        this.ledge = this.platforms.create(x, y, 'platform');
        this.setScaleAndSolid(this.ledge);
        this.ledge = this.platforms.create((x+60), y, 'platformr');
        this.setScaleAndSolid(this.ledge);
        this.ledge = this.platforms.create((x-60), y, 'platforml');
        this.setScaleAndSolid(this.ledge);
    },

    setScaleAndSolid: function(thing, scale){
        scale = typeof scale !== 'undefined' ? scale : 0.5;
        thing.scale.setTo(scale, scale);
        thing.body.immovable = true;
    }
};<|endoftext|>


<commit_before>var pull = require('pull-stream')
var crypto = require('crypto')
var Reconnect = require('pull-reconnect')

function Hash (onHash) {
  var hash = crypto.createHash('sha256')
  return pull.through(function (data) {
    hash.update(
        'string' === typeof data
      ? new Buffer(data, 'utf8')
      : data
    )
  }, function (err) {
    if(err && !onHash) throw err
    onHash && onHash(err, '&'+hash.digest('base64')+'.sha256')
  })
}
var createClient = require('ssb-lite')
//var createClient = require('ssb-client')
var createConfig = require('ssb-config/inject')
//var createClient = require('./lite')
var createFeed   = require('ssb-feed')
var keys = require('./keys')

module.exports = function () {
  var opts = createConfig()
  var sbot = null

  var rec = Reconnect(function (isConn) {
    createClient(keys, opts, function (err, _sbot) {
      if(err) {console.error(err.stack); isConn(err)}
      sbot = _sbot
      sbot.on('closed', function () {
        sbot = null
        isConn(new Error('closed'))
      })
      isConn()
    })
  })

  var internal = {
    getLatest: rec.async(function (id, cb) {
      sbot.getLatest(id, cb)
    }),
    add: rec.async(function (msg, cb) {
      sbot.add(msg, cb)
    })
  }

  var feed = createFeed(internal, keys)

  return {
    sbot_blobs_add: rec.sink(function (cb) {
      return pull(
        Hash(cb),
        sbot.blobs.add()
      )
    }),
    sbot_links: rec.source(function (query) {
      return sbot.links(query)
    }),
    sbot_links2: rec.source(function (query) {
      return sbot.links2.read(query)
    }),
    sbot_query: rec.source(function (query) {
      return sbot.query.read(query)
    }),
    sbot_log: rec.source(function (opts) {
      return sbot.createLogStream(opts)
    }),
    sbot_user_feed: rec.source(function (opts) {
      return sbot.createUserStream(opts)
    }),
    sbot_get: rec.async(function (key, cb) {
      sbot.get(key, cb)
    }),
    sbot_publish: rec.async(function (msg, cb) {
      feed.add(msg, function (err, msg) {
        cb(err, msg)
      })
    }),
    sbot_whoami: rec.async(function (cb) {
      sbot.whoami(cb)
    })
  }
}

<commit_msg>disable until ssb-lite is ready<commit_after>var pull = require('pull-stream')
var crypto = require('crypto')
var Reconnect = require('pull-reconnect')

function Hash (onHash) {
  var hash = crypto.createHash('sha256')
  return pull.through(function (data) {
    hash.update(
        'string' === typeof data
      ? new Buffer(data, 'utf8')
      : data
    )
  }, function (err) {
    if(err && !onHash) throw err
    onHash && onHash(err, '&'+hash.digest('base64')+'.sha256')
  })
}
//uncomment this to use from browser...
//also depends on having ssb-ws installed.
//var createClient = require('ssb-lite')
var createClient = require('ssb-client')

var createConfig = require('ssb-config/inject')

var createFeed   = require('ssb-feed')
var keys = require('./keys')

module.exports = function () {
  var opts = createConfig()
  var sbot = null

  var rec = Reconnect(function (isConn) {
    createClient(keys, opts, function (err, _sbot) {
      if(err) {console.error(err.stack); isConn(err)}
      sbot = _sbot
      sbot.on('closed', function () {
        sbot = null
        isConn(new Error('closed'))
      })
      isConn()
    })
  })

  var internal = {
    getLatest: rec.async(function (id, cb) {
      sbot.getLatest(id, cb)
    }),
    add: rec.async(function (msg, cb) {
      sbot.add(msg, cb)
    })
  }

  var feed = createFeed(internal, keys)

  return {
    sbot_blobs_add: rec.sink(function (cb) {
      return pull(
        Hash(cb),
        sbot.blobs.add()
      )
    }),
    sbot_links: rec.source(function (query) {
      return sbot.links(query)
    }),
    sbot_links2: rec.source(function (query) {
      return sbot.links2.read(query)
    }),
    sbot_query: rec.source(function (query) {
      return sbot.query.read(query)
    }),
    sbot_log: rec.source(function (opts) {
      return sbot.createLogStream(opts)
    }),
    sbot_user_feed: rec.source(function (opts) {
      return sbot.createUserStream(opts)
    }),
    sbot_get: rec.async(function (key, cb) {
      sbot.get(key, cb)
    }),
    sbot_publish: rec.async(function (msg, cb) {
      feed.add(msg, function (err, msg) {
        cb(err, msg)
      })
    }),
    sbot_whoami: rec.async(function (cb) {
      sbot.whoami(cb)
    })
  }
}

<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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.

/**
 * @fileoverview Helper function that spawns a go binary process.
 */
import child from 'child_process';
import lodash from 'lodash';
import q from 'q';
import semver from 'semver';

import conf from './conf';

// Add base directory to the gopath so that local imports work.
const sourceGopath = `${conf.paths.backendTmp}:${conf.paths.backendVendor}`;
// Add the project's required go tools to the PATH.
const devPath = `${process.env.PATH}:${conf.paths.goTools}/bin`;

/**
 * The environment needed for the execution of any go command.
 */
const env = lodash.merge(process.env, {GOPATH: sourceGopath, PATH: devPath});

/**
 * Minimum required Go Version
 */
const minGoVersion = '1.6.1';

/**
 * Spawns a Go process after making sure all Go prerequisites are
 * present. Backend source files must be packaged with 'package-backend'
 * task before running
 * this command.
 *
 * @param {!Array<string>} args - Arguments of the go command.
 * @param {function(?Error=)} doneFn - Callback.
 * @param {!Object<string, string>=} [envOverride] optional environment variables overrides map.
 */
export default function spawnGoProcess(args, doneFn, envOverride) {
  checkPrerequisites()
      .then(() => spawnProcess(args, envOverride))
      .then(doneFn)
      .fail((error) => doneFn(error));
}

/**
 * Checks if all prerequisites for a go-command execution are present.
 * @return {Q.Promise} A promise object.
 */
function checkPrerequisites() {
  return checkGo().then(checkGoVersion).then(checkGovendor);
}

/**
 * Checks if go is on the PATH prior to a go command execution, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGo() {
  let deferred = q.defer();
  child.exec(
      'which go', {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(new Error(
              'Go is not on the path. Please pass the PATH variable when you run ' +
              'the gulp task with "PATH=$PATH" or install go if you have not yet.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}

/**
 * Checks if go version fulfills the minimum version prerequisite, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGoVersion() {
  let deferred = q.defer();
  child.exec(
      'go version', {
        env: env,
      },
      function(error, stdout) {
        let match = /[\d\.]+/.exec(stdout.toString());  // matches version number
        if (match.length < 1) {
          deferred.reject(new Error('Go version not found.'));
          return;
        }
        let currentGoVersion = match[0];
        // semver requires a patch number, so we'll append '.0' if it isn't present.
        if (currentGoVersion.split('.').length === 2) {
          currentGoVersion = `${currentGoVersion}.0`;
        }
        if (semver.lt(currentGoVersion, minGoVersion)) {
          deferred.reject(new Error(
              `The current go version '${currentGoVersion}' is older than ` +
              `the minimum required version '${minGoVersion}'. ` +
              `Please upgrade your go version!`));
          return;
        }
        deferred.resolve();
      });

  return deferred.promise;
}

/**
 * Checks if govendor is on the PATH prior to a go command execution,
 * promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGovendor() {
  let deferred = q.defer();
  child.exec(
      'which govendor', {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(new Error(
              'Govendor is not on the path. ' +
              'Please run "npm install" in the base directory of the project.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}

/**
 * Spawns Go process.
 * Promises an error if the go command process fails.
 *
 * @param {!Array<string>} args - Arguments of the go command.
 * @param {!Object<string, string>=} [envOverride] optional environment variables overrides map.
 * @return {Q.Promise} A promise object.
 */
function spawnProcess(args, envOverride) {
  let deferred = q.defer();
  let envLocal = lodash.merge(env, envOverride);
  let goTask = child.spawn('go', args, {
    env: envLocal,
    stdio: 'inherit',
  });
  // Call Gulp callback on task exit. This has to be done to make Gulp dependency management
  // work.
  goTask.on('exit', function(code) {
    if (code !== 0) {
      deferred.reject(Error(`Go command error, code: ${code}`));
      return;
    }
    deferred.resolve();
  });
  return deferred.promise;
}
<commit_msg>Allow for devel versions Go to go unchecked (#1616)<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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.

/**
 * @fileoverview Helper function that spawns a go binary process.
 */
import child from 'child_process';
import lodash from 'lodash';
import q from 'q';
import semver from 'semver';

import conf from './conf';

// Add base directory to the gopath so that local imports work.
const sourceGopath = `${conf.paths.backendTmp}:${conf.paths.backendVendor}`;
// Add the project's required go tools to the PATH.
const devPath = `${process.env.PATH}:${conf.paths.goTools}/bin`;

/**
 * The environment needed for the execution of any go command.
 */
const env = lodash.merge(process.env, {GOPATH: sourceGopath, PATH: devPath});

/**
 * Minimum required Go Version
 */
const minGoVersion = '1.6.1';

/**
 * Spawns a Go process after making sure all Go prerequisites are
 * present. Backend source files must be packaged with 'package-backend'
 * task before running
 * this command.
 *
 * @param {!Array<string>} args - Arguments of the go command.
 * @param {function(?Error=)} doneFn - Callback.
 * @param {!Object<string, string>=} [envOverride] optional environment variables overrides map.
 */
export default function spawnGoProcess(args, doneFn, envOverride) {
  checkPrerequisites()
      .then(() => spawnProcess(args, envOverride))
      .then(doneFn)
      .fail((error) => doneFn(error));
}

/**
 * Checks if all prerequisites for a go-command execution are present.
 * @return {Q.Promise} A promise object.
 */
function checkPrerequisites() {
  return checkGo().then(checkGoVersion).then(checkGovendor);
}

/**
 * Checks if go is on the PATH prior to a go command execution, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGo() {
  let deferred = q.defer();
  child.exec(
      'which go', {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(new Error(
              'Go is not on the path. Please pass the PATH variable when you run ' +
              'the gulp task with "PATH=$PATH" or install go if you have not yet.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}

/**
 * Checks if go version fulfills the minimum version prerequisite, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGoVersion() {
  let deferred = q.defer();
  child.exec(
      'go version', {
        env: env,
      },
      function(error, stdout) {
        let match = /go version devel/.exec(stdout.toString());
        if (match && match.length > 0) {
          // If running a development version of Go we asume the version to be
          // good enough, if compilation gives weird errors the developer also
          // should know what is going on, since he uses a development version
          // of Go :)
          deferred.resolve();
          return;
        }
        match = /[\d\.]+/.exec(stdout.toString());  // matches version number
        if (match && match.length < 1) {
          deferred.reject(new Error('Go version not found.'));
          return;
        }
        let currentGoVersion = match[0];
        // semver requires a patch number, so we'll append '.0' if it isn't present.
        if (currentGoVersion.split('.').length === 2) {
          currentGoVersion = `${currentGoVersion}.0`;
        }
        if (semver.lt(currentGoVersion, minGoVersion)) {
          deferred.reject(new Error(
              `The current go version '${currentGoVersion}' is older than ` +
              `the minimum required version '${minGoVersion}'. ` +
              `Please upgrade your go version!`));
          return;
        }
        deferred.resolve();
      });

  return deferred.promise;
}

/**
 * Checks if govendor is on the PATH prior to a go command execution,
 * promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGovendor() {
  let deferred = q.defer();
  child.exec(
      'which govendor', {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(new Error(
              'Govendor is not on the path. ' +
              'Please run "npm install" in the base directory of the project.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}

/**
 * Spawns Go process.
 * Promises an error if the go command process fails.
 *
 * @param {!Array<string>} args - Arguments of the go command.
 * @param {!Object<string, string>=} [envOverride] optional environment variables overrides map.
 * @return {Q.Promise} A promise object.
 */
function spawnProcess(args, envOverride) {
  let deferred = q.defer();
  let envLocal = lodash.merge(env, envOverride);
  let goTask = child.spawn('go', args, {
    env: envLocal,
    stdio: 'inherit',
  });
  // Call Gulp callback on task exit. This has to be done to make Gulp dependency management
  // work.
  goTask.on('exit', function(code) {
    if (code !== 0) {
      deferred.reject(Error(`Go command error, code: ${code}`));
      return;
    }
    deferred.resolve();
  });
  return deferred.promise;
}
<|endoftext|>


<commit_before>function redirectToHomePage() {
  window.location.pathname = 'index';
}

/**
 * Look for a query param in an url
 * return this param or undefined if not found
 * @param {*} name of the query param
 * @param {*} url url
 */
function getParameterByName(name, url) {
  if (!url) url = window.location.href;
  name = name.replace(/[\[\]]/g, '\\$&');
  var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
    results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return '';
  return decodeURIComponent(results[2].replace(/\+/g, ' '));
}

function getApiKeyIfOneTimeLoginTokenIsPresent() {
  const oneTimeLoginToken = getParameterByName('oneTimeLoginToken', window.location.href);
  removeQueryParamsFromUrl();
  if (oneTimeLoginToken) {
    console.log('getting api key from q-cloud');
    getAPIKeyWithOneTimeLoginToken(oneTimeLoginToken);
  } else {
    updateLoginDisplayElements(undefined);
    replaceALLApiKeyByStoredApiKey(undefined);
  }
}

function getCurrentUser() {
  const localAPIKey = getStoredAPIKey();
  $.getJSON("https://q.daskeyboard.com/api/1.0/users/me", localAPIKey)
    // post request success
    .done(function (data) {
      // store email
      localStorage.setItem('email', data.email);
      // update the view with the new user info
      updateLoginDisplayElements(data.email);
      replaceALLApiKeyByStoredApiKey(localAPIKey);
    })
    // error with POST request
    .fail(function () {
      // notify user that error happened
      logout();
    });
}

function onLoginToQCloud() {
  const callbackUrl = window.location.pathname;
  window.location = "https://qapp.daskeyboard.com?source=q-documentation"
    + '&callbackUrl=' + callbackUrl;
}

/**
 *
 * redefine jquery post request to use application/json and stringify the data
 */
$.postJSON = function (url, data, callback) {
  return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
  });
};

/**
 *
 * redefine jquery post request to use application/json and stringify the data
 */
$.getJSON = function (url, apiKey, callback) {
  return jQuery.ajax({
    'type': 'GET',
    'url': url,
    headers: { 'X-API-KEY': apiKey },
    'contentType': 'application/json',
    'dataType': 'json',
    'success': callback
  });
};

/**
 * Get API key from the Q Cloud using a one time login token and store it in the local
 * storage
 * @param {*} loginToken
 */
function getAPIKeyWithOneTimeLoginToken(loginToken) {
  if (!loginToken) {
    console.error('no login token provided');
    return;
  }
  $.postJSON("https://q.daskeyboard.com/api/1.0/users/api_key", { oneTimeLoginToken: loginToken })
    // post request success
    .done(function (data) {
      // store apiKey in local storage
      const apiKey = data.value;
      localStorage.setItem('APIKey', apiKey);
      // notify user that the API key was fetched
      displayFlashNotice('info',
        'You are  logged in: sample code will contain your API key so you can copy paste and experiment easily. Enjoy!');
      getCurrentUser();
    })
    // error with POST request
    .fail(function () {
      // notify user that error happened
      updateLoginDisplayElements(undefined);
      replaceALLApiKeyByStoredApiKey(undefined);
      displayFlashNotice('error', 'Error while fetching API KEY');
    });
}

function getStoredAPIKey() {
  const apiKey = localStorage.getItem('APIKey');
  return apiKey;
}

/************************************************************************
 *
 *  code used to display a notice popover for the user
 *
 *
 * ***********************************************************************
 */

/**
 * Displays a bootstrap alert depending on the noticeType
 * noticeType can be 'info' and the bootstrap alert will be blue
 * or can be 'error' and the bootstrap alert will be red
 * @param {*} noticeType
 * @param {*} message
 */
function displayFlashNotice(noticeType, message) {
  // get the bootstrap alert div
  const flashNoticeDivId = '#flash-notice-section';
  const flashNoticeMessageId = '#flash-notice-message';
  const alertDiv = $(flashNoticeDivId);
  const alertMessage = $(flashNoticeMessageId);

  if (alertDiv && alertMessage) {
    // populate the content of the div with the message
    alertMessage.html(message);
    // remove the previous class lists
    alertDiv.removeClass(['alert-info', 'alert-danger']);
    switch (noticeType) {
      case 'info':
        alertDiv.addClass(['alert-primary']);
        break;

      case 'error':
        alertDiv.addClass(['alert-danger']);
        break;
    }

    // show the div
    alertDiv.css('display', 'block');

  }
}

/**
 * closes the flash notice component by hiding the element in the DOM
 */
function onCloseFlashNotice() {
  const flashNoticeDivId = 'flash-notice-section';
  const alertDiv = document.getElementById(flashNoticeDivId);
  if (alertDiv) {
    alertDiv.style.display = 'none';
  }
}

/************************************************************************
 *
 *  END OF code used to display a notice popover for the user
 *
 *
 * ***********************************************************************
 */

function removeQueryParamsFromUrl() {
  var newurl = window.location.pathname;
  window.history.pushState({ path: newurl }, '', newurl);
}

/**
 * Remove the stored apiKey
 * and update the views to display a none logged user
 */
function logout() {

  // remove api key and email from local storage
  localStorage.removeItem('APIKey');
  localStorage.removeItem('email');

  // reload page
  window.location.reload();
}

function updateLoginDisplayElements(currentUserEmail) {
  if (currentUserEmail) {
    // hide login message
    $('#header-login-message').css('display', 'none');
    // display welcome message
    $('#header-welcome-message').text('Welcome ' + currentUserEmail);
    $('#header-welcome-message').css('display', 'inline-block');
    $('#header-welcome-message').css('font-weight', 'bold');
    // display logout action
    $('#logout-action').css('display', 'inline-block');
  } else {
    // hide logout action
    $('#logout-action').css('display', 'none');
    // hide welcome message
    $('#header-welcome-message').css('display', 'none');
    // display login message
    $('#header-login-message').css('display', 'inline-block');
  }
}

/************************************************************************
 *
 *  code used to display the dynamic content in the code pages
 *
 *
 * ***********************************************************************
 */

function formatJSONCode() {
  var jsonCode = document.getElementsByClassName('json-code');
  for (var i = 0; i < jsonCode.length; i++) {
    var content = jsonCode[i].textContent;
    jsonCode[i].innerHTML = syntaxHighlight(content);
  }
};

function replaceALLApiKeyByStoredApiKey(apiKey) {
  $("body").children().each(function () {
    if (!apiKey) {

      // TODO change with the root to the API Key explanation page
      const apiKeyMoreDetails = window.location.origin + '/get-started/software/';
      $(this).html($(this).html().replace(/\$API_KEY/g,
        // ""
        // + "login to retrieve your api-key"));
        "<button class='login-code-button' data-toggle='tooltip' data-html='true' title='This is a sample API key. Login to see examples "
        + "pre-filled with your keys.'>login to retrieve your api-key</button>"));
    } else {
      $(this).html($(this).html().replace(/\$API_KEY/g, apiKey));
    }
  });
}

/**
 * Use to beautify json code
 * @param {*} json
 */
function syntaxHighlight(json) {
  if (typeof json != 'string') {
    json = JSON.stringify(json, undefined, 2);
  }
  json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
  return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
    var cls = 'number';
    if (/^"/.test(match)) {
      if (/:$/.test(match)) {
        cls = 'key';
      } else {
        cls = 'string';
      }
    } else if (/true|false/.test(match)) {
      cls = 'boolean';
    } else if (/null/.test(match)) {
      cls = 'null';
    }
    // if (cls === 'string') {
    //   return '' + match + '
';
    // } else {
    //   return '' + match + '';
    // }
    return '' + match + '';
  });
}

/************************************************************************
 *
 *  End of code used to display the dynamic content in the code pages
 *
 *
 * ***********************************************************************
 */

/**
 * Detects the os platform and architechture and change the download link of the Q software
 * depending on this informations
 */
function loadDownloadLinkDependingOnOsArchitechture() {
  if (navigator.platform.includes('Win32')) {
    if (navigator.userAgent.indexOf("WOW64") != -1 ||
      navigator.userAgent.indexOf("Win64") != -1) {
      $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0/Das-Keyboard-Q-x64-Setup-3.0.0.exe");
      $('#software-download-button').append(" 64 bit");
      $('#software-version-number').append(" Windows");
      return;

    } else {
      $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0/Das-Keyboard-Q-ia32-Setup-3.0.0.exe");
      $('#software-download-button').append(" 32 bit");
      $('#software-version-number').append(" Windows");
      return;

    }
  }
  if (navigator.platform.includes('MacIntel')) {
    $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/2.0.4/DasKeyboardQ_2.0.4-beta.pkg");
    $('#software-download-button').append(" 64 bit");
    $('#software-version-number').append("-beta");
    $('#software-version-number').append(" Mac");
    return;
  }

  if (navigator.platform.includes('Linux x86_64')) {
    $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/2.0.4/das-keyboard-q_2.0.4~beta.deb");
    $('#software-download-button').append(" 64 bit");
    $('#software-version-number').append("-beta");
    $('#software-version-number').append(" Linux");
    return;
  }

}

/**
 * Detects the device pid given in param in the URL
 * and change the download fw link button depending on the pid
 */
function loadFirmwareDeviceDependingOnPidParam() {
  const pid = getParameterByName('devicePid', window.location.href);
  if (pid) {
    $('#firmware-buttons').css('display', 'flex');
    switch (pid) {
      case 'DK5QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/5Q/5Q+Flash+Upgrade.7.4.18.exe");
        $('#firmware-download-button').text("Download 5Q firmware installer");
        $('#firmware-download-version').text("Version 7.4.18");
        break;
      case 'X50QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/X50Q/DasKeyboard+X50+-+Firmware+Updater+-+57.0.0.exe");
        $('#firmware-download-button').text("Download X50Q firmware installer");
        $('#firmware-download-version').text("Version 57.0.0");
        break;
      case 'DK4QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/DK4Q/DK4Q_US_Firmware_18.23.0.exe");
        $('#firmware-download-button').text("Download DK4Q US firmware installer");
        $('#firmware-download-version').text("Version 18.23.0");
        $('#firmware-download-button-dk4-eu').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/DK4Q/DK4Q_EU_Firmware_19.23.0.exe");
        $('#firmware-download-button-dk4-eu').text("Download DK4Q EU firmware installer");
        $('#firmware-download-version-dk4-eu').text("Version 19.23.0");
        $('#firmware-download-version-dk4-eu').css('visibility', 'visible');
        $('#firmware-download-button-dk4-eu').css('visibility', 'visible');
        break;
    }
  }
}

$(document).ready(function () {
  loadFirmwareDeviceDependingOnPidParam();
  const email = localStorage.getItem('email');
  const apiKey = getStoredAPIKey();
  console.log('apiKey', apiKey);
  console.log('email', email);

  if (email && apiKey) {
    updateLoginDisplayElements(email);
    replaceALLApiKeyByStoredApiKey(apiKey);
  } else {
    //get ApiKey if one time login token present in url
    getApiKeyIfOneTimeLoginTokenIsPresent();
  }

  formatJSONCode();
  loadDownloadLinkDependingOnOsArchitechture();

  // enable bootstrap tooltips
  $('[data-toggle="tooltip"]').tooltip();

  // enable bootstrap popovers
  $('[data-toggle="popover"]').popover();

  $('.popover-dismiss').popover({
    trigger: 'focus'
  });
});
<commit_msg>3.0.0-beta.2 Max Linux<commit_after>function redirectToHomePage() {
  window.location.pathname = 'index';
}

/**
 * Look for a query param in an url
 * return this param or undefined if not found
 * @param {*} name of the query param
 * @param {*} url url
 */
function getParameterByName(name, url) {
  if (!url) url = window.location.href;
  name = name.replace(/[\[\]]/g, '\\$&');
  var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
    results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return '';
  return decodeURIComponent(results[2].replace(/\+/g, ' '));
}

function getApiKeyIfOneTimeLoginTokenIsPresent() {
  const oneTimeLoginToken = getParameterByName('oneTimeLoginToken', window.location.href);
  removeQueryParamsFromUrl();
  if (oneTimeLoginToken) {
    console.log('getting api key from q-cloud');
    getAPIKeyWithOneTimeLoginToken(oneTimeLoginToken);
  } else {
    updateLoginDisplayElements(undefined);
    replaceALLApiKeyByStoredApiKey(undefined);
  }
}

function getCurrentUser() {
  const localAPIKey = getStoredAPIKey();
  $.getJSON("https://q.daskeyboard.com/api/1.0/users/me", localAPIKey)
    // post request success
    .done(function (data) {
      // store email
      localStorage.setItem('email', data.email);
      // update the view with the new user info
      updateLoginDisplayElements(data.email);
      replaceALLApiKeyByStoredApiKey(localAPIKey);
    })
    // error with POST request
    .fail(function () {
      // notify user that error happened
      logout();
    });
}

function onLoginToQCloud() {
  const callbackUrl = window.location.pathname;
  window.location = "https://qapp.daskeyboard.com?source=q-documentation"
    + '&callbackUrl=' + callbackUrl;
}

/**
 *
 * redefine jquery post request to use application/json and stringify the data
 */
$.postJSON = function (url, data, callback) {
  return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
  });
};

/**
 *
 * redefine jquery post request to use application/json and stringify the data
 */
$.getJSON = function (url, apiKey, callback) {
  return jQuery.ajax({
    'type': 'GET',
    'url': url,
    headers: { 'X-API-KEY': apiKey },
    'contentType': 'application/json',
    'dataType': 'json',
    'success': callback
  });
};

/**
 * Get API key from the Q Cloud using a one time login token and store it in the local
 * storage
 * @param {*} loginToken
 */
function getAPIKeyWithOneTimeLoginToken(loginToken) {
  if (!loginToken) {
    console.error('no login token provided');
    return;
  }
  $.postJSON("https://q.daskeyboard.com/api/1.0/users/api_key", { oneTimeLoginToken: loginToken })
    // post request success
    .done(function (data) {
      // store apiKey in local storage
      const apiKey = data.value;
      localStorage.setItem('APIKey', apiKey);
      // notify user that the API key was fetched
      displayFlashNotice('info',
        'You are  logged in: sample code will contain your API key so you can copy paste and experiment easily. Enjoy!');
      getCurrentUser();
    })
    // error with POST request
    .fail(function () {
      // notify user that error happened
      updateLoginDisplayElements(undefined);
      replaceALLApiKeyByStoredApiKey(undefined);
      displayFlashNotice('error', 'Error while fetching API KEY');
    });
}

function getStoredAPIKey() {
  const apiKey = localStorage.getItem('APIKey');
  return apiKey;
}

/************************************************************************
 *
 *  code used to display a notice popover for the user
 *
 *
 * ***********************************************************************
 */

/**
 * Displays a bootstrap alert depending on the noticeType
 * noticeType can be 'info' and the bootstrap alert will be blue
 * or can be 'error' and the bootstrap alert will be red
 * @param {*} noticeType
 * @param {*} message
 */
function displayFlashNotice(noticeType, message) {
  // get the bootstrap alert div
  const flashNoticeDivId = '#flash-notice-section';
  const flashNoticeMessageId = '#flash-notice-message';
  const alertDiv = $(flashNoticeDivId);
  const alertMessage = $(flashNoticeMessageId);

  if (alertDiv && alertMessage) {
    // populate the content of the div with the message
    alertMessage.html(message);
    // remove the previous class lists
    alertDiv.removeClass(['alert-info', 'alert-danger']);
    switch (noticeType) {
      case 'info':
        alertDiv.addClass(['alert-primary']);
        break;

      case 'error':
        alertDiv.addClass(['alert-danger']);
        break;
    }

    // show the div
    alertDiv.css('display', 'block');

  }
}

/**
 * closes the flash notice component by hiding the element in the DOM
 */
function onCloseFlashNotice() {
  const flashNoticeDivId = 'flash-notice-section';
  const alertDiv = document.getElementById(flashNoticeDivId);
  if (alertDiv) {
    alertDiv.style.display = 'none';
  }
}

/************************************************************************
 *
 *  END OF code used to display a notice popover for the user
 *
 *
 * ***********************************************************************
 */

function removeQueryParamsFromUrl() {
  var newurl = window.location.pathname;
  window.history.pushState({ path: newurl }, '', newurl);
}

/**
 * Remove the stored apiKey
 * and update the views to display a none logged user
 */
function logout() {

  // remove api key and email from local storage
  localStorage.removeItem('APIKey');
  localStorage.removeItem('email');

  // reload page
  window.location.reload();
}

function updateLoginDisplayElements(currentUserEmail) {
  if (currentUserEmail) {
    // hide login message
    $('#header-login-message').css('display', 'none');
    // display welcome message
    $('#header-welcome-message').text('Welcome ' + currentUserEmail);
    $('#header-welcome-message').css('display', 'inline-block');
    $('#header-welcome-message').css('font-weight', 'bold');
    // display logout action
    $('#logout-action').css('display', 'inline-block');
  } else {
    // hide logout action
    $('#logout-action').css('display', 'none');
    // hide welcome message
    $('#header-welcome-message').css('display', 'none');
    // display login message
    $('#header-login-message').css('display', 'inline-block');
  }
}

/************************************************************************
 *
 *  code used to display the dynamic content in the code pages
 *
 *
 * ***********************************************************************
 */

function formatJSONCode() {
  var jsonCode = document.getElementsByClassName('json-code');
  for (var i = 0; i < jsonCode.length; i++) {
    var content = jsonCode[i].textContent;
    jsonCode[i].innerHTML = syntaxHighlight(content);
  }
};

function replaceALLApiKeyByStoredApiKey(apiKey) {
  $("body").children().each(function () {
    if (!apiKey) {

      // TODO change with the root to the API Key explanation page
      const apiKeyMoreDetails = window.location.origin + '/get-started/software/';
      $(this).html($(this).html().replace(/\$API_KEY/g,
        // ""
        // + "login to retrieve your api-key"));
        "<button class='login-code-button' data-toggle='tooltip' data-html='true' title='This is a sample API key. Login to see examples "
        + "pre-filled with your keys.'>login to retrieve your api-key</button>"));
    } else {
      $(this).html($(this).html().replace(/\$API_KEY/g, apiKey));
    }
  });
}

/**
 * Use to beautify json code
 * @param {*} json
 */
function syntaxHighlight(json) {
  if (typeof json != 'string') {
    json = JSON.stringify(json, undefined, 2);
  }
  json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
  return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
    var cls = 'number';
    if (/^"/.test(match)) {
      if (/:$/.test(match)) {
        cls = 'key';
      } else {
        cls = 'string';
      }
    } else if (/true|false/.test(match)) {
      cls = 'boolean';
    } else if (/null/.test(match)) {
      cls = 'null';
    }
    // if (cls === 'string') {
    //   return '' + match + '
';
    // } else {
    //   return '' + match + '';
    // }
    return '' + match + '';
  });
}

/************************************************************************
 *
 *  End of code used to display the dynamic content in the code pages
 *
 *
 * ***********************************************************************
 */

/**
 * Detects the os platform and architechture and change the download link of the Q software
 * depending on this informations
 */
function loadDownloadLinkDependingOnOsArchitechture() {
  if (navigator.platform.includes('Win32')) {
    if (navigator.userAgent.indexOf("WOW64") != -1 ||
      navigator.userAgent.indexOf("Win64") != -1) {
      $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0/Das-Keyboard-Q-x64-Setup-3.0.0.exe");
      $('#software-download-button').append(" 64 bit");
      $('#software-version-number').append(" Windows");
      return;

    } else {
      $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0/Das-Keyboard-Q-ia32-Setup-3.0.0.exe");
      $('#software-download-button').append(" 32 bit");
      $('#software-version-number').append(" Windows");
      return;

    }
  }
  if (navigator.platform.includes('MacIntel')) {
    $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0-beta/DasKeyboardQ_3.0.0-beta.pkg");
    $('#software-download-button').append(" 64 bit");
    $('#software-version-number').append("-beta.2");
    $('#software-version-number').append(" Mac");
    return;
  }

  if (navigator.platform.includes('Linux x86_64')) {
    $('#software-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/3.0.0-beta/das-keyboard-q_3.0.0~beta.2.deb");
    $('#software-download-button').append(" 64 bit");
    $('#software-version-number').append("-beta.2");
    $('#software-version-number').append(" Linux");
    return;
  }

}

/**
 * Detects the device pid given in param in the URL
 * and change the download fw link button depending on the pid
 */
function loadFirmwareDeviceDependingOnPidParam() {
  const pid = getParameterByName('devicePid', window.location.href);
  if (pid) {
    $('#firmware-buttons').css('display', 'flex');
    switch (pid) {
      case 'DK5QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/5Q/5Q+Flash+Upgrade.7.4.18.exe");
        $('#firmware-download-button').text("Download 5Q firmware installer");
        $('#firmware-download-version').text("Version 7.4.18");
        break;
      case 'X50QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/X50Q/DasKeyboard+X50+-+Firmware+Updater+-+57.0.0.exe");
        $('#firmware-download-button').text("Download X50Q firmware installer");
        $('#firmware-download-version').text("Version 57.0.0");
        break;
      case 'DK4QPID':
        $('#firmware-download-button').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/DK4Q/DK4Q_US_Firmware_18.23.0.exe");
        $('#firmware-download-button').text("Download DK4Q US firmware installer");
        $('#firmware-download-version').text("Version 18.23.0");
        $('#firmware-download-button-dk4-eu').attr("href", "https://s3-us-west-2.amazonaws.com/q-software-releases/Firmware-releases/DK4Q/DK4Q_EU_Firmware_19.23.0.exe");
        $('#firmware-download-button-dk4-eu').text("Download DK4Q EU firmware installer");
        $('#firmware-download-version-dk4-eu').text("Version 19.23.0");
        $('#firmware-download-version-dk4-eu').css('visibility', 'visible');
        $('#firmware-download-button-dk4-eu').css('visibility', 'visible');
        break;
    }
  }
}

$(document).ready(function () {
  loadFirmwareDeviceDependingOnPidParam();
  const email = localStorage.getItem('email');
  const apiKey = getStoredAPIKey();
  console.log('apiKey', apiKey);
  console.log('email', email);

  if (email && apiKey) {
    updateLoginDisplayElements(email);
    replaceALLApiKeyByStoredApiKey(apiKey);
  } else {
    //get ApiKey if one time login token present in url
    getApiKeyIfOneTimeLoginTokenIsPresent();
  }

  formatJSONCode();
  loadDownloadLinkDependingOnOsArchitechture();

  // enable bootstrap tooltips
  $('[data-toggle="tooltip"]').tooltip();

  // enable bootstrap popovers
  $('[data-toggle="popover"]').popover();

  $('.popover-dismiss').popover({
    trigger: 'focus'
  });
});
<|endoftext|>


<commit_before>$(function () {
	var uploadInput = $('#upload-input')
	  , uploadBtn = $('#upload-btn')
	  , uploadFiles = $('#upload-filelist')

	var btnContent = ""

	if (!$.hasFileAPI()) {
		$('#no-file-api').show()
		uploadBtn.hide()
	}

	uploadBtn.cabinet(uploadInput)

	uploadBtn.on('dragenter', function (e) {
		if (this === e.target) {
			$(this).addClass('drop')
			btnContent = $(this).html()
			$(this).html('Drop it here~')
		}
	})

	uploadBtn.on('drop', function (e) {
		$(this).trigger('dragleave')
	})

	uploadBtn.on('dragleave', function (e) {
		node = e.target
		do {
			if (node === this) {
				$(this).removeClass('drop')
				$(this).html(btnContent)
				break
			}
		} while (node = node.parentNode)
	})

	var MAX_SIZE = (function (node) {
		var max = node.attr('data-max-size') || '10MiB'
		var num = parseInt(/([0-9,]+).*/.exec(max)[1].replace(',', ''))
		var unit = /(?:([KMGTPEZY])(i)?B|([BKMGTPEZY]))/.exec(max) || ["B","",""]

		var oneUnit = Math.pow(
			(unit[2] === "i" ? 1024 : 1000),
			'BKMGTPEZY'.indexOf(unit[1])
		)

		return num * oneUnit
	})(uploadInput)

	var createRow = function (filename, size, extra) {
		var rowItem = $('
')
		  , rowName = $('')
		  , rowProg = $('
')
		  , rowSize = $('')
		  , rowUrl  = $('')

		rowItem.addClass(extra || '')

		$('
').appendTo(rowProg)

		rowItem.attr('data-filename', escape(filename))
		rowName.text(filename)
		rowSize.text(size)

		rowItem.append(rowName, rowProg, rowSize, rowUrl)

		return rowItem
	}

	uploadBtn.on('change', function (e) {
		uploadFiles.empty().removeClass('error completed')

		var files = uploadInput[0].filelist;

		files.forEach(function (file) {
			createRow(file.name, file.humanSize).appendTo(uploadFiles)
		})

		var totalRow = createRow('', files.humanSize, 'total')
		totalRow.appendTo(uploadFiles)

		if (files.size > MAX_SIZE) {
			uploadFiles.addClass('error')

			$('.file-name', totalRow).text('onii-chan y-your upload is t-too big…')
			return
		}

		var up = files.upload("upload.php")

		var eachRow = function (files, fn) {
			var hits = {}
			files.forEach(function (file) {
				++hits[file.name] || (hits[file.name] = 0)
				var row = $($('li[data-filename="' + escape(file.name) + '"]')[hits[file.name] || 0])
				fn.call(row, row, file, files)
			})
		}

		var totalName = $('.file-name', totalRow)

		up.on('uploadprogress', function (e, files) {
			eachRow(files, function (row, file, files) {
				$('.progress-inner', row).width((file.percentUploaded * 100) + '%')
			})
			$('.progress-inner', totalRow).width((files.percentUploaded * 100) + '%')
		})

		up.on('uploadcomplete', function (e) {
			$('.progress-inner').width('100%')
			totalName.text('Grabbing URLs...')
		})

		up.on('load', function (e, res) {
			switch (e.target.status) {
				case 200:
					var res = JSON.parse(res)
					if (!res.success) {
						uploadFiles.addClass('error')
						$('.file-name', totalRow).text('Something went wrong; try again later.')
						break
					}
					eachRow(res.files, function (row, file, files) {
						var link = $('')
						var domains = Array('b.1339.cf', 'c.1339.cf', 'd.1339.cf', 'e.1339.cf', 'f.1339.cf', 'g.1339.cf')
						var fucktwitter = domains[Math.floor(Math.random() * domains.length)]
						link.attr('href', 'http://'+fucktwitter+'/' + file.url)
							.attr('target', '_BLANK')
							.text(fucktwitter+'/' + file.url)

						$('.file-url', row).append(link)
					})
					uploadFiles.addClass('completed')
					totalName.text('Done!')
					break
				case 413:
					uploadFiles.addClass('error completed')
					// Terrible work-around, but necessary since otherwise the '…' entity is left decoded
					totalName.html($('
').html('onii-chan, y-your upload is t-too big…').text());
					break
				default:
					uploadFiles.addClass('error completed')
					totalName.text('Something went wrong; try again later.')
			}
		})
		up.upload()
	})
})

function moon() {
    document.getElementById("ohayou").innerHTML = "お早う!";
}<commit_msg>solution for sending links via steam, shit though :poop:<commit_after>$(function () {
	var uploadInput = $('#upload-input')
	  , uploadBtn = $('#upload-btn')
	  , uploadFiles = $('#upload-filelist')

	var btnContent = ""

	if (!$.hasFileAPI()) {
		$('#no-file-api').show()
		uploadBtn.hide()
	}

	uploadBtn.cabinet(uploadInput)

	uploadBtn.on('dragenter', function (e) {
		if (this === e.target) {
			$(this).addClass('drop')
			btnContent = $(this).html()
			$(this).html('Drop it here~')
		}
	})

	uploadBtn.on('drop', function (e) {
		$(this).trigger('dragleave')
	})

	uploadBtn.on('dragleave', function (e) {
		node = e.target
		do {
			if (node === this) {
				$(this).removeClass('drop')
				$(this).html(btnContent)
				break
			}
		} while (node = node.parentNode)
	})

	var MAX_SIZE = (function (node) {
		var max = node.attr('data-max-size') || '10MiB'
		var num = parseInt(/([0-9,]+).*/.exec(max)[1].replace(',', ''))
		var unit = /(?:([KMGTPEZY])(i)?B|([BKMGTPEZY]))/.exec(max) || ["B","",""]

		var oneUnit = Math.pow(
			(unit[2] === "i" ? 1024 : 1000),
			'BKMGTPEZY'.indexOf(unit[1])
		)

		return num * oneUnit
	})(uploadInput)

	var createRow = function (filename, size, extra) {
		var rowItem = $('
')
		  , rowName = $('')
		  , rowProg = $('
')
		  , rowSize = $('')
		  , rowUrl  = $('')

		rowItem.addClass(extra || '')

		$('
').appendTo(rowProg)

		rowItem.attr('data-filename', escape(filename))
		rowName.text(filename)
		rowSize.text(size)

		rowItem.append(rowName, rowProg, rowSize, rowUrl)

		return rowItem
	}

	uploadBtn.on('change', function (e) {
		uploadFiles.empty().removeClass('error completed')

		var files = uploadInput[0].filelist;

		files.forEach(function (file) {
			createRow(file.name, file.humanSize).appendTo(uploadFiles)
		})

		var totalRow = createRow('', files.humanSize, 'total')
		totalRow.appendTo(uploadFiles)

		if (files.size > MAX_SIZE) {
			uploadFiles.addClass('error')

			$('.file-name', totalRow).text('onii-chan y-your upload is t-too big…')
			return
		}

		var up = files.upload("upload.php")

		var eachRow = function (files, fn) {
			var hits = {}
			files.forEach(function (file) {
				++hits[file.name] || (hits[file.name] = 0)
				var row = $($('li[data-filename="' + escape(file.name) + '"]')[hits[file.name] || 0])
				fn.call(row, row, file, files)
			})
		}

		var totalName = $('.file-name', totalRow)

		up.on('uploadprogress', function (e, files) {
			eachRow(files, function (row, file, files) {
				$('.progress-inner', row).width((file.percentUploaded * 100) + '%')
			})
			$('.progress-inner', totalRow).width((files.percentUploaded * 100) + '%')
		})

		up.on('uploadcomplete', function (e) {
			$('.progress-inner').width('100%')
			totalName.text('Grabbing URLs...')
		})

		up.on('load', function (e, res) {
			switch (e.target.status) {
				case 200:
					var res = JSON.parse(res)
					if (!res.success) {
						uploadFiles.addClass('error')
						$('.file-name', totalRow).text('Something went wrong; try again later.')
						break
					}
					eachRow(res.files, function (row, file, files) {
						var link = $('')
						var domains = Array('b.1339.cf', 'c.1339.cf', 'd.1339.cf', 'e.1339.cf', 'f.1339.cf', 'g.1339.cf')
						var fucktwitter = domains[Math.floor(Math.random() * domains.length)]
						link.attr('href', 'http://'+fucktwitter+'/' + file.url)
							.attr('target', '_BLANK')
							.text(fucktwitter+'/' + file.url)

						var steamlink = $('')
						steamlink.attr('href', 'http://a.1336.cf/' + file.url)
							.attr('target', '_BLANK')
							.text('Steam Link')

						$('.file-url', row).append(link)
						$('.file-url', row).append(' · ')
						$('.file-url', row).append(steamlink)
					})
					uploadFiles.addClass('completed')
					totalName.text('Done!')
					break
				case 413:
					uploadFiles.addClass('error completed')
					// Terrible work-around, but necessary since otherwise the '…' entity is left decoded
					totalName.html($('
').html('onii-chan, y-your upload is t-too big…').text());
					break
				default:
					uploadFiles.addClass('error completed')
					totalName.text('Something went wrong; try again later.')
			}
		})
		up.upload()
	})
})

function moon() {
    document.getElementById("ohayou").innerHTML = "お早う!";
}

function steam() {

}<|endoftext|>