<commit_before>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app'),
  assetRev = require('broccoli-asset-rev'),
  htmlmin = require('broccoli-htmlmin'),
  Funnel = require('broccoli-funnel'),
  extraAssets, tree, sherlogScript;

var app = new EmberApp({
  storeConfigInMeta: false
});

app.import('vendor/scripts/jquery.drawPieChart.js');

app.import('bower_components/socket.io-client/socket.io.js');
app.import('bower_components/ember-sockets/dist/ember-sockets.js');
app.import('bower_components/ember-uploader/dist/ember-uploader.js');
app.import('bower_components/animate.css/animate.min.css');

/*
 * No VNC includes
 */
app.import('bower_components/no-vnc/include/util.js');
app.import('bower_components/no-vnc/include/webutil.js');
app.import('bower_components/no-vnc/include/base64.js');
app.import('bower_components/no-vnc/include/websock.js');
app.import('bower_components/no-vnc/include/des.js');
app.import('bower_components/no-vnc/include/keysymdef.js');
app.import('bower_components/no-vnc/include/keyboard.js');
app.import('bower_components/no-vnc/include/input.js');
app.import('bower_components/no-vnc/include/display.js');
app.import('bower_components/no-vnc/include/jsunzip.js');
app.import('bower_components/no-vnc/include/rfb.js');
app.import('bower_components/no-vnc/include/keysym.js');

if (app.env == 'production') {
  extraAssets = new Funnel('vendor/scripts', {
    srcDir: '/',
    include: ['sherlog.js'],
    destDir: '/assets'
  });
}
else{
  app.import('vendor/scripts/sherlog-dev.js');
}

if (app.env == 'production') {
  app.import('bower_components/raven-js/dist/raven.min.js');
}
else {
  app.import('bower_components/raven-js/dist/raven.js');
}

app.import('bower_components/raven-js/plugins/jquery.js');
app.import('bower_components/raven-js/plugins/native.js');
app.import('bower_components/raven-js/plugins/console.js');

tree = app.toTree(extraAssets);

options = {
  quotes: true
};

if (app.env == 'production') {
  tree = assetRev(tree, {
    enabled: true,
    extensions: ['js', 'css', 'png', 'jpg', 'gif'],
    replaceExtensions: ['html', 'js', 'css'],
    prepend: '//du6tdhcax0qep.cloudfront.net/'
  });
  tree = htmlmin(tree, options);
}

if (app.env == 'staging') {
  tree = assetRev(tree, {
    enabled: true,
    extensions: ['js', 'css', 'png', 'jpg', 'gif'],
    replaceExtensions: ['html', 'js', 'css'],
    prepend: '//sherlock-assets-staging.s3-us-west-2.amazonaws.com/'
  });
}

module.exports = tree;
<commit_msg>removing unwanted plugins<commit_after>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app'),
  assetRev = require('broccoli-asset-rev'),
  htmlmin = require('broccoli-htmlmin'),
  Funnel = require('broccoli-funnel'),
  extraAssets, tree, sherlogScript;

var app = new EmberApp({
  storeConfigInMeta: false
});

app.import('vendor/scripts/jquery.drawPieChart.js');

app.import('bower_components/socket.io-client/socket.io.js');
app.import('bower_components/ember-sockets/dist/ember-sockets.js');
app.import('bower_components/ember-uploader/dist/ember-uploader.js');
app.import('bower_components/animate.css/animate.min.css');

/*
 * No VNC includes
 */
app.import('bower_components/no-vnc/include/util.js');
app.import('bower_components/no-vnc/include/webutil.js');
app.import('bower_components/no-vnc/include/base64.js');
app.import('bower_components/no-vnc/include/websock.js');
app.import('bower_components/no-vnc/include/des.js');
app.import('bower_components/no-vnc/include/keysymdef.js');
app.import('bower_components/no-vnc/include/keyboard.js');
app.import('bower_components/no-vnc/include/input.js');
app.import('bower_components/no-vnc/include/display.js');
app.import('bower_components/no-vnc/include/jsunzip.js');
app.import('bower_components/no-vnc/include/rfb.js');
app.import('bower_components/no-vnc/include/keysym.js');

if (app.env == 'production') {
  extraAssets = new Funnel('vendor/scripts', {
    srcDir: '/',
    include: ['sherlog.js'],
    destDir: '/assets'
  });
}
else{
  app.import('vendor/scripts/sherlog-dev.js');
}

if (app.env == 'production') {
  app.import('bower_components/raven-js/dist/raven.min.js');
}
else {
  app.import('bower_components/raven-js/dist/raven.js');
}

tree = app.toTree(extraAssets);

options = {
  quotes: true
};

if (app.env == 'production') {
  tree = assetRev(tree, {
    enabled: true,
    extensions: ['js', 'css', 'png', 'jpg', 'gif'],
    replaceExtensions: ['html', 'js', 'css'],
    prepend: '//du6tdhcax0qep.cloudfront.net/'
  });
  tree = htmlmin(tree, options);
}

if (app.env == 'staging') {
  tree = assetRev(tree, {
    enabled: true,
    extensions: ['js', 'css', 'png', 'jpg', 'gif'],
    replaceExtensions: ['html', 'js', 'css'],
    prepend: '//sherlock-assets-staging.s3-us-west-2.amazonaws.com/'
  });
}

module.exports = tree;
<|endoftext|>


<commit_before>// saved buffer

var saveFlowTimeout = null;
var wordcount = 0;
var score = 0;
var sv_time = 0;
var flowing = false;

var game_started = false;
var game_start_time = null;
var game_mode = null;
var timer_goal = null;
var wordcount_goal = null;
var puppies_mode = null;
var final_game_length = null;

function saveFlow() {
    var text = $('#playingfield').val();
    var chars = text.length;
    var words = getWordCount(text);
    var flow_time = getElapsedSeconds(sv_time);

    freezeFlowAndReset(text);

    wordcount += words;
    current_score = getScore(text, flow_time);
    score += current_score;

    updateFlowStatus();
    displayEncouragement(current_score);

    if (checkEndGame()) {
        endGame();
    }

    flowing = false;
}

function checkEndGame() {
    if (game_mode == "wordcount" && wordcount >= wordcount_goal) {
        return true;
    }
    if (game_mode == "timer" && getElapsedSeconds(game_start_time) >= timer_goal) {
        return true;
    }
    return false;
}

function endGame() {
    final_game_length = getElapsedSeconds(game_start_time);
    // pop up a modal
    // set game end time, compute final stats
    // model can ask for a title
}

function displayEncouragement(score) {
    var word;
    word = "poor";
    if (score > 50) { word = "okay"; }
    if (score > 75) { word = "fair"; }
    if (score > 125) { word = "cool"; }
    if (score > 200) { word = "nice"; }
    if (score > 300) { word = "sweet"; }
    if (score > 400) { word = "great"; }
    if (score > 600) { word = "awesome"; }
    if (score > 800) { word = "amazing"; }
    if (score > 1000) { word = "incredible"; }
    if (score > 1400) { word = "spectacular"; }
    if (score > 1800) { word = "unbelievable"; }
    if (score > 2200) { word = "extraordinary"; }
    $('.encouragement').html("
" + word + " flow!
");
    $('.encouragement').css("display", "block");
}

function hideEncouragement() {
    $('.encouragement').css("display", "none");
}

function freezeFlowAndReset(text) {
    $('.btn-save').before("

" + text + "\n" + "

");
    $('#playingfield').val("");
}

function scoreBoardUpdate(wordcount, score, words, this_score) {
    var total_wordcount = wordcount + words;
    var total_score = score + this_score;
    if (game_mode == "wordcount") {
        countdown = "| Words left: " + (wordcount_goal - total_wordcount) + ""
    }
    if (game_mode == "timer") {
        countdown = "| Secs left: " + (timer_goal - getElapsedSeconds(game_start_time)).toFixed(1) + ""
    }
    $('#scoreboard').html("
Words: " + total_wordcount + " | Score: " + total_score + " " + countdown + "
");
}

function scroll() {
    $("html, body").animate({ scrollTop: $('#playingfield').offset().top }, "slow");
}

// scores should be higher the longer the text is
// scores should be higher the longer the time is
// scores should be higher the higher the ratio of text to time is
function getScore(text, time) {
    var chars = text.length;
    var words = getWordCount(text);
    var wpm = (words / time) * 60;
    var score = Math.round(words*5*wpm/40);

    return score;
}

function getWordCount(text) {
    if (text == "") {
        return 0;
    }

    s = text.replace(/(^\s*)|(\s*$)/gi,"");
    s = s.replace(/[ ]{2,}/gi," ");
    s = s.replace(/\n /,"\n");
    return s.split(' ').length;
}

updateFlowStatus = function() {
    var text = $('#playingfield').val();
    var chars = text.length;
    var words = getWordCount(text);
    var seconds = getElapsedSeconds(sv_time);
    var wpm = Math.round(words / seconds * 60);
    $('.stats').html('
Words: ' + words + ' (+' + words*5 + ' pts) | WPM: ' + wpm + ' (x' + (wpm / 40).toFixed(1) + ' bonus)

');
    var this_score = getScore(text, seconds);

    scoreBoardUpdate(wordcount, score, words, this_score);
    // if (wordcount >= 500) {
    //     $('.btn-save').css('display', 'block');
    //     $('.btn-save').on('click', function() {
    //         saveFlowToServer();
    //     });
    // }
}

function startGame() {
    game_mode = $('#tekst-mode').val();
    wordcount_goal = parseInt($('#tekst-wordcount').val());
    // seconds
    timer_goal = 60 * parseInt($('#tekst-timer').val());
    puppies_mode = $('#tekst-puppies').val();

    game_start_time = getTime();
    game_started = true;
    window.setInterval(updateFlowStatus, 100);
}

function startNewFlow() {
    sv_time = getTime();
    hideEncouragement();
    flowing = true;
}

updateFlowState = function() {
    if (! game_started) {
        startGame();
    }
    if (! flowing) {
        startNewFlow();
    }
    if (saveFlowTimeout) {
        window.clearTimeout(saveFlowTimeout);
    }

    updateFlowStatus();

    saveFlowTimeout = window.setTimeout(saveFlow, 500);
}

function getTime() {
    return (new Date).getTime();
}

function getElapsedSeconds(time) {
    return (getTime() - time) / 1000;
}

document.getElementById("playingfield").oninput = updateFlowState;

function saveFlowToServer() {
    $('.flow-save').css('display', 'block');
    saveFlow();
    var total_text = $('.text-content').text();
    $.post('/flow', { text: total_text, score: score, mode: game_mode, timer: final_game_length, wordcount: wordcount, title: title });
}
<commit_msg>Add tracking of highest wpm and longest streak to JS<commit_after>// Game state vars
var saveFlowTimeout = null;
var wordcount = 0;
var score = 0;
var sv_time = 0;
var flowing = false;

// Game mode vars
var game_started = false;
var game_start_time = null;
var game_mode = null;
var timer_goal = null;
var wordcount_goal = null;
var puppies_mode = null;
var final_game_length = null;

// Stats collection vars
var longest_flow = -1;
var highest_wpm = -1;

function saveFlow() {
    var text = $('#playingfield').val();
    var chars = text.length;
    var words = getWordCount(text);
    var flow_time = getElapsedSeconds(sv_time);

    freezeFlowAndReset(text);

    wordcount += words;
    current_score = getScore(text, flow_time);
    score += current_score;

    if (words > longest_flow) {
        longest_flow = words;
    }

    updateFlowStatus();
    displayEncouragement(current_score);

    if (checkEndGame()) {
        endGame();
    }

    flowing = false;
}

function checkEndGame() {
    if (game_mode == "wordcount" && wordcount >= wordcount_goal) {
        return true;
    }
    if (game_mode == "timer" && getElapsedSeconds(game_start_time) >= timer_goal) {
        return true;
    }
    return false;
}

function endGame() {
    final_game_length = getElapsedSeconds(game_start_time);
    // pop up a modal
    // set game end time, compute final stats
    // model can ask for a title
}

function displayEncouragement(score) {
    var word;
    word = "poor";
    if (score > 50) { word = "okay"; }
    if (score > 75) { word = "fair"; }
    if (score > 125) { word = "cool"; }
    if (score > 200) { word = "nice"; }
    if (score > 300) { word = "sweet"; }
    if (score > 400) { word = "great"; }
    if (score > 600) { word = "awesome"; }
    if (score > 800) { word = "amazing"; }
    if (score > 1000) { word = "incredible"; }
    if (score > 1400) { word = "spectacular"; }
    if (score > 1800) { word = "unbelievable"; }
    if (score > 2200) { word = "extraordinary"; }
    $('.encouragement').html("
" + word + " flow!
");
    $('.encouragement').css("display", "block");
}

function hideEncouragement() {
    $('.encouragement').css("display", "none");
}

function freezeFlowAndReset(text) {
    $('.btn-save').before("

" + text + "\n" + "

");
    $('#playingfield').val("");
}

function scoreBoardUpdate(wordcount, score, words, this_score) {
    var total_wordcount = wordcount + words;
    var total_score = score + this_score;
    if (game_mode == "wordcount") {
        countdown = "| Words left: " + (wordcount_goal - total_wordcount) + ""
    }
    if (game_mode == "timer") {
        countdown = "| Secs left: " + (timer_goal - getElapsedSeconds(game_start_time)).toFixed(1) + ""
    }
    $('#scoreboard').html("
Words: " + total_wordcount + " | Score: " + total_score + " " + countdown + "
");
}

function scroll() {
    $("html, body").animate({ scrollTop: $('#playingfield').offset().top }, "slow");
}

// scores should be higher the longer the text is
// scores should be higher the longer the time is
// scores should be higher the higher the ratio of text to time is
function getScore(text, time) {
    var chars = text.length;
    var words = getWordCount(text);
    var wpm = (words / time) * 60;
    var score = Math.round(words*5*wpm/40);

    return score;
}

function getWordCount(text) {
    if (text == "") {
        return 0;
    }

    s = text.replace(/(^\s*)|(\s*$)/gi,"");
    s = s.replace(/[ ]{2,}/gi," ");
    s = s.replace(/\n /,"\n");
    return s.split(' ').length;
}

updateFlowStatus = function() {
    var text = $('#playingfield').val();
    var chars = text.length;
    var words = getWordCount(text);
    var seconds = getElapsedSeconds(sv_time);
    var wpm = Math.round(words / seconds * 60);
    $('.stats').html('
Words: ' + words + ' (+' + words*5 + ' pts) | WPM: ' + wpm + ' (x' + (wpm / 40).toFixed(1) + ' bonus)

');
    var this_score = getScore(text, seconds);

    if (wpm > highest_wpm) {
        highest_wpm = wpm;
    }

    scoreBoardUpdate(wordcount, score, words, this_score);
    // if (wordcount >= 500) {
    //     $('.btn-save').css('display', 'block');
    //     $('.btn-save').on('click', function() {
    //         saveFlowToServer();
    //     });
    // }
}

function startGame() {
    game_mode = $('#tekst-mode').val();
    wordcount_goal = parseInt($('#tekst-wordcount').val());
    // seconds
    timer_goal = 60 * parseInt($('#tekst-timer').val());
    puppies_mode = $('#tekst-puppies').val();

    game_start_time = getTime();
    game_started = true;
    window.setInterval(updateFlowStatus, 100);
}

function startNewFlow() {
    sv_time = getTime();
    hideEncouragement();
    flowing = true;
}

updateFlowState = function() {
    if (! game_started) {
        startGame();
    }
    if (! flowing) {
        startNewFlow();
    }
    if (saveFlowTimeout) {
        window.clearTimeout(saveFlowTimeout);
    }

    updateFlowStatus();

    saveFlowTimeout = window.setTimeout(saveFlow, 500);
}

function getTime() {
    return (new Date).getTime();
}

function getElapsedSeconds(time) {
    return (getTime() - time) / 1000;
}

document.getElementById("playingfield").oninput = updateFlowState;

function saveFlowToServer() {
    $('.flow-save').css('display', 'block');
    saveFlow();
    var total_text = $('.text-content').text();
    $.post('/flow', { text: total_text, score: score, mode: game_mode, timer: final_game_length, wordcount: wordcount, title: title, longest_flow: longest_flow, highest_wpm: highest_wpm });
}
<|endoftext|>


<commit_before>var submitNewForwarding = function() {
    var form = $('#newForwardingForm');
    var data = JSON.stringify(form.serializeObject());

    $.post('../api/forwardings', data, function(response) {
        // TODO: add new forwarding to list
        // ugly hack, see http://stackoverflow.com/questions/11519660/twitter-bootstrap-modal-backdrop-doesnt-disappear
        //e.preventDefault();
        $('#newForwardingDialog').modal('hide');
        //$('body').removeClass('modal-open');
        //$('.modal-backdrop').remove();

        $('#forwardingsList').append('

' + response.forwarding.source + '

' + response.forwarding.destination + '

 <a class="deleteForwarding" href="#" data-email="<%= forwarding.source %>">

');

        return false;
    });

    return false;
};

var deleteForwarding = function() {
    var id = $(this).data('email');
    var that = this;

    _confirm({
        url: '../api/forwardings/' + id,
        httptype: 'DELETE',
        datatype: 'text',
        title: 'Delete forwarding',
        text: 'Are you sure?',
        ok: 'Delete'
    }).done(function(){
            $(that).closest('.row').remove();
        });
};

$('.deleteForwarding').click(deleteForwarding);

var cancelEditing = function(){
    var destination = $(this).closest('.row').find('.editable');
    var destValue = $(this).data('destination');

    destination.empty();
    destination.text(destValue);
};

var saveEditing = function(){
    var source = $(this).data('email');
    var destLocation = $(this).closest(".row").find(".editable");
    var data = $(this).closest(".form-inline").serializeObject();
    data.source = source;

    $.post('../api/forwardings/' + source, JSON.stringify(data), function(response) {
        destLocation.empty();
        destLocation.text(data.destination);
    }, 'text');
};

var editForwarding = function(){
    var destination = $(this).closest('.row').find('.editable');
    var destValue = destination.text();
    var sourceValue = $(this).data('email');

    destination.empty();
    var template = $( "#forwardingEditTemplate" ).html()
    var processedTemplate = template.format( sourceValue, destValue);
    destination.append(processedTemplate);
    destination.find(".btn-primary").click(saveEditing);
    destination.find(".btn-secondary").click(cancelEditing);
}

$('.editForwarding').click(editForwarding);

var newForwarding = function() {
    var template =  $( "#newForwardingTemplate" ).html();
    var dialog = $('#newForwardingDialog');
    dialog.find('.modal-body').html(template);
    var footer = dialog.find('.modal-footer');
    footer.find('.btn-primary').unbind('click');
    footer.find('.btn-cancel').unbind('click');
    footer.find('.btn-primary').on('click', submitNewForwarding);

    dialog.modal('show');
}

$('#newForwarding').click(newForwarding);<commit_msg>fix append new row after creation of a new forwarding<commit_after>var submitNewForwarding = function() {
    var form = $('#newForwardingForm');
    var data = JSON.stringify(form.serializeObject());

    $.post('../api/forwardings', data, function(response) {
        // TODO: add new forwarding to list
        // ugly hack, see http://stackoverflow.com/questions/11519660/twitter-bootstrap-modal-backdrop-doesnt-disappear
        //e.preventDefault();
        $('#newForwardingDialog').modal('hide');
        //$('body').removeClass('modal-open');
        //$('.modal-backdrop').remove();

        var line = $('

' +
            response.forwarding.source + '

' +
            response.forwarding.destination +
            '

');
        line.find('.editForwarding').click(editForwarding);
        line.find('.deleteForwarding').click(deleteForwarding);

        $('#forwardingsList').append(line);

        return false;
    });

    return false;
};

var deleteForwarding = function() {
    var id = $(this).data('email');
    var that = this;

    _confirm({
        url: '../api/forwardings/' + id,
        httptype: 'DELETE',
        datatype: 'text',
        title: 'Delete forwarding',
        text: 'Are you sure?',
        ok: 'Delete'
    }).done(function(){
            $(that).closest('.row').remove();
        });
};

$('.deleteForwarding').click(deleteForwarding);

var cancelEditing = function(){
    var destination = $(this).closest('.row').find('.editable');
    var destValue = $(this).data('destination');

    destination.empty();
    destination.text(destValue);
};

var saveEditing = function(){
    var source = $(this).data('email');
    var destLocation = $(this).closest(".row").find(".editable");
    var data = $(this).closest(".form-inline").serializeObject();
    data.source = source;

    $.post('../api/forwardings/' + source, JSON.stringify(data), function(response) {
        destLocation.empty();
        destLocation.text(data.destination);
    }, 'text');
};

var editForwarding = function(){
    var destination = $(this).closest('.row').find('.editable');
    var destValue = destination.text();
    var sourceValue = $(this).data('email');

    destination.empty();
    var template = $( "#forwardingEditTemplate" ).html()
    var processedTemplate = template.format( sourceValue, destValue);
    destination.append(processedTemplate);
    destination.find(".btn-primary").click(saveEditing);
    destination.find(".btn-secondary").click(cancelEditing);
}

$('.editForwarding').click(editForwarding);

var newForwarding = function() {
    var template =  $( "#newForwardingTemplate" ).html();
    var dialog = $('#newForwardingDialog');
    dialog.find('.modal-body').html(template);
    var footer = dialog.find('.modal-footer');
    footer.find('.btn-primary').unbind('click');
    footer.find('.btn-cancel').unbind('click');
    footer.find('.btn-primary').on('click', submitNewForwarding);

    dialog.modal('show');
}

$('#newForwarding').click(newForwarding);<|endoftext|>


<commit_before>var Router = Backbone.Controller.extend({
    routes: {
        '': 'list',
        'list': 'list',
        'reference': 'reference',
        'project/:id': 'project',
        'visualization/:id': 'visualization',
    },
    list: function() {
        new ListView();
    },
    project: function(id) {
        new ProjectView({ model: new Project({ id: id }) });
    },
    visualization: function(id) {
        new VisualizationView({ id: id });
    },
    reference: function() {
        new ReferenceView();
    },
    error: function() {
        new ErrorView({ message: 'Page not found.' });
    }
});

var App = function() {
    this.el = $('body');
    this.controller = new Router;

    // Catchall error page requires a regex so we must add its route manually.
    this.controller.route(/^(.*?)/, 'error', Router.prototype.error);

    // Set body ID on each route page.
    // @TODO needs more sanitization.
    this.controller.bind('all', function(page) {
        $('body').attr('id', page.split(':').pop());
    });

    this.loading = function(message) {
        this.loadingView = new LoadingView({message: message});
    }

    this.done = function() {
        this.loadingView.remove();
    }

    this.message = function(title, message, type) {
        type = type || 'status';
        if (type == 'projectInfo') {
            new PopupView({
                title: title,
                content: ich.PopupProjectInfo({
                    tilelive_url: message.tilelive_url,
                    mml_url: message.mml_url,
                    type: type
                }, true)
            });
        }
        else {
            new PopupView({
                title: title,
                content: ich.PopupMessage({
                    message: message,
                    type: type
                }, true)
            });
        }
    };
};

var LoadingView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function () {
        $(this.el).html(ich.LoadingView(this.options));
        window.app.el.append(this.el);
        return this;
    }
});

var ErrorView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function () {
        $(this.el).html(ich.ErrorView(this.options));
        window.app.el.html(this.el);
        return this;
    }
});

$(function() {
    window.app = new App();
    Backbone.history.start();
});

<commit_msg>Mixing Backbone.Events to the global app object.<commit_after>var Router = Backbone.Controller.extend({
    routes: {
        '': 'list',
        'list': 'list',
        'reference': 'reference',
        'project/:id': 'project',
        'visualization/:id': 'visualization',
    },
    list: function() {
        new ListView();
    },
    project: function(id) {
        new ProjectView({ model: new Project({ id: id }) });
    },
    visualization: function(id) {
        new VisualizationView({ id: id });
    },
    reference: function() {
        new ReferenceView();
    },
    error: function() {
        new ErrorView({ message: 'Page not found.' });
    }
});

var App = function() {
    this.el = $('body');
    this.controller = new Router;

    // Catchall error page requires a regex so we must add its route manually.
    this.controller.route(/^(.*?)/, 'error', Router.prototype.error);

    // Set body ID on each route page.
    // @TODO needs more sanitization.
    this.controller.bind('all', function(page) {
        $('body').attr('id', page.split(':').pop());
    });

    this.loading = function(message) {
        this.loadingView = new LoadingView({message: message});
    }

    this.done = function() {
        this.loadingView.remove();
    }

    this.message = function(title, message, type) {
        type = type || 'status';
        if (type == 'projectInfo') {
            new PopupView({
                title: title,
                content: ich.PopupProjectInfo({
                    tilelive_url: message.tilelive_url,
                    mml_url: message.mml_url,
                    type: type
                }, true)
            });
        }
        else {
            new PopupView({
                title: title,
                content: ich.PopupMessage({
                    message: message,
                    type: type
                }, true)
            });
        }
    };
};

var LoadingView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function () {
        $(this.el).html(ich.LoadingView(this.options));
        window.app.el.append(this.el);
        return this;
    }
});

var ErrorView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function () {
        $(this.el).html(ich.ErrorView(this.options));
        window.app.el.html(this.el);
        return this;
    }
});

$(function() {
    window.app = new App();
    _.extend(window.app, Backbone.Events);
    Backbone.history.start();
});

<|endoftext|>


<commit_before>var data = {
    currentProject: null,
    currentLanguage: null,
    projectHandlers: [],
    isAdmin: false,
    isRoot: false,
    baseStrings: [],
    strings: [],
    filteredData: [],
    pagedData: [],
    translatedStringsHistory: [],
    topUsers: [],
    admins: [],
    loading: 0,
    acceptedStringsHidden: false,
    showingPendingOnly: false,
    currentPage: 0,
    pageSize: 100,
    numberOfPages: 0,
    whiteboard: {},
    searchInput: '',
    manualInputBaseString: {},
    editStringModalData: {},
    pageLoadedAt: 0
};

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

var app = new Vue({
    el: '#translate',
    data: function () {
        return data;
    },
    created: function () {
        // Reload the page after 2hrs, after CSRF expires
        data.pageLoadedAt = this.getCurrentTimestamp();
        setInterval(this.checkCSRFExpiry, 30000)
    },
    methods: {
        getRequest: function (url, params, success) {
            data.loading++;

            $.get(url, params, success).fail(function (jqXHR, textStatus, errorThrown) {
                if (typeof jqXHR.responseJSON == 'undefined')
                    alert('Error ' + jqXHR.status + ' occurred. Please try again.');
                else
                    alert(jqXHR.responseJSON.error.message);
            }).always(function () {
                data.loading--;
            });
        },
        postRequest: function (url, params, success) {
            data.loading++;

            $.post(url, params, success).fail(function (jqXHR, textStatus, errorThrown) {
                if (typeof jqXHR.responseJSON == 'undefined')
                    alert('Error ' + jqXHR.status + ' occurred. Please try again.');
                else
                    alert(jqXHR.responseJSON.error.message);
            }).always(function () {
                data.loading--;
            });
        },
        loadData: function () {
            data.currentProject = $('#project').val();
            data.currentLanguage = $('#language').val();

            app.getRequest("api/base-strings", {project_id: data.currentProject}, function (response) {
                data.baseStrings = response;

                Object.keys(response).forEach(function (key) {
                    data.strings[response[key].id] = [];
                });

                data.pagedData = data.filteredData = data.baseStrings;
                app.resetPagination();

                app.loadTranslatedStrings();
                app.loadInvolvedUsers();
                app.loadAdmins();
                app.checkPrivileges();
                app.checkProjectHandlers();
                app.loadWhiteboard();
            });
        },
        resetPagination: function () {
            data.numberOfPages = Math.ceil(data.filteredData.length / data.pageSize);
            this.setPage(0);
        },
        previousPage: function () {
            if (data.currentPage - 1 >= 0)
                this.setPage(data.currentPage - 1);
        },
        nextPage: function () {
            if (data.currentPage + 1 < data.numberOfPages)
                this.setPage(data.currentPage + 1);
        },
        setPage: function (page) {
            data.currentPage = page;

            var start = (data.currentPage * data.pageSize);
            var end = start + data.pageSize;
            data.pagedData = data.filteredData.slice(start, end);
        },
        loadTranslatedStrings: function () {
            app.getRequest("api/strings", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                Object.keys(response).forEach(function (key) {
                    data.strings[response[key].base_string_id].push(response[key]);
                });
            });
        },
        loadInvolvedUsers: function () {
            app.getRequest("api/strings/users", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                data.topUsers = response
            });
        },
        loadAdmins: function () {
            app.getRequest("api/strings/admins", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                data.admins = response
            });
        },
        checkPrivileges: function () {
            app.getRequest("api/check-privileges", {language_id: data.currentLanguage}, function (response) {
                data.isAdmin = response.is_admin;
                data.isRoot = response.is_root;
            });
        },
        checkProjectHandlers: function () {
            app.getRequest("api/project-handlers", {language_id: data.currentLanguage}, function (response) {
                data.projectHandlers = response;
            });
        },
        loadWhiteboard: function () {
            app.getRequest("api/admin-whiteboard/" + data.currentProject + '/' + data.currentLanguage, {}, function (response) {
                data.whiteboard = response;
            });
        },
        saveWhiteboard: function () {
            var postData = {
                project_id: data.currentProject,
                language_id: data.currentLanguage,
                text: data.whiteboard.text
            };

            app.postRequest("api/admin-whiteboard", postData, function (response) {
                app.loadWhiteboard();
            });
        },
        hideAccepted: function () {
            if (data.acceptedStringsHidden) {
                data.filteredData = data.baseStrings;
                this.resetPagination();
                data.acceptedStringsHidden = false;
            } else {
                data.filteredData = data.baseStrings.filter(function (item) {
                    var result = true;

                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].is_accepted == true) {
                            result = false;
                        }
                    })

                    return result;
                });

                this.resetPagination();
                data.acceptedStringsHidden = true;
                data.showingPendingOnly = false;
            }
        },
        showPendingOnly: function () {
            if (data.showingPendingOnly) {
                data.filteredData = data.baseStrings;
                this.resetPagination();
                data.showingPendingOnly = false;
            } else {
                data.filteredData = data.baseStrings.filter(function (item) {
                    var hasTranslations = false
                    var is_accepted = false;

                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].is_accepted == true) {
                            is_accepted = true;
                        }

                        hasTranslations = true;
                    })

                    return !is_accepted && hasTranslations;
                });

                this.resetPagination();
                data.showingPendingOnly = true;
                data.acceptedStringsHidden = false;
            }
        },
        range: function (start, end) {
            var ret = [];
            if (!end) {
                end = start;
                start = 0;
            }
            for (var i = start; i < end; i++) {
                ret.push(i);
            }
            return ret;
        },
        /*
         *
         *  TODO: MOVE ELSEWHERE! Separate component or something
         *
         */
        vote: function (base_string_id, string_id, vote) {
            var postData = {
                'string_id': string_id,
                'vote': vote
            };

            app.postRequest("api/strings/vote", postData, function (response) {
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id) {
                        if (vote == 1)
                            !isNaN(data.strings[base_string_id][key].up_votes) ? data.strings[base_string_id][key].up_votes++ : data.strings[base_string_id][key].up_votes = 1;
                        else
                            !isNaN(data.strings[base_string_id][key].down_votes) ? data.strings[base_string_id][key].down_votes++ : data.strings[base_string_id][key].down_votes = 1;
                    }
                });
            });
        },
        trash: function (base_string_id, string_id) {
            var postData = {
                'string_id': string_id,
                'language_id': data.currentLanguage
            };

            app.postRequest("api/strings/trash", postData, function (response) {
                var index = -1;
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id) {
                        index = key;
                    }
                });

                data.strings[base_string_id].splice(index, 1);
            });
        },
        trashBaseString: function (base_string) {
            var postData = {
                id: base_string.id
            };

            app.postRequest("api/base-strings/trash", postData, function (response) {
                var index = -1;
                Object.keys(data.baseStrings).forEach(function (key) {
                    if (data.baseStrings[key].id == base_string.id) {
                        index = key;
                    }
                });

                data.baseStrings.splice(index, 1);
                app.resetPagination();
            });
        },
        accept: function (base_string_id, string_id) {
            var postData = {
                'string_id': string_id,
                'base_string_id': base_string_id,
                'language_id': data.currentLanguage
            };

            app.postRequest("api/strings/accept", postData, function (response) {
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id)
                        data.strings[base_string_id][key].is_accepted = true;
                    else
                        data.strings[base_string_id][key].is_accepted = false;
                });
            });
        },
        add: function (base_string_id) {
            var textInput = $('#stringInput' + base_string_id);

            var postData = {
                'project_id': data.currentProject,
                'language_id': data.currentLanguage,
                'base_string_id': base_string_id,
                'text': textInput.val()
            };

            app.postRequest("api/strings/store", postData, function (response) {
                data.strings[base_string_id].push(response);
                textInput.val('');
            });
        },
        showTranslationHistory: function (base_string_id) {
            var getData = {
                project_id: data.currentProject,
                language_id: data.currentLanguage,
                base_string_id: base_string_id
            };

            app.getRequest("api/strings/history", getData, function (response) {
                data.translatedStringsHistory = response;
                $('#translatedStringsHistory').modal();
            });
        },
        edit: function (string) {
            data.editStringModalData = string;
            $('#stringEditModal').modal();
        },
        saveString: function (string) {
            var postData = {
                string_id: string.id,
                text: string.text
            };

            app.postRequest("api/strings/update", postData, function (response) {
                $('#stringEditModal').modal('hide');
            });
        },
        showNewBaseStringForm: function () {
            data.manualInputBaseString = {};
            $('#baseStringEditModal').modal();
        },
        editBaseString: function (base_string) {
            data.manualInputBaseString = base_string;
            $('#baseStringEditModal').modal();
        },
        saveBaseString: function (base_string_id) {
            // TODO make it work properly
            var postData = {
                id: base_string_id,
                project_id: data.currentProject,
                key: data.manualInputBaseString.key,
                text: data.manualInputBaseString.text
            };

            app.postRequest("api/base-strings", postData, function (response) {
                if (typeof base_string_id == 'undefined') {
                    data.baseStrings.push(response);
                    data.strings[response.id] = [];
                    app.resetPagination();
                }

                $('#baseStringEditModal').modal('hide');
            });
        },
        lockBaseString: function (base_string) {
            let postData = {
                id: base_string.id,
            };

            app.postRequest("api/base-strings/lock", postData, function (response) {
                base_string.locked = response.locked;
            });
        },
        // Refresh the page after 2 hours. Needed for CSRF token expiry, useful for phones.
        checkCSRFExpiry: function () {
            var currentTimestamp = this.getCurrentTimestamp();

            if ((data.pageLoadedAt + 3600 * 2) < currentTimestamp) {
                alert('Session expired. Please reload the page.');
            }
        },
        getCurrentTimestamp: function () {
            return Math.floor(Date.now() / 1000);
        }
    },
    watch: {
        searchInput: _.debounce(
            function (val) {
                data.filteredData = data.baseStrings.filter(function (item) {
                    // Search in translated strings
                    var translatedTextContainsQuery = false;
                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].text.toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            translatedTextContainsQuery = true;
                        }
                    })

                    // Search in keys and values, also return true if translated string contains query
                    return item.key.toLowerCase().indexOf(val.toLowerCase()) !== -1
                        || item.text.toLowerCase().indexOf(val.toLowerCase()) !== -1
                        || translatedTextContainsQuery;
                });

                this.resetPagination();
                data.showingPendingOnly = false;
                data.acceptedStringsHidden = false;
            }, 500),
    }
})<commit_msg>translate.js fix<commit_after>var data = {
    currentProject: null,
    currentLanguage: null,
    projectHandlers: [],
    isAdmin: false,
    isRoot: false,
    baseStrings: [],
    strings: [],
    filteredData: [],
    pagedData: [],
    translatedStringsHistory: [],
    topUsers: [],
    admins: [],
    loading: 0,
    acceptedStringsHidden: false,
    showingPendingOnly: false,
    currentPage: 0,
    pageSize: 100,
    numberOfPages: 0,
    whiteboard: {},
    searchInput: '',
    manualInputBaseString: {},
    editStringModalData: {},
    pageLoadedAt: 0
};

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

var app = new Vue({
    el: '#translate',
    data: function () {
        return data;
    },
    created: function () {
        // Reload the page after 2hrs, after CSRF expires
        data.pageLoadedAt = this.getCurrentTimestamp();
        setInterval(this.checkCSRFExpiry, 30000)
    },
    methods: {
        getRequest: function (url, params, success) {
            data.loading++;

            $.get(url, params, success).fail(function (jqXHR, textStatus, errorThrown) {
                if (typeof jqXHR.responseJSON == 'undefined')
                    alert('Error ' + jqXHR.status + ' occurred. Please try again.');
                else
                    alert(jqXHR.responseJSON.error.message);
            }).always(function () {
                data.loading--;
            });
        },
        postRequest: function (url, params, success) {
            data.loading++;

            $.post(url, params, success).fail(function (jqXHR, textStatus, errorThrown) {
                if (typeof jqXHR.responseJSON == 'undefined')
                    alert('Error ' + jqXHR.status + ' occurred. Please try again.');
                else
                    alert(jqXHR.responseJSON.error.message);
            }).always(function () {
                data.loading--;
            });
        },
        loadData: function () {
            data.currentProject = $('#project').val();
            data.currentLanguage = $('#language').val();

            app.getRequest("api/base-strings", {project_id: data.currentProject}, function (response) {
                data.baseStrings = response;

                Object.keys(response).forEach(function (key) {
                    data.strings[response[key].id] = [];
                });

                data.pagedData = data.filteredData = data.baseStrings;
                app.resetPagination();

                app.loadTranslatedStrings();
                app.loadInvolvedUsers();
                app.loadAdmins();
                app.checkPrivileges();
                app.checkProjectHandlers();
                app.loadWhiteboard();
            });
        },
        resetPagination: function () {
            data.numberOfPages = Math.ceil(data.filteredData.length / data.pageSize);
            this.setPage(0);
        },
        previousPage: function () {
            if (data.currentPage - 1 >= 0)
                this.setPage(data.currentPage - 1);
        },
        nextPage: function () {
            if (data.currentPage + 1 < data.numberOfPages)
                this.setPage(data.currentPage + 1);
        },
        setPage: function (page) {
            data.currentPage = page;

            var start = (data.currentPage * data.pageSize);
            var end = start + data.pageSize;
            data.pagedData = data.filteredData.slice(start, end);
        },
        loadTranslatedStrings: function () {
            app.getRequest("api/strings", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                Object.keys(response).forEach(function (key) {
                    let translatedStrings = data.strings[response[key].base_string_id];

                    if(!Array.isArray(translatedStrings)){
                        translatedStrings = [];
                    }
                    translatedStrings.push(response[key]);
                });
            });
        },
        loadInvolvedUsers: function () {
            app.getRequest("api/strings/users", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                data.topUsers = response
            });
        },
        loadAdmins: function () {
            app.getRequest("api/strings/admins", {
                project_id: data.currentProject,
                language_id: data.currentLanguage
            }, function (response) {
                data.admins = response
            });
        },
        checkPrivileges: function () {
            app.getRequest("api/check-privileges", {language_id: data.currentLanguage}, function (response) {
                data.isAdmin = response.is_admin;
                data.isRoot = response.is_root;
            });
        },
        checkProjectHandlers: function () {
            app.getRequest("api/project-handlers", {language_id: data.currentLanguage}, function (response) {
                data.projectHandlers = response;
            });
        },
        loadWhiteboard: function () {
            app.getRequest("api/admin-whiteboard/" + data.currentProject + '/' + data.currentLanguage, {}, function (response) {
                data.whiteboard = response;
            });
        },
        saveWhiteboard: function () {
            var postData = {
                project_id: data.currentProject,
                language_id: data.currentLanguage,
                text: data.whiteboard.text
            };

            app.postRequest("api/admin-whiteboard", postData, function (response) {
                app.loadWhiteboard();
            });
        },
        hideAccepted: function () {
            if (data.acceptedStringsHidden) {
                data.filteredData = data.baseStrings;
                this.resetPagination();
                data.acceptedStringsHidden = false;
            } else {
                data.filteredData = data.baseStrings.filter(function (item) {
                    var result = true;

                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].is_accepted == true) {
                            result = false;
                        }
                    })

                    return result;
                });

                this.resetPagination();
                data.acceptedStringsHidden = true;
                data.showingPendingOnly = false;
            }
        },
        showPendingOnly: function () {
            if (data.showingPendingOnly) {
                data.filteredData = data.baseStrings;
                this.resetPagination();
                data.showingPendingOnly = false;
            } else {
                data.filteredData = data.baseStrings.filter(function (item) {
                    var hasTranslations = false
                    var is_accepted = false;

                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].is_accepted == true) {
                            is_accepted = true;
                        }

                        hasTranslations = true;
                    })

                    return !is_accepted && hasTranslations;
                });

                this.resetPagination();
                data.showingPendingOnly = true;
                data.acceptedStringsHidden = false;
            }
        },
        range: function (start, end) {
            var ret = [];
            if (!end) {
                end = start;
                start = 0;
            }
            for (var i = start; i < end; i++) {
                ret.push(i);
            }
            return ret;
        },
        /*
         *
         *  TODO: MOVE ELSEWHERE! Separate component or something
         *
         */
        vote: function (base_string_id, string_id, vote) {
            var postData = {
                'string_id': string_id,
                'vote': vote
            };

            app.postRequest("api/strings/vote", postData, function (response) {
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id) {
                        if (vote == 1)
                            !isNaN(data.strings[base_string_id][key].up_votes) ? data.strings[base_string_id][key].up_votes++ : data.strings[base_string_id][key].up_votes = 1;
                        else
                            !isNaN(data.strings[base_string_id][key].down_votes) ? data.strings[base_string_id][key].down_votes++ : data.strings[base_string_id][key].down_votes = 1;
                    }
                });
            });
        },
        trash: function (base_string_id, string_id) {
            var postData = {
                'string_id': string_id,
                'language_id': data.currentLanguage
            };

            app.postRequest("api/strings/trash", postData, function (response) {
                var index = -1;
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id) {
                        index = key;
                    }
                });

                data.strings[base_string_id].splice(index, 1);
            });
        },
        trashBaseString: function (base_string) {
            var postData = {
                id: base_string.id
            };

            app.postRequest("api/base-strings/trash", postData, function (response) {
                var index = -1;
                Object.keys(data.baseStrings).forEach(function (key) {
                    if (data.baseStrings[key].id == base_string.id) {
                        index = key;
                    }
                });

                data.baseStrings.splice(index, 1);
                app.resetPagination();
            });
        },
        accept: function (base_string_id, string_id) {
            var postData = {
                'string_id': string_id,
                'base_string_id': base_string_id,
                'language_id': data.currentLanguage
            };

            app.postRequest("api/strings/accept", postData, function (response) {
                Object.keys(data.strings[base_string_id]).forEach(function (key) {
                    if (data.strings[base_string_id][key].id == string_id)
                        data.strings[base_string_id][key].is_accepted = true;
                    else
                        data.strings[base_string_id][key].is_accepted = false;
                });
            });
        },
        add: function (base_string_id) {
            var textInput = $('#stringInput' + base_string_id);

            var postData = {
                'project_id': data.currentProject,
                'language_id': data.currentLanguage,
                'base_string_id': base_string_id,
                'text': textInput.val()
            };

            app.postRequest("api/strings/store", postData, function (response) {
                data.strings[base_string_id].push(response);
                textInput.val('');
            });
        },
        showTranslationHistory: function (base_string_id) {
            var getData = {
                project_id: data.currentProject,
                language_id: data.currentLanguage,
                base_string_id: base_string_id
            };

            app.getRequest("api/strings/history", getData, function (response) {
                data.translatedStringsHistory = response;
                $('#translatedStringsHistory').modal();
            });
        },
        edit: function (string) {
            data.editStringModalData = string;
            $('#stringEditModal').modal();
        },
        saveString: function (string) {
            var postData = {
                string_id: string.id,
                text: string.text
            };

            app.postRequest("api/strings/update", postData, function (response) {
                $('#stringEditModal').modal('hide');
            });
        },
        showNewBaseStringForm: function () {
            data.manualInputBaseString = {};
            $('#baseStringEditModal').modal();
        },
        editBaseString: function (base_string) {
            data.manualInputBaseString = base_string;
            $('#baseStringEditModal').modal();
        },
        saveBaseString: function (base_string_id) {
            // TODO make it work properly
            var postData = {
                id: base_string_id,
                project_id: data.currentProject,
                key: data.manualInputBaseString.key,
                text: data.manualInputBaseString.text
            };

            app.postRequest("api/base-strings", postData, function (response) {
                if (typeof base_string_id == 'undefined') {
                    data.baseStrings.push(response);
                    data.strings[response.id] = [];
                    app.resetPagination();
                }

                $('#baseStringEditModal').modal('hide');
            });
        },
        lockBaseString: function (base_string) {
            let postData = {
                id: base_string.id,
            };

            app.postRequest("api/base-strings/lock", postData, function (response) {
                base_string.locked = response.locked;
            });
        },
        // Refresh the page after 2 hours. Needed for CSRF token expiry, useful for phones.
        checkCSRFExpiry: function () {
            var currentTimestamp = this.getCurrentTimestamp();

            if ((data.pageLoadedAt + 3600 * 2) < currentTimestamp) {
                alert('Session expired. Please reload the page.');
            }
        },
        getCurrentTimestamp: function () {
            return Math.floor(Date.now() / 1000);
        }
    },
    watch: {
        searchInput: _.debounce(
            function (val) {
                data.filteredData = data.baseStrings.filter(function (item) {
                    // Search in translated strings
                    var translatedTextContainsQuery = false;
                    Object.keys(data.strings[item.id]).forEach(function (key) {
                        if (data.strings[item.id][key].text.toLowerCase().indexOf(val.toLowerCase()) !== -1) {
                            translatedTextContainsQuery = true;
                        }
                    })

                    // Search in keys and values, also return true if translated string contains query
                    return item.key.toLowerCase().indexOf(val.toLowerCase()) !== -1
                        || item.text.toLowerCase().indexOf(val.toLowerCase()) !== -1
                        || translatedTextContainsQuery;
                });

                this.resetPagination();
                data.showingPendingOnly = false;
                data.acceptedStringsHidden = false;
            }, 500),
    }
})
<|endoftext|>


<commit_before>import React, { useEffect, useState, useReducer } from 'react';
import { PropTypes as T } from 'prop-types';
import fetch from 'isomorphic-fetch';
import { connect } from 'react-redux';
import qs from 'qs';

import { openDownloadModal } from '../../actions/action-creators';
import { buildQS } from '../../utils/url';
import config from '../../config';

import Header, { LoadingHeader, ErrorHeader } from '../../components/header';
import Dashboard from './dashboard';
import NodesDashboard from './nodes-dashboard';
import NodeLocations from './node-locations';
import DateSelector from '../../components/date-selector';
import Pill from '../../components/pill';
import { formatValueByUnit, renderUnit } from '../../utils/format';

const projectActions = {
  SET_INITIAL_STATE: 'SET_INITIAL_STATE',
  SELECT_LOCATION: 'SELECT_LOCATION',
  DISPLAY_FETCHED_LOCATION_DATA: 'DISPLAY_FETCHED_LOCATION_DATA',
  TOGGLE_MAP_STATE: 'TOGGLE_MAP_STATE',
};

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  projectData: null,
};

const initialProjectState = {
  isFullProject: true,
  isDisplayingSelectionTools: false,
  selectedLocations: {},
};

function updateSelectedLocation(state, paramId, locationId) {
  const { selectedLocations } = state;
  if (selectedLocations[paramId]?.includes(locationId)) {
    // removes location
    const updatedSelection = {
      ...selectedLocations,
      [paramId]: selectedLocations[paramId].filter(
        location => location !== locationId
      ),
    };
    // removes param if last location was removed
    updatedSelection[paramId].length < 1 && delete updatedSelection[paramId];
    return updatedSelection;
  } else if (Object.values(selectedLocations).flat().length < 15) {
    return {
      ...selectedLocations,
      [paramId]: selectedLocations[paramId]
        ? [...selectedLocations[paramId], locationId]
        : [locationId],
    };
  }
}

function reducer(state, action) {
  switch (action.type) {
    case projectActions.TOGGLE_MAP_STATE:
      return {
        isFullProject: !state.isFullProject ? true : state.isFullProject, // only update if previous state was false
        isDisplayingSelectionTools: !state.isDisplayingSelectionTools,
        selectedLocations: {},
      };
    case projectActions.SET_INITIAL_STATE:
      return initialProjectState;
    case projectActions.SELECT_LOCATION:
      return {
        isFullProject: state.isFullProject,
        isDisplayingSelectionTools: true,
        selectedLocations: updateSelectedLocation(
          state,
          action.paramId,
          action.locationId
        ),
      };
    case projectActions.DISPLAY_FETCHED_LOCATION_DATA:
      return {
        isFullProject: false,
        isDisplayingSelectionTools: true,
        selectedLocations: state.selectedLocations,
      };
    default:
      throw new Error();
  }
}

function Project({ match, history, location, _openDownloadModal }) {
  const { id } = match.params;
  const [projectState, dispatch] = useReducer(reducer, initialProjectState);
  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  const [{ fetched, fetching, error, projectData }, setState] = useState(
    defaultState
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  useEffect(() => {
    fetchProjectData(id);

    return () => {
      setState(defaultState);
    };
  }, []);

  const fetchProjectData = id => {
    setState(state => ({ ...state, fetching: true, error: null }));
    fetch(`${config.api}/projects/${encodeURIComponent(id)}`)
      .then(response => {
        if (response.status >= 400) {
          throw new Error('Bad response');
        }
        return response.json();
      })
      .then(
        json => {
          const dat = json.results[0];
          setState(state => ({
            ...state,
            fetched: true,
            fetching: false,
            projectData: {
              ...dat,
              parameters: dat.parameters.map(p => ({
                ...p,
                average: formatValueByUnit(
                  p.average,
                  p.unit,
                  renderUnit(p.unit)
                ),
                lastValue: formatValueByUnit(
                  p.lastValue,
                  p.unit,
                  renderUnit(p.unit)
                ),
                unit: renderUnit(p.unit),
              })),
            },
          }));
        },
        e => {
          console.log('e', e);
          setState(state => ({
            ...state,
            fetched: true,
            fetching: false,
            error: e,
          }));
        }
      );
  };

  const handleLocationSelection = (paramId, locationId) => {
    dispatch({ type: projectActions.SELECT_LOCATION, paramId, locationId });
  };

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return <LoadingHeader />;
  }

  if (error || !projectData) {
    return <ErrorHeader />;
  }

  // Lifecycle stage of different sources.
  const lifecycle = projectData.sources
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  const selectedLocationCount = Object.values(
    projectState.selectedLocations
  ).flat().length;
  return (

      <Header
        tagline="Datasets"
        title={projectData.subtitle}
        action={{
          api: `${config.apiDocs}`,
          download: () =>
            _openDownloadModal({
              downloadType: 'projects',
              country: projectData.countries && projectData.countries[0],
              project: projectData.id,
            }),
        }}
        sourceType={projectData.sourceType}
        isMobile={projectData.isMobile}
      />

        {!projectData.isAnalysis && (
          <DateSelector setDateRange={setDateRange} dateRange={dateRange} />
        )}
        {!projectData.isMobile && projectState.isDisplayingSelectionTools && (
          <div
            className={'filters, inner'}
            style={{
              display: `grid`,
              gridTemplateRows: `1fr`,
              gridTemplateColumns: `repeat(2, 1fr)`,
            }}
          >

              <Pill
                title={`${selectedLocationCount}/15`}
                action={() =>
                  dispatch({ type: projectActions.SET_INITIAL_STATE })
                }
              />

            {projectState.isFullProject && (
              <div style={{ display: `flex`, justifyContent: `flex-end` }}>
                <button
                  className="nav__action-link"
                  onClick={() =>
                    dispatch({
                      type: projectActions.DISPLAY_FETCHED_LOCATION_DATA,
                    })
                  }
                >
                  View Location Data
                </button>

            )}

        )}

        {!projectData.isMobile && (
          <NodeLocations
            bbox={projectData.bbox}
            locationIds={projectData.locationIds}
            parameters={projectData.parameters}
            toggleLocationSelection={() =>
              dispatch({ type: projectActions.TOGGLE_MAP_STATE })
            }
            isDisplayingSelectionTools={projectState.isDisplayingSelectionTools}
            selectedLocations={projectState.selectedLocations}
            handleLocationSelection={handleLocationSelection}
          />
        )}

        {!projectData.isMobile && !projectState.isFullProject ? (
          <>
            <header
              className="fold__header inner"
              style={{ gridTemplateColumns: `1fr`, paddingTop: `4rem` }}
            >

                {`Values for ${selectedLocationCount} selected nodes${
                  selectedLocationCount !== 1 ? 's' : ''
                }`}

            <NodesDashboard
              measurements={projectData.measurements}
              projectId={projectData.id}
              projectName={projectData.name}
              selectedParams={Object.keys(projectState.selectedLocations)}
              lifecycle={lifecycle}
              dateRange={dateRange}
              projectDates={{
                start: projectData.firstUpdated,
                end: projectData.lastUpdated,
              }}
              sources={projectData.sources}
              locations={Object.values(projectState.selectedLocations).flat()}
              country={projectData.countries && projectData.countries[0]}
            />
          </>
        ) : (
          <>
            <header
              className="fold__header inner"
              style={{ gridTemplateColumns: `1fr`, paddingTop: `4rem` }}
            >

                {`Values for ${projectData.locationIds.length} nodes${
                  projectData.locationIds.length !== 1 ? 's' : ''
                }`}

            <Dashboard
              bbox={projectData.bbox}
              isMobile={projectData.isMobile}
              isAnalysis={projectData.isAnalysis}
              locationIds={projectData.locationIds}
              measurements={projectData.measurements}
              projectParams={projectData.parameters}
              projectId={projectData.id}
              projectName={projectData.name}
              lifecycle={lifecycle}
              dateRange={dateRange}
              projectDates={{
                start: projectData.firstUpdated,
                end: projectData.lastUpdated,
              }}
              sources={projectData.sources}
            />
          </>
        )}

  );
}

Project.propTypes = {
  _openDownloadModal: T.func,
  match: T.object, // from react-router
  history: T.object,
  location: T.object,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function dispatcher(dispatch) {
  return {
    _openDownloadModal: (...args) => dispatch(openDownloadModal(...args)),
  };
}

export default connect(() => ({}), dispatcher)(Project);
<commit_msg>Remove extra s 🐍<commit_after>import React, { useEffect, useState, useReducer } from 'react';
import { PropTypes as T } from 'prop-types';
import fetch from 'isomorphic-fetch';
import { connect } from 'react-redux';
import qs from 'qs';

import { openDownloadModal } from '../../actions/action-creators';
import { buildQS } from '../../utils/url';
import config from '../../config';

import Header, { LoadingHeader, ErrorHeader } from '../../components/header';
import Dashboard from './dashboard';
import NodesDashboard from './nodes-dashboard';
import NodeLocations from './node-locations';
import DateSelector from '../../components/date-selector';
import Pill from '../../components/pill';
import { formatValueByUnit, renderUnit } from '../../utils/format';

const projectActions = {
  SET_INITIAL_STATE: 'SET_INITIAL_STATE',
  SELECT_LOCATION: 'SELECT_LOCATION',
  DISPLAY_FETCHED_LOCATION_DATA: 'DISPLAY_FETCHED_LOCATION_DATA',
  TOGGLE_MAP_STATE: 'TOGGLE_MAP_STATE',
};

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  projectData: null,
};

const initialProjectState = {
  isFullProject: true,
  isDisplayingSelectionTools: false,
  selectedLocations: {},
};

function updateSelectedLocation(state, paramId, locationId) {
  const { selectedLocations } = state;
  if (selectedLocations[paramId]?.includes(locationId)) {
    // removes location
    const updatedSelection = {
      ...selectedLocations,
      [paramId]: selectedLocations[paramId].filter(
        location => location !== locationId
      ),
    };
    // removes param if last location was removed
    updatedSelection[paramId].length < 1 && delete updatedSelection[paramId];
    return updatedSelection;
  } else if (Object.values(selectedLocations).flat().length < 15) {
    return {
      ...selectedLocations,
      [paramId]: selectedLocations[paramId]
        ? [...selectedLocations[paramId], locationId]
        : [locationId],
    };
  }
}

function reducer(state, action) {
  switch (action.type) {
    case projectActions.TOGGLE_MAP_STATE:
      return {
        isFullProject: !state.isFullProject ? true : state.isFullProject, // only update if previous state was false
        isDisplayingSelectionTools: !state.isDisplayingSelectionTools,
        selectedLocations: {},
      };
    case projectActions.SET_INITIAL_STATE:
      return initialProjectState;
    case projectActions.SELECT_LOCATION:
      return {
        isFullProject: state.isFullProject,
        isDisplayingSelectionTools: true,
        selectedLocations: updateSelectedLocation(
          state,
          action.paramId,
          action.locationId
        ),
      };
    case projectActions.DISPLAY_FETCHED_LOCATION_DATA:
      return {
        isFullProject: false,
        isDisplayingSelectionTools: true,
        selectedLocations: state.selectedLocations,
      };
    default:
      throw new Error();
  }
}

function Project({ match, history, location, _openDownloadModal }) {
  const { id } = match.params;
  const [projectState, dispatch] = useReducer(reducer, initialProjectState);
  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  const [{ fetched, fetching, error, projectData }, setState] = useState(
    defaultState
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  useEffect(() => {
    fetchProjectData(id);

    return () => {
      setState(defaultState);
    };
  }, []);

  const fetchProjectData = id => {
    setState(state => ({ ...state, fetching: true, error: null }));
    fetch(`${config.api}/projects/${encodeURIComponent(id)}`)
      .then(response => {
        if (response.status >= 400) {
          throw new Error('Bad response');
        }
        return response.json();
      })
      .then(
        json => {
          const dat = json.results[0];
          setState(state => ({
            ...state,
            fetched: true,
            fetching: false,
            projectData: {
              ...dat,
              parameters: dat.parameters.map(p => ({
                ...p,
                average: formatValueByUnit(
                  p.average,
                  p.unit,
                  renderUnit(p.unit)
                ),
                lastValue: formatValueByUnit(
                  p.lastValue,
                  p.unit,
                  renderUnit(p.unit)
                ),
                unit: renderUnit(p.unit),
              })),
            },
          }));
        },
        e => {
          console.log('e', e);
          setState(state => ({
            ...state,
            fetched: true,
            fetching: false,
            error: e,
          }));
        }
      );
  };

  const handleLocationSelection = (paramId, locationId) => {
    dispatch({ type: projectActions.SELECT_LOCATION, paramId, locationId });
  };

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return <LoadingHeader />;
  }

  if (error || !projectData) {
    return <ErrorHeader />;
  }

  // Lifecycle stage of different sources.
  const lifecycle = projectData.sources
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  const selectedLocationCount = Object.values(
    projectState.selectedLocations
  ).flat().length;
  return (

      <Header
        tagline="Datasets"
        title={projectData.subtitle}
        action={{
          api: `${config.apiDocs}`,
          download: () =>
            _openDownloadModal({
              downloadType: 'projects',
              country: projectData.countries && projectData.countries[0],
              project: projectData.id,
            }),
        }}
        sourceType={projectData.sourceType}
        isMobile={projectData.isMobile}
      />

        {!projectData.isAnalysis && (
          <DateSelector setDateRange={setDateRange} dateRange={dateRange} />
        )}
        {!projectData.isMobile && projectState.isDisplayingSelectionTools && (
          <div
            className={'filters, inner'}
            style={{
              display: `grid`,
              gridTemplateRows: `1fr`,
              gridTemplateColumns: `repeat(2, 1fr)`,
            }}
          >

              <Pill
                title={`${selectedLocationCount}/15`}
                action={() =>
                  dispatch({ type: projectActions.SET_INITIAL_STATE })
                }
              />

            {projectState.isFullProject && (
              <div style={{ display: `flex`, justifyContent: `flex-end` }}>
                <button
                  className="nav__action-link"
                  onClick={() =>
                    dispatch({
                      type: projectActions.DISPLAY_FETCHED_LOCATION_DATA,
                    })
                  }
                >
                  View Location Data
                </button>

            )}

        )}

        {!projectData.isMobile && (
          <NodeLocations
            bbox={projectData.bbox}
            locationIds={projectData.locationIds}
            parameters={projectData.parameters}
            toggleLocationSelection={() =>
              dispatch({ type: projectActions.TOGGLE_MAP_STATE })
            }
            isDisplayingSelectionTools={projectState.isDisplayingSelectionTools}
            selectedLocations={projectState.selectedLocations}
            handleLocationSelection={handleLocationSelection}
          />
        )}

        {!projectData.isMobile && !projectState.isFullProject ? (
          <>
            <header
              className="fold__header inner"
              style={{ gridTemplateColumns: `1fr`, paddingTop: `4rem` }}
            >

                {`Values for ${selectedLocationCount} selected node${
                  selectedLocationCount !== 1 ? 's' : ''
                }`}

            <NodesDashboard
              measurements={projectData.measurements}
              projectId={projectData.id}
              projectName={projectData.name}
              selectedParams={Object.keys(projectState.selectedLocations)}
              lifecycle={lifecycle}
              dateRange={dateRange}
              projectDates={{
                start: projectData.firstUpdated,
                end: projectData.lastUpdated,
              }}
              sources={projectData.sources}
              locations={Object.values(projectState.selectedLocations).flat()}
              country={projectData.countries && projectData.countries[0]}
            />
          </>
        ) : (
          <>
            <header
              className="fold__header inner"
              style={{ gridTemplateColumns: `1fr`, paddingTop: `4rem` }}
            >

                {`Values for ${projectData.locationIds.length} node${
                  projectData.locationIds.length !== 1 ? 's' : ''
                }`}

            <Dashboard
              bbox={projectData.bbox}
              isMobile={projectData.isMobile}
              isAnalysis={projectData.isAnalysis}
              locationIds={projectData.locationIds}
              measurements={projectData.measurements}
              projectParams={projectData.parameters}
              projectId={projectData.id}
              projectName={projectData.name}
              lifecycle={lifecycle}
              dateRange={dateRange}
              projectDates={{
                start: projectData.firstUpdated,
                end: projectData.lastUpdated,
              }}
              sources={projectData.sources}
            />
          </>
        )}

  );
}

Project.propTypes = {
  _openDownloadModal: T.func,
  match: T.object, // from react-router
  history: T.object,
  location: T.object,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function dispatcher(dispatch) {
  return {
    _openDownloadModal: (...args) => dispatch(openDownloadModal(...args)),
  };
}

export default connect(() => ({}), dispatcher)(Project);
<|endoftext|>


<commit_before>// Copyright (c) 2012 Aaron Roth
// See the file license.txt for copying permission.
//
// This code is based on and at times copied verbatim from a tutorial
// written by Charlie Key. His tutorial is hosted on www.switchonthecode.com
// and is titled "Creating a Roulette Wheel Using HTML5 Canvas."
//

// ------------------ Globals ------------------ //

// Canvas.
var canvasX = 250;
var canvasY = 250;

// Wheel positioning.
var arc = Math.PI / 18.5;
var context;
var insideRadius = 175;
var outsideRadius = 200;
var startAngle = 1.5 * Math.PI;
var textRadius = 184;

// Wheel style and content.
var black = '#000000';
var fontStyle = 'bold 12px sans-serif';
var green = '#006600';
var lineWidth = 2;
var red = '#ff0000';
var white = '#ffffff';
var numbers = ['0', '32', '15', '19', '4', '21', '2', '25', '17', '34', '6',
               '27', '13', '36', '11', '30', '8', '23', '10', '5', '24', '16',
               '33', '1', '20', '14', '31', '9', '22', '18', '29', '7', '28',
               '12', '35', '3', '26'];

// Wheel spinning.
var spinAngle = 0;
var spinAngleStart = 0;
var spinTime = 0;
var spinTimeout = null;
var spinTimeTotal = 0;

// --------------------------------------------- //

$(document).ready(function() {
  $('#start-button').click(start_game);
  $('#spin-button').click(spin);
});

function draw_wheel() {
  var canvas = document.getElementById('wheel');

  // Make sure the browser supports canvas.
  if (canvas.getContext) {
    context = canvas.getContext('2d');
    context.clearRect(0, 0, 500, 500);

    // Set wheel styles.
    context.strokeStyle = black;
    context.lineWidth = lineWidth;
    context.font = fontStyle;

    // Draw entire wheel.
    for (var i = 0; i < 37; i++) {
      var angle = startAngle + i * arc;

      // Set colors.
      if (i == 0) {
        context.fillStyle = green;
      } else if (i % 2 != 0) {
        context.fillStyle = red;
      } else {
        context.fillStyle = black;
      }

      // Draw wheel.
      context.beginPath();
      context.arc(canvasX, canvasY, outsideRadius, angle, angle + arc, false);
      context.arc(canvasX, canvasY, insideRadius, angle + arc, angle, true);
      context.stroke();
      context.fill();
      context.save();

      // Draw numbers on the wheel.
      var text = numbers[i];
      var transX = canvasX + Math.cos(angle + arc / 2) * textRadius;
      var transY = canvasY + Math.sin(angle + arc / 2) * textRadius;
      var rotateVal = angle + arc / 2 + Math.PI / 2;

      context.translate(transX, transY);
      context.rotate(rotateVal);
      context.fillStyle = white;
      context.fillText(text, -context.measureText(text).width / 2, 0);
      context.restore();
    }

    // Draw arrow.
    context.fillStyle = white;
    context.beginPath();
    context.moveTo(250 - 0, 250 - (outsideRadius + 5));
    context.lineTo(250 + 0, 250 - (outsideRadius + 5));
    context.lineTo(250 + 0, 250 - (outsideRadius - 5));
    context.lineTo(250 + 9, 250 - (outsideRadius - 5));
    context.lineTo(250 + 0, 250 - (outsideRadius - 13));
    context.lineTo(250 - 9, 250 - (outsideRadius - 5));
    context.lineTo(250 - 0, 250 - (outsideRadius - 5));
    context.lineTo(250 - 0, 250 - (outsideRadius + 5));
    context.fill();
  } else {
    alert('Your browser does not support this game! ' +
          'Try Safari, Chrome, Firefox, or Opera.');
  }
}

function ease_out(t, b, c, d) {
  var ts = (t /= d) * t;
  var tc = ts * t;

  return b + c * (tc + -3 * ts + 3 * t);
}

function rotate_wheel() {
  spinTime += 30;

  if (spinTime >= spinTimeTotal) {
    stop_wheel();
  } else {
    spinAngle = spinAngleStart -
                ease_out(spinTime, 0, spinAngleStart, spinTimeTotal);

    startAngle += spinAngle * Math.PI / 180;
    draw_wheel();
    spinTimeout = setTimeout('rotate_wheel()', 30);
  }
}

function spin() {
  spinAngleStart = Math.random() * 10 + 10;
  spinTime = 0;
  spinTimeTotal = (Math.random() * 10 + 2) * 1000;
  rotate_wheel();
}

function start_game() {
  var startBank = $('#starting-bank').val();
  var minBet = $('#min-bet').val();
  var maxBet = $('#max-bet').val();

  $('#form').fadeOut(100, 'linear', function() {
    $('#form').remove();
  });
  $('#title').fadeOut(100, 'linear', function() {
    $('#title').remove();
  });

  $('#game-board').fadeIn(100, 'linear');
  draw_wheel();
}

function stop_wheel() {
  clearTimeout(spinTimeout);

  // Calculate what number the ball landed on.
  var radiansSpun = startAngle - (1.5 * Math.PI);
  var unitsSpun = radiansSpun / arc;
  var number = Math.ceil((unitsSpun % 37));
  if (number == 0) {
    number = 37;
  }
  var index = 37 - number;
  context.save();
  var winningNumber = numbers[index];
  alert('The winning number is ' + winningNumber + '!');
}<commit_msg>game state object added<commit_after>// Copyright (c) 2012 Aaron Roth
// See the file license.txt for copying permission.
//
// This code is based on and at times copied verbatim from a tutorial
// written by Charlie Key. His tutorial is hosted on www.switchonthecode.com
// and is titled "Creating a Roulette Wheel Using HTML5 Canvas."
//

// ------------------ Globals ------------------ //

// Game state object.
var gameState = {
                  "bank": 0,
                  "bets": [
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    },
                    {
                      "team1": 0,
                      "team2": 0
                    }
                  ],
                  "chips": {
                    "team1": 0,
                    "team2": 0
                  },
                  "max": 0,
                  "min": 0,
                  "scores": {
                    "team1": 0,
                    "team2": 0
                  },
                  "wheel": {
                    "color": "",
                    "number": 0
                  }
                };

// Canvas.
var canvasX = 250;
var canvasY = 250;

// Wheel positioning.
var arc = Math.PI / 18.5;
var context;
var insideRadius = 175;
var outsideRadius = 200;
var startAngle = 1.5 * Math.PI;
var textRadius = 184;

// Wheel style and content.
var black = '#000000';
var fontStyle = 'bold 12px sans-serif';
var green = '#006600';
var lineWidth = 2;
var red = '#ff0000';
var white = '#ffffff';
var numbers = ['0', '32', '15', '19', '4', '21', '2', '25', '17', '34', '6',
               '27', '13', '36', '11', '30', '8', '23', '10', '5', '24', '16',
               '33', '1', '20', '14', '31', '9', '22', '18', '29', '7', '28',
               '12', '35', '3', '26'];

// Wheel spinning.
var spinAngle = 0;
var spinAngleStart = 0;
var spinTime = 0;
var spinTimeout = null;
var spinTimeTotal = 0;

// --------------------------------------------- //

$(document).ready(function() {
  $('#start-button').click(start_game);
  $('#spin-button').click(spin);
});

function draw_wheel() {
  var canvas = document.getElementById('wheel');

  // Make sure the browser supports canvas.
  if (canvas.getContext) {
    context = canvas.getContext('2d');
    context.clearRect(0, 0, 500, 500);

    // Set wheel styles.
    context.strokeStyle = black;
    context.lineWidth = lineWidth;
    context.font = fontStyle;

    // Draw entire wheel.
    for (var i = 0; i < 37; i++) {
      var angle = startAngle + i * arc;

      // Set colors.
      if (i == 0) {
        context.fillStyle = green;
      } else if (i % 2 != 0) {
        context.fillStyle = red;
      } else {
        context.fillStyle = black;
      }

      // Draw wheel.
      context.beginPath();
      context.arc(canvasX, canvasY, outsideRadius, angle, angle + arc, false);
      context.arc(canvasX, canvasY, insideRadius, angle + arc, angle, true);
      context.stroke();
      context.fill();
      context.save();

      // Draw numbers on the wheel.
      var text = numbers[i];
      var transX = canvasX + Math.cos(angle + arc / 2) * textRadius;
      var transY = canvasY + Math.sin(angle + arc / 2) * textRadius;
      var rotateVal = angle + arc / 2 + Math.PI / 2;

      context.translate(transX, transY);
      context.rotate(rotateVal);
      context.fillStyle = white;
      context.fillText(text, -context.measureText(text).width / 2, 0);
      context.restore();
    }

    // Draw arrow.
    context.fillStyle = white;
    context.beginPath();
    context.moveTo(250 - 0, 250 - (outsideRadius + 5));
    context.lineTo(250 + 0, 250 - (outsideRadius + 5));
    context.lineTo(250 + 0, 250 - (outsideRadius - 5));
    context.lineTo(250 + 9, 250 - (outsideRadius - 5));
    context.lineTo(250 + 0, 250 - (outsideRadius - 13));
    context.lineTo(250 - 9, 250 - (outsideRadius - 5));
    context.lineTo(250 - 0, 250 - (outsideRadius - 5));
    context.lineTo(250 - 0, 250 - (outsideRadius + 5));
    context.fill();
  } else {
    alert('Your browser does not support this game! ' +
          'Try Safari, Chrome, Firefox, or Opera.');
  }
}

function ease_out(t, b, c, d) {
  var ts = (t /= d) * t;
  var tc = ts * t;

  return b + c * (tc + -3 * ts + 3 * t);
}

function rotate_wheel() {
  spinTime += 30;

  if (spinTime >= spinTimeTotal) {
    stop_wheel();
  } else {
    spinAngle = spinAngleStart -
                ease_out(spinTime, 0, spinAngleStart, spinTimeTotal);

    startAngle += spinAngle * Math.PI / 180;
    draw_wheel();
    spinTimeout = setTimeout('rotate_wheel()', 30);
  }
}

function spin() {
  spinAngleStart = Math.random() * 10 + 10;
  spinTime = 0;
  spinTimeTotal = (Math.random() * 10 + 2) * 1000;
  rotate_wheel();
}

function start_game() {
  var startBank = $('#starting-bank').val();
  var minBet = $('#min-bet').val();
  var maxBet = $('#max-bet').val();

  $('#form').fadeOut(100, 'linear', function() {
    $('#form').remove();
  });
  $('#title').fadeOut(100, 'linear', function() {
    $('#title').remove();
  });

  $('#game-board').fadeIn(100, 'linear');
  draw_wheel();
}

function stop_wheel() {
  clearTimeout(spinTimeout);

  // Calculate what number the ball landed on.
  var radiansSpun = startAngle - (1.5 * Math.PI);
  var unitsSpun = radiansSpun / arc;
  var number = Math.ceil(unitsSpun % 37);
  if (number == 0) {
    number = 37;
  }
  var index = 37 - number;
  context.save();
  var winningNumber = numbers[index];
  alert(gameState["wheel"]["color"]);
  alert('The winning number is ' + winningNumber + '!');
}<|endoftext|>


<commit_before>wwm.shell = (function () {
	var jqMap;
	function setJqMap($con) {
		jqMap = {
			$con: $con,
			$view: $con.find('#view'),
			$modal: $con.find('#modal'),
			$kakaoLogin: $con.find('#kakao-login-btn')
		};
	}
	function initModule($con) {
		var logged = localStorage.login && !!JSON.parse(localStorage.login);
		var first = localStorage.login && JSON.parse(localStorage.first);
		//if (first) {
		//	wwm.modal.initModule($('#wwm-intro').html());
		//}
		if (logged) {
			wwm.lobby.initModule(jqMap.$view);
		} else {
			$con.find('#view').html($('#wwm-login').html());
			setJqMap($con);
			jqMap.$kakaoLogin.on({
				click: function () {
					$.get('/login/kakao').done(function (res) {
						if (res === 'success') {
							alert('로그인되었습니다!');
							wwm.lobby.initModule(jqMap.$view);
						}
					}).fail(function (err) {
						alert(err);
					});
				},
				mouseover: function () {
					this.src = '/kakao_account_login_btn_medium_narrow_ov.png';
				},
				mouseout: function () {
					this.src = '/kakao_account_login_btn_medium_narrow.png';
				}
			});
		}
		Kakao.init('a35623411563ec424430d3bd5dc7a93e');
	}
	return {
		initModule: initModule
	};
}());<commit_msg>Update wwm.shell.js<commit_after>wwm.shell = (function () {
	var jqMap;
	function setJqMap($con) {
		jqMap = {
			$con: $con,
			$view: $con.find('#view'),
			$modal: $con.find('#modal'),
			$kakaoLogin: $con.find('#kakao-login-btn')
		};
	}
	function initModule($con) {
		var logged = localStorage.login && !!JSON.parse(localStorage.login);
		var first = localStorage.login && JSON.parse(localStorage.first);
		//if (first) {
		//	wwm.modal.initModule($('#wwm-intro').html());
		//}
		if (logged) {
			wwm.lobby.initModule(jqMap.$view);
		} else {
			$con.find('#view').html($('#wwm-login').html());
			setJqMap($con);
			jqMap.$kakaoLogin.on({
				click: function () {
					$.get('/login/kakao').done(function (res) {
						if (res === 'success') {
							alert('로그인되었습니다!');
							wwm.lobby.initModule(jqMap.$view);
						}
					}).fail(function (err) {
						console.log(err);
						alert('오류 발생! 콘솔 확인');
					});
				},
				mouseover: function () {
					this.src = '/kakao_account_login_btn_medium_narrow_ov.png';
				},
				mouseout: function () {
					this.src = '/kakao_account_login_btn_medium_narrow.png';
				}
			});
		}
		Kakao.init('a35623411563ec424430d3bd5dc7a93e');
	}
	return {
		initModule: initModule
	};
}());
<|endoftext|>


<commit_before>var connect = require('connect');
var serveStatic = require('serve-static');
connect().use(serveStatic(__dirname+"/public")).listen(8080, function(){
    console.log('Server running on 8080...');
});
<commit_msg>Using<commit_after>var connect = require('connect');
var serveStatic = require('serve-static');
console.log (process.env);
connect().use(serveStatic(__dirname+"/public")).listen($PORT, function(){
    console.log('Server running on' + $PORT);
});
<|endoftext|>