<commit_before>window.addEventListener('load', function() {
    let gameCanvas = document.getElementById('game-canvas'),
        gameContext1 = gameCanvas.getContext('2d'),
        gameContext = gameCanvas.getContext('2d'),
        gameContext2 = document.getElementById('game-canvas2').getContext('2d');

    let ninjaRunningImg = document.getElementById('ninja-running'),
        ninjaJumpingImg = document.getElementById('ninja-jumping'),
        ninjaHittingImg = document.getElementById('ninja-hitting'),
        obstacleCrateImg = document.getElementById('obstacle-crate'),
        music = document.getElementById('music'),
        pauseContainer = document.getElementById('pause-container'),
        pauseButton = document.getElementById('continue-button');

    let gameWalkingLine = gameCanvas.height - (ninjaRunningImg.height + 10),
        crateYLine = gameCanvas.height - (obstacleCrateImg.height + 10),
        isRunning = true;

    let ninjaSprite = createSprite({
        spriteSheets: [ninjaRunningImg, ninjaJumpingImg, ninjaHittingImg],
        spriteSheet: ninjaRunningImg,
        context: gameContext,
        width: ninjaRunningImg.width / 4,
        height: ninjaRunningImg.height,
        numberOfFrames: 4,
        loopTicksPerFrame: 5
    });

    let ninjaPhysicalBody = createPhysicalBody({
        coordinates: { x: 30, y: gameWalkingLine / 2 },
        speed: { x: 0, y: 0 },
        height: ninjaSprite.height,
        width: ninjaSprite.width * 2 / 3,
        image: ninjaRunningImg
    });

    let obstacleCrateSprite = createObstacle({
        spriteSheets: [obstacleCrateImg],
        spriteSheet: obstacleCrateImg,
        context: gameContext,
        width: obstacleCrateImg.width,
        height: obstacleCrateImg.height,
        obstacleCrateYLine: crateYLine,
        numberOfFrames: 1,
        loopTicksPerFrame: 1
    });

    let keyRepeatDuration = 1000, //interval in miliseconds to allow ninja to hit again obsticales
        lastHitPressed = Date.now(); //the time of first hit
    window.addEventListener('keydown', function(ev) {
        let speed = 4;

        // left arrow => walk left
        if (ev.keyCode === 37) {
            ninjaPhysicalBody.speed.x = -speed;
        }
        // up arrow => jump
        if (ev.keyCode === 38) {
            if (ninjaPhysicalBody.coordinates.y < gameWalkingLine) {
                return;
            }

            ninjaPhysicalBody.speed.y = -speed * 1.3;
        }
        // right arrow => walk right
        if (ev.keyCode === 39) {
            if (ninjaPhysicalBody.coordinates.y < gameWalkingLine) {
                return;
            }
            ninjaPhysicalBody.speed.x = speed;
        }
        // down arrow => fall faster
        if (ev.keyCode === 40) {
            ninjaPhysicalBody.speed.y = speed;
        }
        // p is pressed => game paused
        if (ev.keyCode === 80) {
            if (isRunning) {
                pauseGame('pause');
            } else {
                pauseGame('continue');
            }
        }

        // Space is pressed => hit
        if (ev.keyCode === 32) {
            //Do not allow repeated hit => the hit by sword can accure at least
            //{ctrlKeyRepeatDuration} miiseconds after previous hit
            let now = Date.now();
            if (now - lastHitPressed < keyRepeatDuration) {
                ninjaPhysicalBody.image = null;
                return;
            } else {
                lastHitPressed = now;
                ninjaSprite.spriteSheet = ninjaHittingImg;
                ninjaSprite.width = ninjaHittingImg.width / 2;
                ninjaSprite.height = ninjaHittingImg.height;
                ninjaSprite.loopTicksPerFrame = 10;
                ninjaSprite.numberOfFrames = 2;
                ninjaSprite.frameIndex = 0;
                ninjaPhysicalBody.image = ninjaHittingImg;
            }
        }

        //Ninja's coordinatesX to be in the canvas only
        if ((ninjaPhysicalBody.coordinates.x > (gameWalkingLine * 2))) {
            ninjaPhysicalBody.speed.x = -speed * 1.3;
        } else if (ninjaPhysicalBody.coordinates.x <= 40) {
            ninjaPhysicalBody.speed.x = +speed * 1.3;
        }
    });

    window.addEventListener('keyup', function(ev) {
        if (ev.keyCode === 32) {
            ninjaPhysicalBody.image = null;
        }
    });
    pauseButton.addEventListener("click", function() {
        pauseGame("continue");
    });

    let background = createBackground();

    let gravity = gameGravity(gameWalkingLine);

    function pauseGame(gameStatus) {
        switch (gameStatus) {
            case "continue":
                isRunning = true;
                pauseContainer.style.display = "none";
                break;
            case "pause":
                isRunning = false;
                pauseContainer.style.display = "";
                break;

            default:
                break;
        }
    }

    // I have changes here
    let counter = 0;

    function gameLoop() {
        counter += 1;
        gameContext.clearRect(0, 0, gameContext.canvas.width, gameContext.canvas.height);
        gameContext = counter % 2 === 1 ? gameContext2 : gameContext1;

        if (isRunning) {
            gravity.applyGravityVerticalY(ninjaPhysicalBody, 0.15);
            gravity.removeAccelerationHorizontalX(ninjaPhysicalBody, 0.1);

            let lastNinjaCoordinates = ninjaPhysicalBody.move();
            ninjaSprite.render(ninjaPhysicalBody.coordinates, lastNinjaCoordinates, gameWalkingLine);
            ninjaSprite.update();

            obstacleCrateSprite.iterateObstaclesArray(ninjaPhysicalBody);
            obstacleCrateSprite.spawnBoxHurdle();

            background.render();

            background.update();
        }

        window.requestAnimationFrame(gameLoop);
    }

    gameLoop();
    regulateSound();
    showScores();
});<commit_msg>Additional function for Safari Browser<commit_after>// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel

// MIT license

(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());

window.addEventListener('load', function() {
    var gameCanvas = document.getElementById('game-canvas'),
        gameContext1 = gameCanvas.getContext('2d'),
        gameContext = gameCanvas.getContext('2d'),
        gameContext2 = document.getElementById('game-canvas2').getContext('2d');

    var ninjaRunningImg = document.getElementById('ninja-running'),
        ninjaJumpingImg = document.getElementById('ninja-jumping'),
        ninjaHittingImg = document.getElementById('ninja-hitting'),
        obstacleCrateImg = document.getElementById('obstacle-crate'),
        music = document.getElementById('music'),
        pauseContainer = document.getElementById('pause-container'),
        pauseButton = document.getElementById('continue-button');

    var gameWalkingLine = gameCanvas.height - (ninjaRunningImg.height + 10),
        crateYLine = gameCanvas.height - (obstacleCrateImg.height + 10),
        isRunning = true;

    var ninjaSprite = createSprite({
        spriteSheets: [ninjaRunningImg, ninjaJumpingImg, ninjaHittingImg],
        spriteSheet: ninjaRunningImg,
        context: gameContext,
        width: ninjaRunningImg.width / 4,
        height: ninjaRunningImg.height,
        numberOfFrames: 4,
        loopTicksPerFrame: 5
    });

    var ninjaPhysicalBody = createPhysicalBody({
        coordinates: { x: 30, y: gameWalkingLine / 2 },
        speed: { x: 0, y: 0 },
        height: ninjaSprite.height,
        width: ninjaSprite.width * 2 / 3,
        image: ninjaRunningImg
    });

    var obstacleCrateSprite = createObstacle({
        spriteSheets: [obstacleCrateImg],
        spriteSheet: obstacleCrateImg,
        context: gameContext,
        width: obstacleCrateImg.width,
        height: obstacleCrateImg.height,
        obstacleCrateYLine: crateYLine,
        numberOfFrames: 1,
        loopTicksPerFrame: 1
    });

    var keyRepeatDuration = 1000, //interval in miliseconds to allow ninja to hit again obsticales
        lastHitPressed = Date.now(); //the time of first hit
    window.addEventListener('keydown', function(ev) {
        let speed = 4;

        // left arrow => walk left
        if (ev.keyCode === 37) {
            ninjaPhysicalBody.speed.x = -speed;
        }
        // up arrow => jump
        if (ev.keyCode === 38) {
            if (ninjaPhysicalBody.coordinates.y < gameWalkingLine) {
                return;
            }

            ninjaPhysicalBody.speed.y = -speed * 1.3;
        }
        // right arrow => walk right
        if (ev.keyCode === 39) {
            if (ninjaPhysicalBody.coordinates.y < gameWalkingLine) {
                return;
            }
            ninjaPhysicalBody.speed.x = speed;
        }
        // down arrow => fall faster
        if (ev.keyCode === 40) {
            ninjaPhysicalBody.speed.y = speed;
        }
        // p is pressed => game paused
        if (ev.keyCode === 80) {
            if (isRunning) {
                pauseGame('pause');
            } else {
                pauseGame('continue');
            }
        }

        // Space is pressed => hit
        if (ev.keyCode === 32) {
            //Do not allow repeated hit => the hit by sword can accure at least
            //{ctrlKeyRepeatDuration} miiseconds after previous hit
            let now = Date.now();
            if (now - lastHitPressed < keyRepeatDuration) {
                ninjaPhysicalBody.image = null;
                return;
            } else {
                lastHitPressed = now;
                ninjaSprite.spriteSheet = ninjaHittingImg;
                ninjaSprite.width = ninjaHittingImg.width / 2;
                ninjaSprite.height = ninjaHittingImg.height;
                ninjaSprite.loopTicksPerFrame = 10;
                ninjaSprite.numberOfFrames = 2;
                ninjaSprite.frameIndex = 0;
                ninjaPhysicalBody.image = ninjaHittingImg;
            }
        }

        //Ninja's coordinatesX to be in the canvas only
        if ((ninjaPhysicalBody.coordinates.x > (gameWalkingLine * 2))) {
            ninjaPhysicalBody.speed.x = -speed * 1.3;
        } else if (ninjaPhysicalBody.coordinates.x <= 40) {
            ninjaPhysicalBody.speed.x = +speed * 1.3;
        }
    });

    window.addEventListener('keyup', function(ev) {
        if (ev.keyCode === 32) {
            ninjaPhysicalBody.image = null;
        }
    });
    pauseButton.addEventListener("click", function() {
        pauseGame("continue");
    });

    var background = createBackground();

    var gravity = gameGravity(gameWalkingLine);

    function pauseGame(gameStatus) {
        switch (gameStatus) {
            case "continue":
                isRunning = true;
                pauseContainer.style.display = "none";
                break;
            case "pause":
                isRunning = false;
                pauseContainer.style.display = "";
                break;

            default:
                break;
        }
    }

    // I have changes here
    var counter = 0;

    function gameLoop() {
        counter += 1;
        gameContext.clearRect(0, 0, gameContext.canvas.width, gameContext.canvas.height);
        gameContext = counter % 2 === 1 ? gameContext2 : gameContext1;

        if (isRunning) {
            gravity.applyGravityVerticalY(ninjaPhysicalBody, 0.15);
            gravity.removeAccelerationHorizontalX(ninjaPhysicalBody, 0.1);

            var lastNinjaCoordinates = ninjaPhysicalBody.move();
            ninjaSprite.render(ninjaPhysicalBody.coordinates, lastNinjaCoordinates, gameWalkingLine);
            ninjaSprite.update();

            obstacleCrateSprite.iterateObstaclesArray(ninjaPhysicalBody);
            obstacleCrateSprite.spawnBoxHurdle();

            background.render();

            background.update();
        }

        window.requestAnimationFrame(gameLoop);
    }

    gameLoop();
    regulateSound();
    showScores();
});
<|endoftext|>


<commit_before>function y_ipad(){
 var ua = navigator.userAgent.toLowerCase();
 if(ua.match(/iPad/i)=="ipad" || ua.match(/iphone/i)=="iphone" || ua.match(/android/i)=="android")
 {
  //移动端处理
 }
}
function hidebox()
{
$('.txtbox').hide(500);
}
function posttxt()
{
if($('#text').val()=="")
{
	return;
}
else
{
	$.post("https://kami.im/js/post.php", { name: $('#name').val(), emails: $('#emails').val(),text:$('#text').val() },
	function(data)
	{
		$('#text').val('');
		getlist(1);
	});
}
}
function getlist(num){
$.post("https://kami.im/js/get.php",{page:num}, function(data) {
  $(".txtlist").html('

'+data);
  $imgs = $('.oimg');
  $emailcc=$('.email');
  for(var i_i=0;i_i<$imgs.length;i_i++)
  {
    $emailcc[i_i].id="email_"+i_i;
	$imgs[i_i].src='https://www.gravatar.com/avatar/'+hex_md5($('#email_'+i_i).attr('yv'))+'?s=128&d=&r=G';
  }
  $(".pdtitle").html("Message Board world line:"+$("#ctime").html()+"
x
");
});
 $('.txtbox').show(500);
}

var text="Darkness cannot drive out darkness; only light can do that. Hate cannot drive out hate; only love can do that.";
var delay=50;
var i=0;
function scrollit(){
txt.innerText=text.slice(0,i++);
if(i>text.length){
    i=0;
	$('#fos').fadeIn(4000);
    return;
}
else setTimeout("scrollit()",delay);
}
<commit_msg>Update ota.js<commit_after>function y_ipad(){
 var ua = navigator.userAgent.toLowerCase();
 if(ua.match(/iPad/i)=="ipad" || ua.match(/iphone/i)=="iphone" || ua.match(/android/i)=="android")
 {
  //移动端处理
 }
}
function hidebox()
{
$('.txtbox').hide(500);
}
function posttxt()
{
if($('#text').val()=="")
{
	return;
}
else
{
	$.post("http://happybirthday-liulu.ml//js/post.php", { name: $('#name').val(), emails: $('#emails').val(),text:$('#text').val() },
	function(data)
	{
		$('#text').val('');
		getlist(1);
	});
}
}
function getlist(num){
$.post("https://kami.im/js/get.php",{page:num}, function(data) {
  $(".txtlist").html('

'+data);
  $imgs = $('.oimg');
  $emailcc=$('.email');
  for(var i_i=0;i_i<$imgs.length;i_i++)
  {
    $emailcc[i_i].id="email_"+i_i;
	$imgs[i_i].src='https://www.gravatar.com/avatar/'+hex_md5($('#email_'+i_i).attr('yv'))+'?s=128&d=&r=G';
  }
  $(".pdtitle").html("Message Board world line:"+$("#ctime").html()+"
x
");
});
 $('.txtbox').show(500);
}

var text="Darkness cannot drive out darkness; only light can do that. Hate cannot drive out hate; only love can do that.";
var delay=50;
var i=0;
function scrollit(){
txt.innerText=text.slice(0,i++);
if(i>text.length){
    i=0;
	$('#fos').fadeIn(4000);
    return;
}
else setTimeout("scrollit()",delay);
}
<|endoftext|>


<commit_before>/**
 *
 *      ioBroker mqtt Adapter
 *
 *      (c) 2014-2018 bluefox
 *
 *      MIT License
 *
 */
'use strict';

const utils    = require(__dirname + '/lib/utils'); // Get common adapter utils
const adapter  = new utils.Adapter('mqtt');

let server   = null;
let client   = null;
let states   = {};

const messageboxRegex = new RegExp('\.messagebox$');

function decrypt(key, value) {
    let result = '';
    for (let i = 0; i < value.length; ++i) {
        result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
    }
    return result;
}

adapter.on('message', function (obj) {
    if (obj) processMessage(obj);
    processMessages();
});

adapter.on('ready', function () {
    adapter.config.pass = decrypt('Zgfr56gFe87jJOM', adapter.config.pass);
    adapter.config.maxTopicLength = adapter.config.maxTopicLength || 100;
    if (adapter.config.ssl && adapter.config.type === 'server') {
        // Load certificates
        adapter.getCertificates(function (err, certificates) {
            adapter.config.certificates = certificates;
            main();
        });
    } else {
        // Start
        main();
    }
});

adapter.on('unload', function () {
    if (client) client.destroy();
    if (server) server.destroy();
});

// is called if a subscribed state changes
adapter.on('stateChange', (id, state) => {
    adapter.log.debug('stateChange ' + id + ': ' + JSON.stringify(state));
    // State deleted
    if (!state) {
        delete states[id];
        // If SERVER
        if (server) server.onStateChange(id);
        // if CLIENT
        if (client) client.onStateChange(id);
    } else
    // you can use the ack flag to detect if state is desired or acknowledged
    if ((adapter.config.sendAckToo || !state.ack) && !messageboxRegex.test(id)) {
        const oldVal = states[id] ? states[id].val : null;
        const oldAck = states[id] ? states[id].ack : null;
        states[id] = state;

        // If value really changed
        if (!adapter.config.onchange || oldVal !== state.val || oldAck !== state.ack) {
            // If SERVER
            if (server) server.onStateChange(id, state);
            // if CLIENT
            if (client) client.onStateChange(id, state);
        }
    }
});

function processMessage(obj) {
    if (!obj || !obj.command) return;
    switch (obj.command) {
        case 'test': {
            // Try to connect to mqtt broker
            if (obj.callback && obj.message) {
                const mqtt = require('mqtt');
                const _url = 'mqtt://' + (obj.message.user ? (obj.message.user + ':' + obj.message.pass + '@') : '') + obj.message.url + (obj.message.port ? (':' + obj.message.port) : '') + '?clientId=ioBroker.' + adapter.namespace;
                const _client = mqtt.connect(_url);
                // Set timeout for connection
                const timeout = setTimeout(() => {
                    _client.end();
                    adapter.sendTo(obj.from, obj.command, 'timeout', obj.callback);
                }, 2000);

                // If connected, return success
                _client.on('connect', () => {
                    _client.end();
                    clearTimeout(timeout);
                    adapter.sendTo(obj.from, obj.command, 'connected', obj.callback);
                });
            }
        }
    }
}

function processMessages() {
    adapter.getMessage((err, obj) => {
        if (obj) {
            processMessage(obj.command, obj.message);
            processMessages();
        }
    });
}

let cnt = 0;
function readStatesForPattern(pattern) {
    adapter.getForeignStates(pattern, (err, res) => {
        if (!err && res) {
            if (!states) states = {};

            for (const id in res) {
                if (res.hasOwnProperty(id) &&  !messageboxRegex.test(id)) {
                    states[id] = res[id];
                }
            }
        }
        // If all patters answered, start client or server
        if (!--cnt) {
            if (adapter.config.type === 'client') {
                client = new require(__dirname + '/lib/client')(adapter, states);
            } else {
                server = new require(__dirname + '/lib/server')(adapter, states);
            }
        }
    });
}

function main() {
    // Subscribe on own variables to publish it
    if (adapter.config.publish) {
        const parts = adapter.config.publish.split(',');
        for (let t = 0; t < parts.length; t++) {
            if (parts[t].indexOf('#') !== -1) {
                adapter.log.warn('Used MQTT notation for ioBroker in pattern "' + parts[t] + '": use "' + parts[t].replace(/#/g, '*') + ' notation');
                parts[t] = parts[t].replace(/#/g, '*');
            }
            adapter.subscribeForeignStates(parts[t].trim());
            cnt++;
            readStatesForPattern(parts[t]);
        }
    } else {
        // subscribe for all variables
        adapter.subscribeForeignStates('*');
        readStatesForPattern('*');
    }

    adapter.config.defaultQoS = parseInt(adapter.config.defaultQoS, 10) || 0;
    adapter.config.retain = adapter.config.retain === 'true' || adapter.config.retain === true;
    adapter.config.clean = adapter.config.clean === 'true' || adapter.config.clean === true;
    adapter.config.retransmitInterval = parseInt(adapter.config.retransmitInterval, 10) || 2000;
    adapter.config.retransmitCount = parseInt(adapter.config.retransmitCount, 10) || 10;

    if (adapter.config.retransmitInterval < adapter.config.sendInterval) {
        adapter.config.retransmitInterval = adapter.config.sendInterval * 5;
    }

    // If no subscription, start client or server
    if (!cnt) {
        if (adapter.config.type === 'client') {
            client = new require(__dirname + '/lib/client')(adapter, states);
        } else {
            server = new require(__dirname + '/lib/server')(adapter, states);
        }
    }
}
<commit_msg>Update main.js<commit_after>/**
 *
 *      ioBroker mqtt Adapter
 *
 *      (c) 2014-2018 bluefox
 *
 *      MIT License
 *
 */
'use strict';

const utils    = require(__dirname + '/lib/utils'); // Get common adapter utils
const adapter  = new utils.Adapter('mqtt');

let server   = null;
let client   = null;
let states   = {};

const messageboxRegex = new RegExp('\.messagebox$');

function decrypt(key, value) {
    let result = '';
    for (let i = 0; i < value.length; ++i) {
        result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
    }
    return result;
}

adapter.on('message', function (obj) {
    if (obj) processMessage(obj);
    processMessages();
});

adapter.on('ready', function () {
    adapter.config.pass = decrypt('Zgfr56gFe87jJOM', adapter.config.pass);
    adapter.config.maxTopicLength = adapter.config.maxTopicLength || 100;
    if (adapter.config.ssl && adapter.config.type === 'server') {
        // Load certificates
        adapter.getCertificates(function (err, certificates) {
            adapter.config.certificates = certificates;
            main();
        });
    } else {
        // Start
        main();
    }
});

adapter.on('unload', function () {
    if (client) client.destroy();
    if (server) server.destroy();
});

// is called if a subscribed state changes
adapter.on('stateChange', (id, state) => {
    adapter.log.debug('stateChange ' + id + ': ' + JSON.stringify(state));
    // State deleted
    if (!state) {
        delete states[id];
        // If SERVER
        if (server) server.onStateChange(id);
        // if CLIENT
        if (client) client.onStateChange(id);
    } else
    // you can use the ack flag to detect if state is desired or acknowledged
    if ((adapter.config.sendAckToo || !state.ack) && !messageboxRegex.test(id)) {
        const oldVal = states[id] ? states[id].val : null;
        const oldAck = states[id] ? states[id].ack : null;
        states[id] = state;

        // If value really changed
        if (!adapter.config.onchange || oldVal !== state.val || oldAck !== state.ack) {
            // If SERVER
            if (server) server.onStateChange(id, state);
            // if CLIENT
            if (client) client.onStateChange(id, state);
        }
    }
});

function processMessage(obj) {
    if (!obj || !obj.command) return;
    switch (obj.command) {
        case 'test': {
            // Try to connect to mqtt broker
            if (obj.callback && obj.message) {
                const mqtt = require('mqtt');
                const _url = 'mqtt://' + (obj.message.user ? (obj.message.user + ':' + obj.message.pass + '@') : '') + obj.message.url + (obj.message.port ? (':' + obj.message.port) : '') + '?clientId=ioBroker.' + adapter.namespace;
                const _client = mqtt.connect(_url);
                // Set timeout for connection
                const timeout = setTimeout(() => {
                    _client.end();
                    adapter.sendTo(obj.from, obj.command, 'timeout', obj.callback);
                }, 2000);

                // If connected, return success
                _client.on('connect', () => {
                    _client.end();
                    clearTimeout(timeout);
                    adapter.sendTo(obj.from, obj.command, 'connected', obj.callback);
                });
            }
        }
    }
}

function processMessages() {
    adapter.getMessage((err, obj) => {
        if (obj) {
            processMessage(obj.command, obj.message);
            processMessages();
        }
    });
}

let cnt = 0;
function readStatesForPattern(pattern) {
    adapter.getForeignStates(pattern, (err, res) => {
        if (!err && res) {
            if (!states) states = {};

            for (const id in res) {
                if (res.hasOwnProperty(id) &&  !messageboxRegex.test(id)) {
                    states[id] = res[id];
                }
            }
        }
        // If all patters answered, start client or server
        if (!--cnt) {
            if (adapter.config.type === 'client') {
                client = new require(__dirname + '/lib/client')(adapter, states);
            } else {
                server = new require(__dirname + '/lib/server')(adapter, states);
            }
        }
    });
}

function main() {
    // Subscribe on own variables to publish it
    if (adapter.config.publish) {
        const parts = adapter.config.publish.split(',');
        for (let t = 0; t < parts.length; t++) {
            if (parts[t].indexOf('#') !== -1) {
                adapter.log.warn('Used MQTT notation for ioBroker in pattern "' + parts[t] + '": use "' + parts[t].replace(/#/g, '*') + ' notation');
                parts[t] = parts[t].replace(/#/g, '*');
            }
            adapter.subscribeForeignStates(parts[t].trim());
            cnt++;
            readStatesForPattern(parts[t]);
        }
    } else {
        // subscribe for all variables
        adapter.subscribeForeignStates('*');
        readStatesForPattern('*');
    }

    adapter.config.defaultQoS = parseInt(adapter.config.defaultQoS, 10) || 0;
    adapter.config.retain = adapter.config.retain === 'true' || adapter.config.retain === true;
    adapter.config.persistent = adapter.config.persistent === 'true' || adapter.config.persistent === true;
    adapter.config.retransmitInterval = parseInt(adapter.config.retransmitInterval, 10) || 2000;
    adapter.config.retransmitCount = parseInt(adapter.config.retransmitCount, 10) || 10;

    if (adapter.config.retransmitInterval < adapter.config.sendInterval) {
        adapter.config.retransmitInterval = adapter.config.sendInterval * 5;
    }

    // If no subscription, start client or server
    if (!cnt) {
        if (adapter.config.type === 'client') {
            client = new require(__dirname + '/lib/client')(adapter, states);
        } else {
            server = new require(__dirname + '/lib/server')(adapter, states);
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Simple HTTP Server
 *
 * Author: phen
 *
 * @param {Object} opts
 * @param {Object} appLifeCycle - handle different life cycle phases for registering requests to the express app instance
 * @param {boolean} auth - disable the auth handling to implement by your own
 * @param {string} secret - the cookie secret name for cookie access
 * @param {number} port - the cookie secret name for cookie access
 * @param {string} fileStorageName - path to store the files
 * @param {function} appLifeCycle.phase1 - executed before the files listener is attached
 * @param {function} appLifeCycle.fileFilter - filter for files and folders which will not be send to client (return file name or undefined to filter out)
 * @param {function} appLifeCycle.onUploadFile - listener will be called if file is successfully saves on file system
 * @param {function} appLifeCycle.onDeleteFile - listener will be called if file is successfully deleted from file system
 * @returns {function}
 */
function main(opts, appLifeCycle) {

    var fs = require('fs'),
        wsConnection = require('./server/lib/wsConnection'),
        cookieParser = require('cookie-parser'),
        sessionStore = require('./server/lib/sessionStore'),
        packageJSON = require('./package.json'),
        bodyParser = require('body-parser'),
        folderUtil = require('./lib/folderUtil'),
        changeHistoryLogger = require('./server/lib/changeHistoryLogger'),
        express = require('express'),
        busboy = require('connect-busboy'),
        serveIndex = require('serve-index'),
        thumbNail = require('./lib/thumbNail')(opts.fileStorageName, 'tmb_'),
        app,
        finalhandler = require('finalhandler'),
        serveStatic = require('serve-static'),
        serve = serveStatic(opts.dirName),
        index = serveIndex(opts.dirName, {'icons': true}),
        acceptedImageExtensions = ['jpeg', 'jpg', 'png', 'gif'];

    app = express();
    app.use(busboy());

    app.get(['/dist/*'], function (req, res) {
        var done = finalhandler(req, res);
        serve(req, res, function onNext(err) {
            if (err) {
                return done(err);
            }
            index(req, res, done);
        });
    });

    app.get('/files*', function (req, res) {
        var done = finalhandler(req, res);
        serve(req, res, function onNext(err) {
            if (err) {
                return done(err);
            }
            index(req, res, done);
        });
    });

    // use bodyParser middleware for handling request bodies (express does *not* provide that feature out-of-the-box).
    // since we only have one case of that (POST to /login where username, password are in the body) and that one is url-encoded,
    // we only need that flavor of bodyParser. about the "extended" property, see https://github.com/expressjs/body-parser#bodyparserurlencodedoptions
    app.use(bodyParser.urlencoded({ extended: false }));
    // same for parsing cookie
    app.use(cookieParser());

    appLifeCycle && appLifeCycle.phase1 && appLifeCycle.phase1(app);
    app.get(/^((?!^(\/dist|\/bower_components)).)*$/, function(req, res, next) {

        if (packageJSON.config.auth) {
            // file request
            let isAuth = req.session && req.session.authId;
            if (!/\./.test(req.path) && !isAuth) {
                // TODO sending the login page only makes sense for browser requests. if anybody is e.g. using curl to
                // retrieve message bundles, we should only return a 401 but no content
                res.sendFile(__dirname + '/auth.html');
            } else {
                next();
            }
        } else {
            next();
        }

    });

    app.post('/uploadFile', function (req, res, next) {
        if (packageJSON.config.auth) {
            if (req.session && (req.session.isMaintainer) || req.session.isAdmin) {
                if (req.session.isAdmin) {
                    next();
                } else if (!/.json/.test(req.query.filename)) {
                    next();
                } else {
                    res.status(401).send('Not authorized');
                }
            } else {
                res.status(401).send('Not authorized');
            }
        } else {
            // res.status(401).send('Not authorized');
            next()
        }
    });

    /**
     * Limited restrictions!
     *
     * visitors:
     *  * are not allowed at all
     * maintainer:
     *  * not allowed to delete .json files
     * admins:
     *  * allowed to do everything
     */
    app.post('/deleteFile', function (req, res, next) {
        if (packageJSON.config.auth) {
            if (req.session && req.session.isMaintainer || req.session.isAdmin) {
                if (req.session.isAdmin) {
                    next();
                } else if (!/.json/.test(req.query.filename)) {
                    next();
                } else {
                    res.status(401).send('Not authorized');
                }
            } else {
                res.status(401).send('Not authorized');
            }
        } else {
            // res.status(401).send('Not authorized');
            next()
        }
    });
    /**
     * match except for folder dist
     *
     * If the URL has a dot inside it expect to send a files. Otherwise it sends the index.
     */
    app.get(/^((?!^(\/dist)).)*$/, function (req, res) {
        if (/\./.test(req.path)) {
            // contains a . - looks like a file request so check the files system
            fs.exists(decodeURI(opts.fileStorageName + req.path), function (exists) {
                if (exists) {
                    // not sure if it is good by default but - needs to be configurable
                    res.header("Access-Control-Allow-Origin", "*");
                    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

                    if (/\?tmb/.test(req.url)) {

                        thumbNail.create(decodeURI(req.path), function (file) {
                            if (file) {
                                res.sendFile(file);
                            } else {
                                res.sendFile(decodeURI(opts.fileStorageName + req.path));
                            }
                        });

                    } else {
                        res.sendFile(decodeURI(opts.fileStorageName + req.path), {dotfiles : 'allow'});
                    }
                } else {
                    // no file found - send 404 file
                    res.status(404).sendFile(opts.dirName + '404.html');
                }
            });

        } else {
            // send index
            res.sendFile(opts.dirName + 'index.html');

        }
    });

    app.post('/uploadFile', function (req, res) {
        var fstream, folder = folderUtil.formatFolder(req.query.folder);

        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            // replace all spaces with underscores
            // TODO it's not a good idea to rename file - because there are people they put spaces in a file name
            var fName = filename; //.split(' ').join('_');

            function writeFile() {

                fstream = fs.createWriteStream(opts.fileStorageName + folder + fName);
                file.pipe(fstream);
                fstream.on('close', function () {
                    // TODO add correct type
                    var extension = fName.split('.').pop();
                    if (extension && acceptedImageExtensions.indexOf(extension.toLowerCase()) !== -1) {
                        res.status(200).send({file: folder + fName, name: fName, type: 'image/jpg'});
                    } else {
                        res.status(200).send({file: folder + fName, name: fName, type: extension});
                    }
                });
            }
            changeHistoryLogger.write(opts.fileStorageName, folder + fName, 'upload', req.session.authId || 'anonymous');
            appLifeCycle && appLifeCycle.onUploadFile && appLifeCycle.onUploadFile(req, {
                rootFolder : opts.fileStorageName,
                fileName : folder + fName
            });
            folderUtil.createFolder(opts.fileStorageName, folder, writeFile);
        });
    });

    /**
     * get all available files
     */
    app.post('/getFiles', function (req, res) {
        var folder = '';

        req.on("data", function (chunk) {
            folder += chunk.toString();
        });

        req.on("end", function () {
            folder = folderUtil.formatFolder(folder);
            fs.readdir(opts.fileStorageName + folder, function (err, files) {

                var fileList = [],
                    length;

                if (err === null) {
                    files = files.filter(function (fileName) {
                        return fileName.split('/').pop().startsWith('tmb_') ? undefined : fileName
                    });
                    if (appLifeCycle && appLifeCycle.fileFilter) {
                        files = files.filter(appLifeCycle.fileFilter);
                    }
                    length = files.length;
                    files.forEach(function (file) {
                        fs.stat(opts.fileStorageName + folder + file, function (err, stats) {
                            if (stats.isFile()) {
                                // TODO add correct type
                                var extension = file.split('.').pop();

                                if (extension && acceptedImageExtensions.indexOf(extension.toLowerCase()) !== -1) {
                                    fileList.push({file: folder + file, name: file, type: 'image/jpg'});
                                } else {
                                    fileList.push({file: folder + file, name: file, type: extension});
                                }
                            } else if (stats.isDirectory()) {
                                // filter out directories - if we need directories we should ask separately for it
                                console.log('Found a directory named:', file);
                            }
                            length--;
                            if (length <= 0) {
                                res.status(200).send(fileList);
                            }
                        });
                    });
                }
            });
        });
    });

    /**
     * get all available folders
     */
    app.post('/getFolders', function (req, res) {
        // get a list of all folders
        var folder = '';

        req.on("data", function (chunk) {
            folder += chunk.toString();
        });

        req.on("end", function () {
            folder = folderUtil.formatFolder(folder);
            fs.readdir(opts.fileStorageName + folder, function (err, files) {
                var fileList = [],
                    length;

                if (err === null) {
                    length = files.length;
                    files.forEach(function (file) {
                        fs.stat(opts.fileStorageName + folder + file, function (err, stats) {
                            if (err) {
                                console.log("app:path not exists:", err);
                                return;
                            }
                            if (stats.isDirectory()) {
                                fileList.push(file);
                            }
                            length--;
                            if (length <= 0) {
                                res.status(200).send(fileList);
                            }
                        });
                    });
                }
            });
        });
    });

    /**
     * delete a file
     */
    app.post('/deleteFile', function (req, res) {
        var fileName;
        if (req.query.hasOwnProperty('filename')) {
            fileName = req.query.filename;
            if (fileName[0] !== '/') {
                fileName = '/' + fileName;
            }
            fs.unlink(opts.fileStorageName + fileName, function () {
                changeHistoryLogger.write(opts.fileStorageName, fileName, 'delete', req.session.authId || 'anonymous');
                appLifeCycle && appLifeCycle.onDeleteFile && appLifeCycle.onDeleteFile(req, {
                    rootFolder : opts.fileStorageName,
                    fileName : fileName
                });
                res.status(200).send(req.query.filename);
            });
            thumbNail.remove(fileName);
        } else {
            res.status(200).send(false);
        }
    });

    let server;

    server = app.listen(opts.port, function () {
        console.log('server started on port %d', opts.port);
    });

    // initialize the json persist via websocket
    wsConnection(server, {
        secret : opts.secret,
        dirName : opts.fileStorageName
    });

    return app;
}

module.exports = main;<commit_msg>deliver default 404.html file (configurable via fourOFourFile property)<commit_after>/**
 * Simple HTTP Server
 *
 * Author: phen
 *
 * @param {Object} opts
 * @param {Object} appLifeCycle - handle different life cycle phases for registering requests to the express app instance
 * @param {boolean} auth - disable the auth handling to implement by your own
 * @param {string} secret - the cookie secret name for cookie access
 * @param {number} port - the cookie secret name for cookie access
 * @param {string} fileStorageName - path to store the files
 * @param {string} fourOFourFile - path of the 404.html which will be shown if the file is not available (default is the dragKing own file)
 * @param {function} appLifeCycle.phase1 - executed before the files listener is attached
 * @param {function} appLifeCycle.fileFilter - filter for files and folders which will not be send to client (return file name or undefined to filter out)
 * @param {function} appLifeCycle.onUploadFile - listener will be called if file is successfully saves on file system
 * @param {function} appLifeCycle.onDeleteFile - listener will be called if file is successfully deleted from file system
 * @returns {function}
 */
function main(opts, appLifeCycle) {

    var fs = require('fs'),
        wsConnection = require('./server/lib/wsConnection'),
        cookieParser = require('cookie-parser'),
        sessionStore = require('./server/lib/sessionStore'),
        packageJSON = require('./package.json'),
        bodyParser = require('body-parser'),
        folderUtil = require('./lib/folderUtil'),
        changeHistoryLogger = require('./server/lib/changeHistoryLogger'),
        express = require('express'),
        busboy = require('connect-busboy'),
        serveIndex = require('serve-index'),
        thumbNail = require('./lib/thumbNail')(opts.fileStorageName, 'tmb_'),
        app,
        finalhandler = require('finalhandler'),
        serveStatic = require('serve-static'),
        serve = serveStatic(opts.dirName),
        index = serveIndex(opts.dirName, {'icons': true}),
        acceptedImageExtensions = ['jpeg', 'jpg', 'png', 'gif'];

    app = express();
    app.use(busboy());

    app.get(['/dist/*'], function (req, res) {
        var done = finalhandler(req, res);
        serve(req, res, function onNext(err) {
            if (err) {
                return done(err);
            }
            index(req, res, done);
        });
    });

    app.get('/files*', function (req, res) {
        var done = finalhandler(req, res);
        serve(req, res, function onNext(err) {
            if (err) {
                return done(err);
            }
            index(req, res, done);
        });
    });

    // use bodyParser middleware for handling request bodies (express does *not* provide that feature out-of-the-box).
    // since we only have one case of that (POST to /login where username, password are in the body) and that one is url-encoded,
    // we only need that flavor of bodyParser. about the "extended" property, see https://github.com/expressjs/body-parser#bodyparserurlencodedoptions
    app.use(bodyParser.urlencoded({ extended: false }));
    // same for parsing cookie
    app.use(cookieParser());

    appLifeCycle && appLifeCycle.phase1 && appLifeCycle.phase1(app);
    app.get(/^((?!^(\/dist|\/bower_components)).)*$/, function(req, res, next) {

        if (packageJSON.config.auth) {
            // file request
            let isAuth = req.session && req.session.authId;
            if (!/\./.test(req.path) && !isAuth) {
                // TODO sending the login page only makes sense for browser requests. if anybody is e.g. using curl to
                // retrieve message bundles, we should only return a 401 but no content
                res.sendFile(__dirname + '/auth.html');
            } else {
                next();
            }
        } else {
            next();
        }

    });

    app.post('/uploadFile', function (req, res, next) {
        if (packageJSON.config.auth) {
            if (req.session && (req.session.isMaintainer) || req.session.isAdmin) {
                if (req.session.isAdmin) {
                    next();
                } else if (!/.json/.test(req.query.filename)) {
                    next();
                } else {
                    res.status(401).send('Not authorized');
                }
            } else {
                res.status(401).send('Not authorized');
            }
        } else {
            // res.status(401).send('Not authorized');
            next()
        }
    });

    /**
     * Limited restrictions!
     *
     * visitors:
     *  * are not allowed at all
     * maintainer:
     *  * not allowed to delete .json files
     * admins:
     *  * allowed to do everything
     */
    app.post('/deleteFile', function (req, res, next) {
        if (packageJSON.config.auth) {
            if (req.session && req.session.isMaintainer || req.session.isAdmin) {
                if (req.session.isAdmin) {
                    next();
                } else if (!/.json/.test(req.query.filename)) {
                    next();
                } else {
                    res.status(401).send('Not authorized');
                }
            } else {
                res.status(401).send('Not authorized');
            }
        } else {
            // res.status(401).send('Not authorized');
            next()
        }
    });
    /**
     * match except for folder dist
     *
     * If the URL has a dot inside it expect to send a files. Otherwise it sends the index.
     */
    app.get(/^((?!^(\/dist)).)*$/, function (req, res) {
        if (/\./.test(req.path)) {
            // contains a . - looks like a file request so check the files system
            fs.exists(decodeURI(opts.fileStorageName + req.path), function (exists) {
                if (exists) {
                    // not sure if it is good by default but - needs to be configurable
                    res.header("Access-Control-Allow-Origin", "*");
                    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

                    if (/\?tmb/.test(req.url)) {

                        thumbNail.create(decodeURI(req.path), function (file) {
                            if (file) {
                                res.sendFile(file);
                            } else {
                                res.sendFile(decodeURI(opts.fileStorageName + req.path));
                            }
                        });

                    } else {
                        res.sendFile(decodeURI(opts.fileStorageName + req.path), {dotfiles : 'allow'});
                    }
                } else {
                    // no file found - send 404 file
                    console.log('main:fileName', __dirname);
                    res.status(404).sendFile(opts.fourOFourFile ? opts.fourOFourFile : __dirname + '/404.html');
                }
            });

        } else {
            // send index
            res.sendFile(opts.dirName + 'index.html');

        }
    });

    app.post('/uploadFile', function (req, res) {
        var fstream, folder = folderUtil.formatFolder(req.query.folder);

        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            // replace all spaces with underscores
            // TODO it's not a good idea to rename file - because there are people they put spaces in a file name
            var fName = filename; //.split(' ').join('_');

            function writeFile() {

                fstream = fs.createWriteStream(opts.fileStorageName + folder + fName);
                file.pipe(fstream);
                fstream.on('close', function () {
                    // TODO add correct type
                    var extension = fName.split('.').pop();
                    if (extension && acceptedImageExtensions.indexOf(extension.toLowerCase()) !== -1) {
                        res.status(200).send({file: folder + fName, name: fName, type: 'image/jpg'});
                    } else {
                        res.status(200).send({file: folder + fName, name: fName, type: extension});
                    }
                });
            }
            changeHistoryLogger.write(opts.fileStorageName, folder + fName, 'upload', req.session.authId || 'anonymous');
            appLifeCycle && appLifeCycle.onUploadFile && appLifeCycle.onUploadFile(req, {
                rootFolder : opts.fileStorageName,
                fileName : folder + fName
            });
            folderUtil.createFolder(opts.fileStorageName, folder, writeFile);
        });
    });

    /**
     * get all available files
     */
    app.post('/getFiles', function (req, res) {
        var folder = '';

        req.on("data", function (chunk) {
            folder += chunk.toString();
        });

        req.on("end", function () {
            folder = folderUtil.formatFolder(folder);
            fs.readdir(opts.fileStorageName + folder, function (err, files) {

                var fileList = [],
                    length;

                if (err === null) {
                    files = files.filter(function (fileName) {
                        return fileName.split('/').pop().startsWith('tmb_') ? undefined : fileName
                    });
                    if (appLifeCycle && appLifeCycle.fileFilter) {
                        files = files.filter(appLifeCycle.fileFilter);
                    }
                    length = files.length;
                    files.forEach(function (file) {
                        fs.stat(opts.fileStorageName + folder + file, function (err, stats) {
                            if (stats.isFile()) {
                                // TODO add correct type
                                var extension = file.split('.').pop();

                                if (extension && acceptedImageExtensions.indexOf(extension.toLowerCase()) !== -1) {
                                    fileList.push({file: folder + file, name: file, type: 'image/jpg'});
                                } else {
                                    fileList.push({file: folder + file, name: file, type: extension});
                                }
                            } else if (stats.isDirectory()) {
                                // filter out directories - if we need directories we should ask separately for it
                                console.log('Found a directory named:', file);
                            }
                            length--;
                            if (length <= 0) {
                                res.status(200).send(fileList);
                            }
                        });
                    });
                }
            });
        });
    });

    /**
     * get all available folders
     */
    app.post('/getFolders', function (req, res) {
        // get a list of all folders
        var folder = '';

        req.on("data", function (chunk) {
            folder += chunk.toString();
        });

        req.on("end", function () {
            folder = folderUtil.formatFolder(folder);
            fs.readdir(opts.fileStorageName + folder, function (err, files) {
                var fileList = [],
                    length;

                if (err === null) {
                    length = files.length;
                    files.forEach(function (file) {
                        fs.stat(opts.fileStorageName + folder + file, function (err, stats) {
                            if (err) {
                                console.log("app:path not exists:", err);
                                return;
                            }
                            if (stats.isDirectory()) {
                                fileList.push(file);
                            }
                            length--;
                            if (length <= 0) {
                                res.status(200).send(fileList);
                            }
                        });
                    });
                }
            });
        });
    });

    /**
     * delete a file
     */
    app.post('/deleteFile', function (req, res) {
        var fileName;
        if (req.query.hasOwnProperty('filename')) {
            fileName = req.query.filename;
            if (fileName[0] !== '/') {
                fileName = '/' + fileName;
            }
            fs.unlink(opts.fileStorageName + fileName, function () {
                changeHistoryLogger.write(opts.fileStorageName, fileName, 'delete', req.session.authId || 'anonymous');
                appLifeCycle && appLifeCycle.onDeleteFile && appLifeCycle.onDeleteFile(req, {
                    rootFolder : opts.fileStorageName,
                    fileName : fileName
                });
                res.status(200).send(req.query.filename);
            });
            thumbNail.remove(fileName);
        } else {
            res.status(200).send(false);
        }
    });

    let server;

    server = app.listen(opts.port, function () {
        console.log('server started on port %d', opts.port);
    });

    // initialize the json persist via websocket
    wsConnection(server, {
        secret : opts.secret,
        dirName : opts.fileStorageName
    });

    return app;
}

module.exports = main;<|endoftext|>


<commit_before>"use strict";

var name = "";
var points = 0;
var gravity;
//Declare global object tetris
var tetris = {};

//Draw the grid --------------------------------------------------
tetris.drawPlayField = function(){

  for(var row = 0; row < 22; row++){
    $('#playfield').append('

');

    for (var col=0;col<10;col++){
      $('tr.'+row).append('	');
    }
  }
}

//Variable to store current coordinates --------------------------

// vart första klossen börjar
tetris.origin = {row:2,col:5};
// vilket typ av kloss som man börjar med
tetris.currentShape = 'L'; // slumpa ist?

tetris.currentCoor;

//Fill the cells -------------------------------------------------
tetris.fillCells = function(coordinates, fillcolor){

  for(var i=0; i < coordinates.length; i++){
    var row = coordinates[i].row;
    var col = coordinates[i].col;
    var $coor = $('.'+row).find('#'+col);
    $coor.attr('bgcolor', fillcolor);
  }
}

/* Funktionen tar en array av koordinater och loopar igenom,
för varje iteration lagras radnumret i den lokala variabeln "row",
samma gäller för colnumret i den lokala variabeln "col". JQuery selektoren lagras
i den lokala variabeln "$coor" - Sen kommer funktionen att byta ut koordinaternas
backgrundsfärg till den färg vi har angett längre ner "currentCoor", i detta fall "black". */

//Move current shape --------------------------------------------
tetris.move = function(direction){
	this.fillCells(this.currentCoor,'');

	//move origin
	if(direction === 'right'){
		this.origin.col++;
	} else if (direction === 'left'){
		this.origin.col--;
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	if(this.ifReverse()){
		if(direction === 'right'){
			this.origin.col--;
		} else if (direction === 'left'){
			this.origin.col++;
		}
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	this.fillCells(this.currentCoor,'black');
}

//Rotera nuvarande figur + efterföljande figurer -----------------------
tetris.rotate = function(){
	var lastShape = this.currentShape;
	this.fillCells(this.currentCoor,'');

	if(this.currentShape === 'L'){
		this.currentShape = 'L90';
	} else if(this.currentShape === 'L90'){
		this.currentShape = 'L180';
	} else if(this.currentShape === 'L180'){
		this.currentShape = 'L270';
	} else if(this.currentShape === 'L270'){
		this.currentShape = 'L';
	} else if(this.currentShape === 'J'){
		this.currentShape = 'J90';
	} else if(this.currentShape === 'J90'){
		this.currentShape = 'J180';
	} else if(this.currentShape === 'J180'){
		this.currentShape = 'J270';
	} else if(this.currentShape === 'J270'){
		this.currentShape = 'J';
	} else if(this.currentShape === 'I'){
		this.currentShape = 'I90';
	} else if(this.currentShape === 'I90'){
		this.currentShape = 'I';
	} else if(this.currentShape === 'S'){
		this.currentShape = 'S90';
	} else if(this.currentShape === 'S90'){
		this.currentShape = 'S';
	} else if(this.currentShape === 'Z'){
		this.currentShape = 'Z90';
	} else if(this.currentShape === 'Z90'){
		this.currentShape = 'Z';
	} else if(this.currentShape === 'T'){
		this.currentShape = 'T90';
	} else if(this.currentShape === 'T90'){
		this.currentShape = 'T180';
	} else if(this.currentShape === 'T180'){
		this.currentShape = 'T270';
	} else if(this.currentShape === 'T270'){
		this.currentShape = 'T';
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	for(var i=0;i<this.currentCoor.length;i++){
		if(this.ifReverse()){
			this.currentShape = lastShape;
		}
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);
	this.fillCells(this.currentCoor,'black');
}

// Definiera tetris-figurer ---------------------------------------------------------
tetris.shapeToCoor = function(shape,origin){
	if (shape === 'L') {
		return [
            { row: origin.row, col: origin.col },
            { row: origin.row - 1, col: origin.col },
            { row: origin.row + 1, col: origin.col },
            { row: origin.row + 1, col: origin.col + 1 }
        ];
	} else if(shape === 'J'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row+1,col:origin.col-1}]
	} else if(shape === 'I'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-2,col:origin.col},{row:origin.row+1,col:origin.col}]
	} else if(shape === 'O'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col+1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'S'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row-1,col:origin.col+1}]
	} else if(shape === 'T'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'Z'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'L90'){
  	return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col-1},{row:origin.row+1,col:origin.col-1}];
  } else if(shape === 'L180'){
  	return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row-1,col:origin.col-1}];
  } else if(shape === 'L270'){
  	return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col-1},{row:origin.row-1,col:origin.col+1}];
  } else if(shape === 'J90'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row-1,col:origin.col-1}]
	} else if(shape === 'J180'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row-1,col:origin.col+1}]
	} else if(shape === 'J270'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row+1,col:origin.col+1}]
	} else if(shape === 'I90'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col+2}]
	} else if(shape === 'S90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col-1},{row:origin.row-2,col:origin.col-1}]
	} else if(shape === 'Z90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col+1},{row:origin.row-2,col:origin.col+1}]
	} else if(shape === 'T90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'T180'){
		return [{row:origin.row,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'T270'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col-1}]
	}
}

/* Definera figurer OCH hur varje figur ska rotera när upp-tangenten trycks ner */

//Drop shape by one row -----------------------------------------------
tetris.drop = function(){
	var reverse = false;

	this.fillCells(this.currentCoor,'');
	this.origin.row++;
	for(var i=0;i<this.currentCoor.length;i++){
		this.currentCoor[i].row++;
		if(this.ifReverse()){
			reverse = true;
		}
	}

	if(reverse){
		for(var i=0;i<this.currentCoor.length;i++){
			this.currentCoor[i].row--;
		}
		this.origin.row--;
	}

	this.fillCells(this.currentCoor,'black');

	if(reverse){
        // game over
        if (this.origin.row == 2) {
            console.log("game over?");
            clearInterval(gravity);

            console.log(name + " fick " + points);
            // spara poäng + spelarens namn i localStorage,
            // visa knapp för att starta om? eller visa highscore

        } else {
            console.log("game continues");
            this.fillCells(this.currentCoor,'BLACK');
            this.emptyFullRow();
            this.spawn();
        }
	}

}

//Spawn random shape -------------------------------------------------
tetris.spawn = function(){
	var random = Math.floor(Math.random()*7);
	var shapeArray = ['L','J','I','O','S','T','Z'];

	this.currentShape = shapeArray[random];
	this.origin = {row:2,col:5};
	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);
}

/* Slumpar fram nya tetris-figurer när den nuvarande har nått botten */

//If we need to reverse  -------------------------------------------------
tetris.ifReverse = function(){
	for(var i=0;i<this.currentCoor.length;i++){
		var row = this.currentCoor[i].row;
		var col = this.currentCoor[i].col;
		var $coor = $('.'+row).find('#'+col);
		if($coor.length === 0 || $coor.attr('bgcolor') === 'BLACK'){
			return true;
		}
	}
	return false;
}

//Empty full row -------------------------------------------------
tetris.emptyFullRow = function(){
	var drops = 0;
	for (var i=21; i>=0;i--){
		var rowIsFull = true;

		for (var j=0;j<10;j++){
			var $coor = $('.'+i).find('#'+j);
			if($coor.attr('bgcolor')!=='BLACK'){
				rowIsFull = false;
			}

			if(drops>0){
				var $newCoor = $('.'+(i+drops)).find('#'+j);
				$newCoor.attr('bgcolor',$coor.attr('bgcolor'));
			}
		}

		if(rowIsFull){
			drops++;
		}
	}
}

// document.ready function - ska alltid vara längst ner ----------------
$(document).ready(function(){
	tetris.drawPlayField();

})

// startar spelet
function startGame() {
	tetris.currentCoor = tetris.shapeToCoor(tetris.currentShape,tetris.origin);
	tetris.fillCells(tetris.currentCoor,'black');

	$(document).keydown(function(e){ // Känner av piltangenterna
		console.log(e.keyCode);
		if(e.keyCode === 39){
			tetris.move('right');
		} else if (e.keyCode === 37){
			tetris.move('left');
		} else if (e.keyCode === 38){
			tetris.rotate();
		} else if (e.keyCode === 40){ // tryck på ner-tangenten och hela figuren droppas!
			tetris.drop();
		}
	})

	// Global
	gravity = setInterval(function(){
		tetris.drop();
        // skriv ut den nuvarande klossens position (för färger) och positionen på spelplanen (origin)
        // console.log(tetris.currentCoor, tetris.origin);
	},500); // Ändra hastigheten här, i millisekunder
}

//---------------------- START GAME -------------------------

var startButton = document.getElementById("start-game");

startButton.addEventListener("click", function() {
    var username = prompt("name");

    if (username !== null) {
        // spara det namn personen fyllde i, i den globala variabeln "name"
        name = username;
        startGame(); // starta spelet
    } else {
        console.log("empty name...");
    }

});

//---------------------- GAME OVER -------------------------
 var button = document.getElementById("game-over");

 button.addEventListener("click", function() {
     // Här prövar vi biblioteket
      swal("Good job!", "You clicked the button!", "success");
 });

<commit_msg>localStorage grej<commit_after>"use strict";

var highScores;

if(localStorage.getItem("highScores")) {
    highScores = JSON.parse(localStorage.getItem("highScores"));
} else {
    highScores = [];
}

var name = "";
var points = 0;
var gravity;
//Declare global object tetris
var tetris = {};

//Draw the grid --------------------------------------------------
tetris.drawPlayField = function(){

  for(var row = 0; row < 22; row++){
    $('#playfield').append('

');

    for (var col=0;col<10;col++){
      $('tr.'+row).append('	');
    }
  }
}

//Variable to store current coordinates --------------------------

// vart första klossen börjar
tetris.origin = {row:2,col:5};
// vilket typ av kloss som man börjar med
tetris.currentShape = 'L'; // slumpa ist?

tetris.currentCoor;

//Fill the cells -------------------------------------------------
tetris.fillCells = function(coordinates, fillcolor){

  for(var i=0; i < coordinates.length; i++){
    var row = coordinates[i].row;
    var col = coordinates[i].col;
    var $coor = $('.'+row).find('#'+col);
    $coor.attr('bgcolor', fillcolor);
  }
}

/* Funktionen tar en array av koordinater och loopar igenom,
för varje iteration lagras radnumret i den lokala variabeln "row",
samma gäller för colnumret i den lokala variabeln "col". JQuery selektoren lagras
i den lokala variabeln "$coor" - Sen kommer funktionen att byta ut koordinaternas
backgrundsfärg till den färg vi har angett längre ner "currentCoor", i detta fall "black". */

//Move current shape --------------------------------------------
tetris.move = function(direction){
	this.fillCells(this.currentCoor,'');

	//move origin
	if(direction === 'right'){
		this.origin.col++;
	} else if (direction === 'left'){
		this.origin.col--;
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	if(this.ifReverse()){
		if(direction === 'right'){
			this.origin.col--;
		} else if (direction === 'left'){
			this.origin.col++;
		}
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	this.fillCells(this.currentCoor,'black');
}

//Rotera nuvarande figur + efterföljande figurer -----------------------
tetris.rotate = function(){
	var lastShape = this.currentShape;
	this.fillCells(this.currentCoor,'');

	if(this.currentShape === 'L'){
		this.currentShape = 'L90';
	} else if(this.currentShape === 'L90'){
		this.currentShape = 'L180';
	} else if(this.currentShape === 'L180'){
		this.currentShape = 'L270';
	} else if(this.currentShape === 'L270'){
		this.currentShape = 'L';
	} else if(this.currentShape === 'J'){
		this.currentShape = 'J90';
	} else if(this.currentShape === 'J90'){
		this.currentShape = 'J180';
	} else if(this.currentShape === 'J180'){
		this.currentShape = 'J270';
	} else if(this.currentShape === 'J270'){
		this.currentShape = 'J';
	} else if(this.currentShape === 'I'){
		this.currentShape = 'I90';
	} else if(this.currentShape === 'I90'){
		this.currentShape = 'I';
	} else if(this.currentShape === 'S'){
		this.currentShape = 'S90';
	} else if(this.currentShape === 'S90'){
		this.currentShape = 'S';
	} else if(this.currentShape === 'Z'){
		this.currentShape = 'Z90';
	} else if(this.currentShape === 'Z90'){
		this.currentShape = 'Z';
	} else if(this.currentShape === 'T'){
		this.currentShape = 'T90';
	} else if(this.currentShape === 'T90'){
		this.currentShape = 'T180';
	} else if(this.currentShape === 'T180'){
		this.currentShape = 'T270';
	} else if(this.currentShape === 'T270'){
		this.currentShape = 'T';
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);

	for(var i=0;i<this.currentCoor.length;i++){
		if(this.ifReverse()){
			this.currentShape = lastShape;
		}
	}

	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);
	this.fillCells(this.currentCoor,'black');
}

// Definiera tetris-figurer ---------------------------------------------------------
tetris.shapeToCoor = function(shape,origin){
	if (shape === 'L') {
		return [
            { row: origin.row, col: origin.col },
            { row: origin.row - 1, col: origin.col },
            { row: origin.row + 1, col: origin.col },
            { row: origin.row + 1, col: origin.col + 1 }
        ];
	} else if(shape === 'J'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row+1,col:origin.col-1}]
	} else if(shape === 'I'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-2,col:origin.col},{row:origin.row+1,col:origin.col}]
	} else if(shape === 'O'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col+1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'S'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row-1,col:origin.col+1}]
	} else if(shape === 'T'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'Z'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'L90'){
  	return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col-1},{row:origin.row+1,col:origin.col-1}];
  } else if(shape === 'L180'){
  	return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row-1,col:origin.col-1}];
  } else if(shape === 'L270'){
  	return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col-1},{row:origin.row-1,col:origin.col+1}];
  } else if(shape === 'J90'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row-1,col:origin.col-1}]
	} else if(shape === 'J180'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row-1,col:origin.col+1}]
	} else if(shape === 'J270'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row+1,col:origin.col+1}]
	} else if(shape === 'I90'){
		return [{row:origin.row,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1},{row:origin.row,col:origin.col+2}]
	} else if(shape === 'S90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col-1},{row:origin.row-2,col:origin.col-1}]
	} else if(shape === 'Z90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row-1,col:origin.col+1},{row:origin.row-2,col:origin.col+1}]
	} else if(shape === 'T90'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'T180'){
		return [{row:origin.row,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col-1},{row:origin.row,col:origin.col+1}]
	} else if(shape === 'T270'){
		return [{row:origin.row,col:origin.col},{row:origin.row-1,col:origin.col},{row:origin.row+1,col:origin.col},{row:origin.row,col:origin.col-1}]
	}
}

/* Definera figurer OCH hur varje figur ska rotera när upp-tangenten trycks ner */

//Drop shape by one row -----------------------------------------------
tetris.drop = function(){
	var reverse = false;

	this.fillCells(this.currentCoor,'');
	this.origin.row++;
	for(var i=0;i<this.currentCoor.length;i++){
		this.currentCoor[i].row++;
		if(this.ifReverse()){
			reverse = true;
		}
	}

	if(reverse){
		for(var i=0;i<this.currentCoor.length;i++){
			this.currentCoor[i].row--;
		}
		this.origin.row--;
	}

	this.fillCells(this.currentCoor,'black');

	if(reverse){
        // game over
        if (this.origin.row == 2) {
            console.log("game over?");
            clearInterval(gravity);

            console.log(name + " fick " + points);
            highScores.push({ name: name, points: points });
            console.log(highScores);
            localStorage.setItem("highScores", JSON.stringify(highScores));
            // spara poäng + spelarens namn i localStorage,
            // visa knapp för att starta om? eller visa highscore

        } else {
            console.log("game continues");
            this.fillCells(this.currentCoor,'BLACK');
            this.emptyFullRow();
            this.spawn();
        }
	}

}

//Spawn random shape -------------------------------------------------
tetris.spawn = function(){
	var random = Math.floor(Math.random()*7);
	var shapeArray = ['L','J','I','O','S','T','Z'];

	this.currentShape = shapeArray[random];
	this.origin = {row:2,col:5};
	this.currentCoor = this.shapeToCoor(this.currentShape,this.origin);
}

/* Slumpar fram nya tetris-figurer när den nuvarande har nått botten */

//If we need to reverse  -------------------------------------------------
tetris.ifReverse = function(){
	for(var i=0;i<this.currentCoor.length;i++){
		var row = this.currentCoor[i].row;
		var col = this.currentCoor[i].col;
		var $coor = $('.'+row).find('#'+col);
		if($coor.length === 0 || $coor.attr('bgcolor') === 'BLACK'){
			return true;
		}
	}
	return false;
}

//Empty full row -------------------------------------------------
tetris.emptyFullRow = function(){
	var drops = 0;
	for (var i=21; i>=0;i--){
		var rowIsFull = true;

		for (var j=0;j<10;j++){
			var $coor = $('.'+i).find('#'+j);
			if($coor.attr('bgcolor')!=='BLACK'){
				rowIsFull = false;
			}

			if(drops>0){
				var $newCoor = $('.'+(i+drops)).find('#'+j);
				$newCoor.attr('bgcolor',$coor.attr('bgcolor'));
			}
		}

		if(rowIsFull){
			drops++;
		}
	}
}

// document.ready function - ska alltid vara längst ner ----------------
$(document).ready(function(){
	tetris.drawPlayField();

})

// startar spelet
function startGame() {
	tetris.currentCoor = tetris.shapeToCoor(tetris.currentShape,tetris.origin);
	tetris.fillCells(tetris.currentCoor,'black');

	$(document).keydown(function(e){ // Känner av piltangenterna
		console.log(e.keyCode);
		if(e.keyCode === 39){
			tetris.move('right');
		} else if (e.keyCode === 37){
			tetris.move('left');
		} else if (e.keyCode === 38){
			tetris.rotate();
		} else if (e.keyCode === 40){ // tryck på ner-tangenten och hela figuren droppas!
			tetris.drop();
		}
	})

	// Global
	gravity = setInterval(function(){
		tetris.drop();
        // skriv ut den nuvarande klossens position (för färger) och positionen på spelplanen (origin)
        // console.log(tetris.currentCoor, tetris.origin);
	},500); // Ändra hastigheten här, i millisekunder
}

//---------------------- START GAME -------------------------

var startButton = document.getElementById("start-game");

startButton.addEventListener("click", function() {
    var username = prompt("name");

    if (username !== null) {
        // spara det namn personen fyllde i, i den globala variabeln "name"
        name = username;
        startGame(); // starta spelet
    } else {
        console.log("empty name...");
    }

});

//---------------------- GAME OVER -------------------------
 var button = document.getElementById("game-over");

 button.addEventListener("click", function() {
     // Här prövar vi biblioteket
      swal("Good job!", "You clicked the button!", "success");
 });

<|endoftext|>


<commit_before>// JP pref list
// TODO: more plain format (using DB?)
const PREF_HOKKAIDO = ["北海道"];
const PREF_TOHOKU   = ["青森県", "岩手県", "秋田県", "宮城県", "山形県", "福島県"];
const PREF_KANTO    = ["茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県"];
const PREF_CHUBU    = ["山梨県", "長野県", "新潟県", "富山県", "石川県", "福井県", "静岡県", "愛知県", "岐阜県"];
const PREF_KINKI    = ["三重県", "滋賀県", "京都府", "大阪府", "兵庫県", "奈良県", "和歌山県"];
const PREF_CHUGOKU  = ["鳥取県", "島根県", "岡山県", "広島県", "山口県"];
const PREF_SHIKOKU  = ["香川県", "愛媛県", "徳島県", "高知県"];
const PREF_KYUSHU   = ["福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"];
var PREF_ALL = new Array();

// Bootstrap button className define
// choose from: default, primary, success, info, warning, danger, link
const BTN_CLASSNAME_CAN_BE_SELECTED     = 'btn btn-primary';
const BTN_CLASSNAME_CAN_NOT_BE_SELECTED = 'btn btn-default';
const BTN_CLASSNAME_NOW_SELECTED        = 'btn btn-warning';

// const parameters
const ROULETTE_SPEED   = 300;  // [ms]
const TIME_TO_STOP_MIN = 3000; // [ms]
const TIME_TO_STOP_MAX = 7000; // [ms]

// other global var
var gPrefIdx = new Array();
var gPrefElem;                 // used as "gPrefElem[gPrefIdx[i]]"
var gNowSelected = 0;
var gRouletteTimeoutID;

function changeButtonStatus(e) {
  if(e.className == BTN_CLASSNAME_CAN_BE_SELECTED) {
    e.className = BTN_CLASSNAME_CAN_NOT_BE_SELECTED;
  }
  else {
    e.className = BTN_CLASSNAME_CAN_BE_SELECTED;
  }
}

function loopRoulette() {
  moveRoulette();
  gRouletteTimeoutID = setTimeout(loopRoulette, ROULETTE_SPEED);
}

// FIXME: this might be a very slow function
function moveRoulette() {
  var idx_old = gNowSelected-1;
  if(idx_old < 0) {
    idx_old = gPrefIdx.length-1;
  }
  gPrefElem[gPrefIdx[idx_old]].className = BTN_CLASSNAME_CAN_BE_SELECTED;
  gPrefElem[gPrefIdx[gNowSelected]].className = BTN_CLASSNAME_NOW_SELECTED;
  gNowSelected = (gNowSelected+1)%gPrefIdx.length;
}

function startRoulette(e) {
  e.disabled = true;
  var elem = document.getElementsByName("pref");
  var length_org = PREF_ALL.length;
  for(var i=0; i<length_org; i++) {
    if(elem[i].className == BTN_CLASSNAME_CAN_NOT_BE_SELECTED) {
      elem[i].disabled = true;
    }
    else {
      gPrefIdx.push(i);
    }
  }
  gPrefElem = document.getElementsByName("pref");
  loopRoulette();
}

function stopRoulette(e) {
  e.disabled = true;
  setTimeout(function() {clearTimeout(gRouletteTimeoutID)}, TIME_TO_STOP_MAX*Math.random()+TIME_TO_STOP_MIN);
}

function init() {
  function mergepref() {
    Array.prototype.push.apply(PREF_ALL, PREF_HOKKAIDO);
    Array.prototype.push.apply(PREF_ALL, PREF_TOHOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_KANTO);
    Array.prototype.push.apply(PREF_ALL, PREF_CHUBU);
    Array.prototype.push.apply(PREF_ALL, PREF_KINKI);
    Array.prototype.push.apply(PREF_ALL, PREF_CHUGOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_SHIKOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_KYUSHU);
  }

  function createBtnHtml(btnLabel) {
    var btnHtml = "<button type='button' name='pref' class='" + BTN_CLASSNAME_CAN_BE_SELECTED + "' onclick='changeButtonStatus(this)'>";
    btnHtml += btnLabel + "</button>";
    return btnHtml;
  }

  mergepref();

  btnInnerHtml = "";
  for(var i=0; i<PREF_ALL.length; i++) {
    btnInnerHtml += createBtnHtml(PREF_ALL[i]);
  }
  document.getElementById("prefBtnID").innerHTML = btnInnerHtml;
}
<commit_msg>change btn's act<commit_after>// JP pref list
// TODO: more plain format (using DB?)
const PREF_HOKKAIDO = ["北海道"];
const PREF_TOHOKU   = ["青森県", "岩手県", "秋田県", "宮城県", "山形県", "福島県"];
const PREF_KANTO    = ["茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県"];
const PREF_CHUBU    = ["山梨県", "長野県", "新潟県", "富山県", "石川県", "福井県", "静岡県", "愛知県", "岐阜県"];
const PREF_KINKI    = ["三重県", "滋賀県", "京都府", "大阪府", "兵庫県", "奈良県", "和歌山県"];
const PREF_CHUGOKU  = ["鳥取県", "島根県", "岡山県", "広島県", "山口県"];
const PREF_SHIKOKU  = ["香川県", "愛媛県", "徳島県", "高知県"];
const PREF_KYUSHU   = ["福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"];
var PREF_ALL = new Array();

// Bootstrap button className define
// choose from: default, primary, success, info, warning, danger, link
const BTN_CLASSNAME_CAN_BE_SELECTED     = 'btn btn-primary';
const BTN_CLASSNAME_CAN_NOT_BE_SELECTED = 'btn btn-default';
const BTN_CLASSNAME_NOW_SELECTED        = 'btn btn-warning';

// const parameters
const ROULETTE_SPEED   = 300;  // [ms]
const TIME_TO_STOP_MIN = 3000; // [ms]
const TIME_TO_STOP_MAX = 7000; // [ms]

// other global var
var gPrefIdx = new Array();
var gPrefElem;                 // used as "gPrefElem[gPrefIdx[i]]"
var gNowSelected = 0;
var gRouletteTimeoutID;

function changeButtonStatus(e) {
  if(e.className == BTN_CLASSNAME_CAN_BE_SELECTED) {
    e.className = BTN_CLASSNAME_CAN_NOT_BE_SELECTED;
  }
  else {
    e.className = BTN_CLASSNAME_CAN_BE_SELECTED;
  }
}

function loopRoulette() {
  moveRoulette();
  gRouletteTimeoutID = setTimeout(loopRoulette, ROULETTE_SPEED);
}

// FIXME: this might be a very slow function
function moveRoulette() {
  var idx_old = gNowSelected-1;
  if(idx_old < 0) {
    idx_old = gPrefIdx.length-1;
  }
  gPrefElem[gPrefIdx[idx_old]].className = BTN_CLASSNAME_CAN_BE_SELECTED;
  gPrefElem[gPrefIdx[gNowSelected]].className = BTN_CLASSNAME_NOW_SELECTED;
  gNowSelected = (gNowSelected+1)%gPrefIdx.length;
}

function startRoulette(e) {
  e.disabled = true;
  var elem = document.getElementsByName("pref");
  var length_org = PREF_ALL.length;
  for(var i=0; i<length_org; i++) {
    elem[i].onclick = "";
    if(elem[i].className == BTN_CLASSNAME_CAN_BE_SELECTED) {
      gPrefIdx.push(i);
    }
    else {
      elem[i].disabled = true;
    }
  }
  gPrefElem = document.getElementsByName("pref");
  loopRoulette();
}

function stopRoulette(e) {
  e.disabled = true;
  setTimeout(function() {clearTimeout(gRouletteTimeoutID)}, TIME_TO_STOP_MAX*Math.random()+TIME_TO_STOP_MIN);
}

function init() {
  function mergepref() {
    Array.prototype.push.apply(PREF_ALL, PREF_HOKKAIDO);
    Array.prototype.push.apply(PREF_ALL, PREF_TOHOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_KANTO);
    Array.prototype.push.apply(PREF_ALL, PREF_CHUBU);
    Array.prototype.push.apply(PREF_ALL, PREF_KINKI);
    Array.prototype.push.apply(PREF_ALL, PREF_CHUGOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_SHIKOKU);
    Array.prototype.push.apply(PREF_ALL, PREF_KYUSHU);
  }

  function createBtnHtml(btnLabel) {
    var btnHtml = "<button type='button' name='pref' class='" + BTN_CLASSNAME_CAN_BE_SELECTED + "' onclick='changeButtonStatus(this)'>";
    btnHtml += btnLabel + "</button>";
    return btnHtml;
  }

  mergepref();

  btnInnerHtml = "";
  for(var i=0; i<PREF_ALL.length; i++) {
    btnInnerHtml += createBtnHtml(PREF_ALL[i]);
  }
  document.getElementById("prefBtnID").innerHTML = btnInnerHtml;
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

"use strict";

var express = require('express');
var twig = require('twig');
//var utils = require('./utils.js');

var app = express();
app.use(express.logger());

app.use('/bootstrap', express.static(__dirname + '/bootstrap'));
app.use('/img', express.static(__dirname + '/img'));

//utils.dbConnect();

app.get('/node/', function(request, response) {
	response.send('Node.js is up and running.');
});

/*
app.get('/', function(request, response) {
	response.redirect('/about/');
});

app.get('/about/', function(request, response) {
	var t = Date.now();
	var options = {};
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about.twig', options);
	console.log(request.path+' - done in '+(Date.now()-t)+' ms');
});
*/

/***** main *****/
var port = process.env.PORT || 5000;
app.listen(port, function() {
	console.log("Listening on " + port);
	if (port==5000) console.log("Try http://localhost:" + port + "/");
});
<commit_msg>Add very basic Node-to-PHP gate.<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

"use strict";

var express = require('express');
var twig = require('twig');
//var utils = require('./utils.js');

var app = express();
app.use(express.logger());

app.use('/bootstrap', express.static(__dirname + '/bootstrap'));
app.use('/img', express.static(__dirname + '/img'));

//utils.dbConnect();

app.get('/node/', function(request, response) {
	response.send('Node.js is up and running.');
});

function phpgate(request, response)
{
	var child_process = require('child_process');
	child_process.execFile('php', ['index.php'], {}, function (error, stdout, stderr) {
		console.log('PHP stdout: ' + stdout);
		console.log('PHP stderr: ' + stderr);
		if (error !== null) {
			console.log('PHP exec error: ' + error);
			response.send('PHP gate error. See console for details.');
		}
		response.send(stdout);
	});
}

app.get('/', phpgate);
app.get('/about/', phpgate);
app.get('/register/', phpgate);
app.post('/register/', phpgate);
app.get('/login/', phpgate);
app.post('/login/', phpgate);
app.post('/profile/', phpgate);
//app.post('/profile/id/{id}/', phpgate);
//app.post('/profile/user/{user}/', phpgate);
app.get('/action/logout', phpgate);
app.get('/game/', phpgate);
//app.get('/action/go/{to}', phpgate);
app.get('/action/attack', phpgate);
app.get('/action/escape', phpgate);
//app.get('/ajax/isNickBusy/{nick}', phpgate);
app.get('/stats/', phpgate);
app.get('/world/', phpgate);
app.get('/development/', phpgate);

/*
app.get('/', function(request, response) {
	response.redirect('/about/');
});

app.get('/about/', function(request, response) {
	var t = Date.now();
	var options = {};
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about.twig', options);
	console.log(request.path+' - done in '+(Date.now()-t)+' ms');
});
*/

/***** main *****/
var port = process.env.PORT || 5000;
app.listen(port, function() {
	console.log("Listening on " + port);
	if (port==5000) console.log("Try http://localhost:" + port + "/");
});
<|endoftext|>