<commit_before>function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Draw ground grass.
    buffer.fillStyle = '#131';
    buffer.fillRect(
      0,
      floor_position,
      width,
      y
    );

    buffer.fillStyle = split_state[0]
      ? '#323232'
      : '#646464';

    // Precalculate left wall split position.
    var precalc = (splits[0][0] * (1 / splits[0][2])) + x;

    // Draw left wall extra bit.
    if(player_position > 0){
        buffer.fillRect(
          0,
          0,
          1 + (player_position >= precalc ? precalc : player_position),
          height
        );
    }

    // Draw left wall closer than split.
    if(player_position < precalc){
        buffer.beginPath();
        buffer.moveTo(
          player_position,
          y - x
        );
        buffer.lineTo(
          precalc,
          (splits[0][1] * (1 / splits[0][2])) + y
        );
        buffer.lineTo(
          precalc,
          (splits[1][1] * (1 / splits[1][2])) + y
        );
        buffer.lineTo(
          player_position,
          y + x
        );
        buffer.closePath();
        buffer.fill();
    }

    // Draw left wall further than split.
    buffer.fillStyle = split_state[0]
      ? '#646464'
      : '#323232';
    buffer.beginPath();
    buffer.moveTo(
      precalc,
      (splits[0][1] * (1 / splits[0][2])) + y
    );
    buffer.lineTo(
      x,
      y
    );
    buffer.lineTo(
      precalc,
      (splits[1][1] * (1 / splits[1][2])) + y
    );
    buffer.closePath();
    buffer.fill();

    buffer.fillStyle = split_state[0]
      ? '#646464'
      : '#323232';

    // Precalculate right wall split position.
    precalc = (splits[2][0] * (1 / splits[2][2])) + x;

    // Draw right wall extra bit.
    if(player_position < 0){
        buffer.fillRect(
          width + player_position < precalc
            ? precalc - 1
            : width + player_position - 1,
          0,
          -player_position,
          height
        );
    }

    // Draw right wall closer than split.
    if(width + player_position > precalc){
        buffer.beginPath();
        buffer.moveTo(
          width + player_position,
          y - x
        );
        buffer.lineTo(
          precalc,
          (splits[2][1] * (1 / splits[2][2])) + y
        );
        buffer.lineTo(
          precalc,
          (splits[3][1] * (1 / splits[3][2])) + y
        );
        buffer.lineTo(
          width + player_position,
          y + x
        );
        buffer.closePath();
        buffer.fill();
    }

    // Draw right wall further than split.
    buffer.fillStyle = split_state[0]
      ? '#323232'
      : '#646464';

    buffer.beginPath();
    buffer.moveTo(
      precalc,
      (splits[2][1] * (1 / splits[2][2])) + y
    );
    buffer.lineTo(
      x,
      y
    );
    buffer.lineTo(
      precalc,
      (splits[3][1] * (1 / splits[3][2])) + y
    );
    buffer.closePath();
    buffer.fill();

    // If frame counter is enabled, draw current frame count.
    if(settings['frame-counter']){
        buffer.fillStyle = '#fff';
        buffer.font = '23pt sans-serif';
        buffer.textAlign = 'left';
        buffer.textBaseline = 'top';
        buffer.fillText(
          frame_counter,
          5,
          5
        );
    }

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    animationFrame = window.requestAnimationFrame(draw);
}

function logic(){
    frame_counter += 1;

    // Get player movement.
    player_dx = 0;
    if(key_left){
        player_dx += x / 20;
    }
    if(key_right){
        player_dx -= x / 20;
    }

    // Update player position.
    player_position += player_dx;

    // Make sure player stays in bounds.
    if(player_position > x / 1.5){
        player_position = x / 1.5;

    }else if(player_position < -x / 1.5){
        player_position = -x / 1.5;
    }

    // Move player forward by moving splits closer.
    for(var id in splits){
        splits[id][2] -= .05;

        // If splits reach player, reset splits.
        if(splits[id][2] < 0){
            splits[id][2] = 25;
            split_state[1] = true;
        }
    }

    // If it is time to reset split.
    if(split_state[1]){
        // Reset player position to start of new section.
        player_position = 0;

        // Switch split.
        split_state[1] = false;
        split_state[0] = !split_state[0];
    }
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('frame-counter').checked = true;
    document.getElementById('movement-keys').value = 'AD';
    document.getElementById('ms-per-frame').value = 25;
    document.getElementById('restart-key').value = 'H';

    save();
}

function resize(){
    if(mode <= 0){
        return;
    }

    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    floor_position = y * (mode - 1);

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

}

// Save settings into window.localStorage if they differ from default.
function save(){
    if(document.getElementById('audio-volume').value == 1){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-audio-volume');
        settings['audio-volume'] = 1;

    }else{
        settings['audio-volume'] = parseFloat(document.getElementById('audio-volume').value);
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-audio-volume',
          settings['audio-volume']
        );
    }

    if(document.getElementById('frame-counter').checked){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-frame-counter');
        settings['frame-counter'] = true;

    }else{
        settings['frame-counter'] = false;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-frame-counter',
          1
        );
    }

    if(document.getElementById('movement-keys').value == 'AD'){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-movement-keys');
        settings['movement-keys'] = 'AD';

    }else{
        settings['movement-keys'] = document.getElementById('movement-keys').value;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-movement-keys',
          settings['movement-keys']
        );
    }

    if(document.getElementById('ms-per-frame').value == 25
      || isNaN(document.getElementById('ms-per-frame').value)
      || document.getElementById('ms-per-frame').value < 1){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-ms-per-frame');
        settings['ms-per-frame'] = 25;

    }else{
        settings['ms-per-frame'] = parseInt(document.getElementById('ms-per-frame').value);
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-ms-per-frame',
          settings['ms-per-frame']
        );
    }

    if(document.getElementById('restart-key').value === 'H'){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-restart-key');
        settings['restart-key'] = 'H';

    }else{
        settings['restart-key'] = document.getElementById('restart-key').value;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-restart-key',
          settings['restart-key']
        );
    }
}

function setmode(newmode, newgame){
    window.cancelAnimationFrame(animationFrame);
    window.clearInterval(interval);

    split_state = [
      false,
      false,
    ];

    mode = newmode;

    // New game mode.
    if(mode > 0){
        splits = [
          [-50, -50, 25],
          [-50, 50, 25],
          [50, -50, 25],
          [50, 50, 25],
        ];

        frame_counter = 0;
        player_dx = 0;
        player_position = 0;

        if(newgame){
            save();

            document.getElementById('page').innerHTML = '<canvas id=canvas></canvas><canvas id=buffer style=display:none></canvas>';

            buffer = document.getElementById('buffer').getContext('2d');
            canvas = document.getElementById('canvas').getContext('2d');

            resize();
        }

        animationFrame = window.requestAnimationFrame(draw);
        interval = window.setInterval(
          'logic()',
          settings['ms-per-frame']
        );

        return;
    }

    // Main menu mode.
    buffer = 0;
    canvas = 0;

    document.getElementById('page').innerHTML = '

Cling to the Ground
Walled Corridor

<input disabled style=border:0 value=ESC>Main Menu
<input id=movement-keys maxlength=2 value='
      + settings['movement-keys'] + '>Move ←→
<input id=restart-key maxlength=1 value='
      + settings['restart-key'] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value='
      + settings['audio-volume'] + '>Audio
<input id=ms-per-frame value='
      + settings['ms-per-frame'] + '>ms/Frame
<input '
      + (settings['frame-counter'] ? 'checked ' : '') + 'id=frame-counter type=checkbox>Frame Counter
Reset Settings

';
}

var animationFrame = 0;
var buffer = 0;
var canvas = 0;
var floor_position = 0;
var frame_counter = 0;
var height = 0;
var interval = 0;
var key_left = false;
var key_right = false;
var mode = 0;
var player_dx = 0;
var player_position = 0;
var settings = {
  'audio-volume': parseFloat(window.localStorage.getItem('FractalRunner-2D3D.htm-audio-volume')) || 1,
  'frame-counter': window.localStorage.getItem('FractalRunner-2D3D.htm-frame-counter') === null,
  'movement-keys': window.localStorage.getItem('FractalRunner-2D3D.htm-movement-keys') || 'AD',
  'ms-per-frame': parseFloat(window.localStorage.getItem('FractalRunner-2D3D.htm-ms-per-frame')) || 25,
  'restart-key': window.localStorage.getItem('FractalRunner-2D3D.htm-restart-key') || 'H',
};
var split_state = [];
var splits = [];
var width = 0;
var x = 0;
var y = 0;

window.onkeydown = function(e){
    if(mode <= 0){
        return;
    }

    var key = e.keyCode || e.which;

    // ESC: return to main menu.
    if(key === 27){
        setmode(
          0,
          true
        );
        return;
    }

    key = String.fromCharCode(key);

    if(key === settings['movement-keys'][0]){
        key_left = true;

    }else if(key === settings['movement-keys'][1]){
        key_right = true;

    }else if(key === settings['restart-key']){
        setmode(
          mode,
          false
        );
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][0]){
        key_left = false;

    }else if(key === settings['movement-keys'][1]){
        key_right = false;
    }
};

window.onload = function(e){
    setmode(
      0,
      true
    );
};

window.onresize = resize;
<commit_msg>added best<commit_after>function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Draw ground grass.
    buffer.fillStyle = '#131';
    buffer.fillRect(
      0,
      floor_position,
      width,
      y
    );

    buffer.fillStyle = split_state[0]
      ? '#323232'
      : '#646464';

    // Precalculate left wall split position.
    var precalc = (splits[0][0] * (1 / splits[0][2])) + x;

    // Draw left wall extra bit.
    if(player_position > 0){
        buffer.fillRect(
          0,
          0,
          1 + (player_position >= precalc ? precalc : player_position),
          height
        );
    }

    // Draw left wall closer than split.
    if(player_position < precalc){
        buffer.beginPath();
        buffer.moveTo(
          player_position,
          y - x
        );
        buffer.lineTo(
          precalc,
          (splits[0][1] * (1 / splits[0][2])) + y
        );
        buffer.lineTo(
          precalc,
          (splits[1][1] * (1 / splits[1][2])) + y
        );
        buffer.lineTo(
          player_position,
          y + x
        );
        buffer.closePath();
        buffer.fill();
    }

    // Draw left wall further than split.
    buffer.fillStyle = split_state[0]
      ? '#646464'
      : '#323232';
    buffer.beginPath();
    buffer.moveTo(
      precalc,
      (splits[0][1] * (1 / splits[0][2])) + y
    );
    buffer.lineTo(
      x,
      y
    );
    buffer.lineTo(
      precalc,
      (splits[1][1] * (1 / splits[1][2])) + y
    );
    buffer.closePath();
    buffer.fill();

    buffer.fillStyle = split_state[0]
      ? '#646464'
      : '#323232';

    // Precalculate right wall split position.
    precalc = (splits[2][0] * (1 / splits[2][2])) + x;

    // Draw right wall extra bit.
    if(player_position < 0){
        buffer.fillRect(
          width + player_position < precalc
            ? precalc - 1
            : width + player_position - 1,
          0,
          -player_position,
          height
        );
    }

    // Draw right wall closer than split.
    if(width + player_position > precalc){
        buffer.beginPath();
        buffer.moveTo(
          width + player_position,
          y - x
        );
        buffer.lineTo(
          precalc,
          (splits[2][1] * (1 / splits[2][2])) + y
        );
        buffer.lineTo(
          precalc,
          (splits[3][1] * (1 / splits[3][2])) + y
        );
        buffer.lineTo(
          width + player_position,
          y + x
        );
        buffer.closePath();
        buffer.fill();
    }

    // Draw right wall further than split.
    buffer.fillStyle = split_state[0]
      ? '#323232'
      : '#646464';

    buffer.beginPath();
    buffer.moveTo(
      precalc,
      (splits[2][1] * (1 / splits[2][2])) + y
    );
    buffer.lineTo(
      x,
      y
    );
    buffer.lineTo(
      precalc,
      (splits[3][1] * (1 / splits[3][2])) + y
    );
    buffer.closePath();
    buffer.fill();

    // If frame counter is enabled, draw current frame count.
    if(settings['frame-counter']){
        buffer.fillStyle = '#fff';
        buffer.font = '23pt sans-serif';
        buffer.textAlign = 'left';
        buffer.textBaseline = 'top';
        buffer.fillText(
          frame_counter,
          5,
          5
        );
        buffer.fillText(
          best,
          5,
          32
        );
    }

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    animationFrame = window.requestAnimationFrame(draw);
}

function logic(){
    frame_counter += 1;

    // Get player movement.
    player_dx = 0;
    if(key_left){
        player_dx += x / 20;
    }
    if(key_right){
        player_dx -= x / 20;
    }

    // Update player position.
    player_position += player_dx;

    // Make sure player stays in bounds.
    if(player_position > x / 1.5){
        player_position = x / 1.5;

    }else if(player_position < -x / 1.5){
        player_position = -x / 1.5;
    }

    // Move player forward by moving splits closer.
    for(var id in splits){
        splits[id][2] -= .05;

        // If splits reach player, reset splits.
        if(splits[id][2] < 0){
            splits[id][2] = 25;
            split_state[1] = true;
        }
    }

    // If it is time to reset split.
    if(split_state[1]){
        // Reset player position to start of new section.
        player_position = 0;

        // Switch split.
        split_state[1] = false;
        split_state[0] = !split_state[0];
    }
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('frame-counter').checked = true;
    document.getElementById('movement-keys').value = 'AD';
    document.getElementById('ms-per-frame').value = 25;
    document.getElementById('restart-key').value = 'H';

    save();
}

function reset_best(){
    if(!window.confirm('Reset best?')){
        return;
    }

    best = 0;
    frame_counter = 0;
    update_best();
    setmode(
      0,
      true
    );
}

function resize(){
    if(mode <= 0){
        return;
    }

    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    floor_position = y * (mode - 1);

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

}

// Save settings into window.localStorage if they differ from default.
function save(){
    if(document.getElementById('audio-volume').value == 1){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-audio-volume');
        settings['audio-volume'] = 1;

    }else{
        settings['audio-volume'] = parseFloat(document.getElementById('audio-volume').value);
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-audio-volume',
          settings['audio-volume']
        );
    }

    if(document.getElementById('frame-counter').checked){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-frame-counter');
        settings['frame-counter'] = true;

    }else{
        settings['frame-counter'] = false;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-frame-counter',
          1
        );
    }

    if(document.getElementById('movement-keys').value == 'AD'){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-movement-keys');
        settings['movement-keys'] = 'AD';

    }else{
        settings['movement-keys'] = document.getElementById('movement-keys').value;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-movement-keys',
          settings['movement-keys']
        );
    }

    if(document.getElementById('ms-per-frame').value == 25
      || isNaN(document.getElementById('ms-per-frame').value)
      || document.getElementById('ms-per-frame').value < 1){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-ms-per-frame');
        settings['ms-per-frame'] = 25;

    }else{
        settings['ms-per-frame'] = parseInt(document.getElementById('ms-per-frame').value);
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-ms-per-frame',
          settings['ms-per-frame']
        );
    }

    if(document.getElementById('restart-key').value === 'H'){
        window.localStorage.removeItem('FractalRunner-2D3D.htm-restart-key');
        settings['restart-key'] = 'H';

    }else{
        settings['restart-key'] = document.getElementById('restart-key').value;
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-restart-key',
          settings['restart-key']
        );
    }
}

function setmode(newmode, newgame){
    window.cancelAnimationFrame(animationFrame);
    window.clearInterval(interval);

    split_state = [
      false,
      false,
    ];

    mode = newmode;

    // New game mode.
    if(mode > 0){
        splits = [
          [-50, -50, 25],
          [-50, 50, 25],
          [50, -50, 25],
          [50, 50, 25],
        ];

        frame_counter = 0;
        player_dx = 0;
        player_position = 0;

        if(newgame){
            save();

            document.getElementById('page').innerHTML = '<canvas id=canvas></canvas><canvas id=buffer style=display:none></canvas>';

            buffer = document.getElementById('buffer').getContext('2d');
            canvas = document.getElementById('canvas').getContext('2d');

            resize();
        }

        animationFrame = window.requestAnimationFrame(draw);
        interval = window.setInterval(
          'logic()',
          settings['ms-per-frame']
        );

        return;
    }

    // Main menu mode.
    buffer = 0;
    canvas = 0;

    document.getElementById('page').innerHTML = '

Cling to the Ground
Walled Corridor

Best: '
      + best
      + '
Reset Best

<input disabled style=border:0 value=ESC>Main Menu
<input id=movement-keys maxlength=2 value='
      + settings['movement-keys'] + '>Move ←→
<input id=restart-key maxlength=1 value='
      + settings['restart-key'] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value='
      + settings['audio-volume'] + '>Audio
<input id=ms-per-frame value='
      + settings['ms-per-frame'] + '>ms/Frame
<input '
      + (settings['frame-counter'] ? 'checked ' : '') + 'id=frame-counter type=checkbox>Frame Counter
Reset Settings

';
}

function update_best(){
    if(frame_counter > best){
        best = frame_counter;
    }

    if(best > 0){
        window.localStorage.setItem(
          'FractalRunner-2D3D.htm-best',
          best
        );

    }else{
        window.localStorage.removeItem('FractalRunner-2D3D.htm-best');
    }
}

var animationFrame = 0;
var best = window.localStorage.getItem('FractalRunner-2D3D.htm-best') === null
  ? 0
  : parseInt(window.localStorage.getItem('FractalRunner-2D3D.htm-best'));
var buffer = 0;
var canvas = 0;
var floor_position = 0;
var frame_counter = 0;
var height = 0;
var interval = 0;
var key_left = false;
var key_right = false;
var mode = 0;
var player_dx = 0;
var player_position = 0;
var settings = {
  'audio-volume': parseFloat(window.localStorage.getItem('FractalRunner-2D3D.htm-audio-volume')) || 1,
  'frame-counter': window.localStorage.getItem('FractalRunner-2D3D.htm-frame-counter') === null,
  'movement-keys': window.localStorage.getItem('FractalRunner-2D3D.htm-movement-keys') || 'AD',
  'ms-per-frame': parseFloat(window.localStorage.getItem('FractalRunner-2D3D.htm-ms-per-frame')) || 25,
  'restart-key': window.localStorage.getItem('FractalRunner-2D3D.htm-restart-key') || 'H',
};
var split_state = [];
var splits = [];
var width = 0;
var x = 0;
var y = 0;

window.onkeydown = function(e){
    if(mode <= 0){
        return;
    }

    var key = e.keyCode || e.which;

    // ESC: return to main menu.
    if(key === 27){
        update_best();
        setmode(
          0,
          true
        );
        return;
    }

    key = String.fromCharCode(key);

    if(key === settings['movement-keys'][0]){
        key_left = true;

    }else if(key === settings['movement-keys'][1]){
        key_right = true;

    }else if(key === settings['restart-key']){
        update_best();
        setmode(
          mode,
          false
        );
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][0]){
        key_left = false;

    }else if(key === settings['movement-keys'][1]){
        key_right = false;
    }
};

window.onload = function(e){
    setmode(
      0,
      true
    );
};

window.onresize = resize;
<|endoftext|>


<commit_before>import {expect} from 'chai';
import Request from '../../src/Request';
import isYoutubeRequest from '../../src/conditions/isYoutubeRequest';

describe('isYoutubeRequest', function() {
	it('should return if the requested URL points to Youtube', function() {
		expect(isYoutubeRequest({
			req: Request('https://www.youtube.com/watch?v=eNcbmrKdf3U')
		})).to.be.true;

		expect(isYoutubeRequest({
			req: Request('https://youtu.be/G5R-F1RmL5Y')
		})).to.be.true;

		expect(isYoutubeRequest({
			req: Request('https://www.google.com')
		})).to.be.false;
	});
});
<commit_msg>Vocabulary<commit_after>import {expect} from 'chai';
import Request from '../../src/Request';
import isYoutubeRequest from '../../src/conditions/isYoutubeRequest';

describe('isYoutubeRequest', function() {
	it('should tell if the requested URL points to Youtube', function() {
		expect(isYoutubeRequest({
			req: Request('https://www.youtube.com/watch?v=eNcbmrKdf3U')
		})).to.be.true;

		expect(isYoutubeRequest({
			req: Request('https://youtu.be/G5R-F1RmL5Y')
		})).to.be.true;

		expect(isYoutubeRequest({
			req: Request('https://www.google.com')
		})).to.be.false;
	});
});
<|endoftext|>


<commit_before>var Alloy = require('alloy'),
	_ = Alloy._,
	Backbone = Alloy.Backbone,
	GA = require('com.animecyc.analytics');

//GA.optOut = true;
GA.debug = false;
GA.trackUncaughtExceptions = true;

var GoogleTracker = GA.getTracker(Alloy.CFG.gaTrackingID);
GoogleTracker.setSessionTimeout(30 * 60);

if (OS_IOS)
	GoogleTracker.setTrackUncaughtExceptions(true);

module.exports = {
	/**
	 * Track a screen
	 *
	 * @param  {String} name The name of the application screen.
	 *
	 */
	trackScreen: function(name) {
		GoogleTracker.trackScreen(name);
	},

	/**
	 * Track an event
	 *
	 * @param {String} category The event category
	 * @param {String} [action] The event action
	 * @param {String} [label] The event label
	 * @param {Number} [value] The event value
	 */
	trackEvent: function(category, action, label, value) {
		GoogleTracker.trackEvent({
			event: category,
			action: action || '',
			label: label || '',
			value: value || 1
		});
	},

	/**
	 * Track social media interaction
	 *
	 * @param  {String} platform The social network with which the user is interacting (e.g. Facebook, Google+, Twitter, etc.).
	 * @param  {String} action The social action taken (e.g. Like, Share, +1, etc.).
	 * @param  {String} [target] The content on which the social action is being taken (i.e. a specific article or video).
	 */
	trackSocial: function(platform, action, target) {
		GoogleTracker.trackSocial({
			social: platform,
			action: action,
			target: target || ''
		});
	},

	/**
	 * [trackTime description]
	 *
	 * @param  {[type]} category [description]
	 * @param  {[type]} interval [description]
	 *
	 * @return {[type]} [description]
	 */
	trackLoadingTime: function(category, interval) {
		GoogleTracker.trackTime({
			category: category,
			interval: interval || 0
		});
	},

	/**
	 * [trackTransaction description]
	 *
	 * @param {Object} config Configuration object
	 * @param {String} config.id A unique ID representing the transaction. This ID should not collide with other transaction IDs.
	 * @param {String} [config.affiliation="In-app Store"] An entity with which the transaction should be affiliated (e.g. a particular store)
	 * @param {Number} config.revenue The total revenue of a transaction, including tax and shipping
	 * @param {String} config.name The name of the product
	 * @param {String} [config.sku] The SKU of the product
	 * @param {String} [config.category] A category to which the product belongs
	 */
	trackTransaction: function(config) {
		var transaction = GA.createTransaction(config.id, {
			affiliation: config.affiliation || 'In-app Store',
			revenue: config.revenue,
			tax: 0,
			shipping: 0
		});

		transaction.addItem({
			sku: config.sku || config.type + '_' + config.name,
			name: config.name,
			category: config.category,
			price: config.revenue,
			quantity: 1
		});

		GoogleTracker.trackTransaction(transaction);
	}
};<commit_msg>Start using other Google Analytics module<commit_after>var Alloy = require('alloy'),
	_ = Alloy._,
	Backbone = Alloy.Backbone,
	GA = require('analytics.google');

//GA.optOut = true;
GA.debug = true;
GA.trackUncaughtExceptions = true;

var GoogleTracker = GA.getTracker(Alloy.CFG.gaTrackingID);

module.exports = {
	/**
	 * Track a screen
	 *
	 * @param  {String} name The name of the application screen.
	 *
	 */
	trackScreen: function(name) {
		GoogleTracker.trackScreen(name);
	},

	/**
	 * Track an event
	 *
	 * @param {String} category The event category
	 * @param {String} [action] The event action
	 * @param {String} [label] The event label
	 * @param {Number} [value] The event value
	 */
	trackEvent: function(category, action, label, value) {
		GoogleTracker.trackEvent({
			category: category,
			action: action || '',
			label: label || '',
			value: value || 1
		});
	},

	/**
	 * Track social media interaction
	 *
	 * @param  {String} platform The social network with which the user is interacting (e.g. Facebook, Google+, Twitter, etc.).
	 * @param  {String} action The social action taken (e.g. Like, Share, +1, etc.).
	 * @param  {String} [target] The content on which the social action is being taken (i.e. a specific article or video).
	 */
	trackSocial: function(platform, action, target) {
		GoogleTracker.trackSocial({
			network: platform,
			action: action,
			target: target || ''
		});
	},

	/**
	 * [trackTime description]
	 *
	 * @param  {[type]} category [description]
	 * @param  {[type]} interval [description]
	 *
	 * @return {[type]} [description]
	 */
	trackLoadingTime: function(category, interval) {
		GoogleTracker.trackTime({
			category: category,
			time: interval || 0
		});
	},

	/**
	 * [trackTransaction description]
	 *
	 * @param {Object} config Configuration object
	 * @param {String} config.id A unique ID representing the transaction. This ID should not collide with other transaction IDs.
	 * @param {String} [config.affiliation="In-app Store"] An entity with which the transaction should be affiliated (e.g. a particular store)
	 * @param {Number} config.revenue The total revenue of a transaction, including tax and shipping
	 * @param {String} config.name The name of the product
	 * @param {String} [config.sku] The SKU of the product
	 * @param {String} [config.category] A category to which the product belongs
	 */
	trackTransaction: function(config) {
		var transaction = GA.createTransaction(config.id, {
			affiliation: config.affiliation || 'In-app Store',
			revenue: config.revenue,
			tax: 0,
			shipping: 0
		});

		transaction.addItem({
			sku: config.sku || config.type + '_' + config.name,
			name: config.name,
			category: config.category,
			price: config.revenue,
			quantity: 1
		});

		GoogleTracker.trackTransaction(transaction);
	}
};
<|endoftext|>


<commit_before>console.log("Starting...")

var config = require("../config.json");

var Queue = new require("./Queue"),
    express = require("express"), app = express(),
    http = require("http"),
    server = http.Server(app),
    io = require("socket.io")(server),
    spotify = require('spotify')({
        appkeyFile: config.spotify.apiKeyLocation
    }),
    loudness = require('loudness'),
    request = require("request");

console.log("Loaded modules")

var queue, spotify, currentTrack, prePhoneVolume, lastTime, accessToken, accessTokenTimeout;
var playing = false;

spotify.on({
    ready: function () {
        console.log("Logged in!");

        queue = new Queue(spotify);

        spotify.player.on({
            endOfTrack: function () {
                playTrack(queue.next());
            }
        });

        server.listen(config.http.port, config.http.ip);
        console.log("Started on port %s:%s", config.http.ip, config.http.port);

        app.use(express.static(__dirname + "/public"));

        io.on('connection', function (socket) {
            socket.on("pause", function () {
                console.log("pause")
                spotify.player.pause();
                playing = false;
                io.emit("playState", playing)
            });
            socket.on("play", function () {
                console.log("play")
                if (!currentTrack) {
                    //Not currently playing anything
                    playTrack(queue.getCurrentTrack());
                } else {
                    spotify.player.resume();
                    playing = true;
                    io.emit("playState", playing)
                }
            });
            socket.on("skip", function () {
                playTrack(queue.next());
            });
            socket.on("skipBack", function () {
                playTrack(queue.previous());
            });
            socket.on("addTrack", function (trackURI) {
                console.log("addTrack", trackURI)
                queue.add(trackURI).then(function () {
                    if (queue.getTracks().length == 1) playTrack(queue.getCurrentTrack())
                });
            })
            socket.on("addTracks", function (tracks) {
                console.log("addTracks", tracks)
                addTracks(tracks);
            })
            socket.on("addPlaylist", function (playlistURI) {
                console.log("addPlaylist", playlistURI)
                var playlist = spotify.createFromLink(playlistURI);
                if (playlist.isLoaded) {
                    addTracks(playlist.getTracks());
                } else {
                    spotify.waitForLoaded([playlist], function () {
                        addTracks(playlist.getTracks());
                    })
                }
            });
            socket.on("getQueue", function () {
                socket.emit("playQueue", queue.getJson()) //No validation needed
            })
            socket.on("toggleShuffle", function (on) {
                queue.toggleShuffle(on); //Validation done in toggleShuffle
            })
            socket.on("repeat", function (repeat) {
                queue.setRepeat(repeat); //TODO add some validation
            })
            socket.on("setVolume", function (volume) {
                loudness.setVolume(volume, function (err) {
                }); //Set power to inverse square (trying to make the slider more linear)
                io.emit("volume", volume);
            })
            socket.on("seek", function (seconds) {
                spotify.player.seek(parseInt(seconds));
            })
            socket.on("phone", function () {
                if (!prePhoneVolume) {
                    loudness.getVolume(function (err, volume) {
                        prePhoneVolume = volume;
                        loudness.setVolume(55, function () {
                        });
                    })
                } else {
                    loudness.setVolume(prePhoneVolume, function () {
                        prePhoneVolume = false;
                    });
                }
            })
            socket.emit("playQueue", queue.getJson())
            socket.emit("playState", playing)
            socket.emit("accessToken", accessToken);
            loudness.getVolume(function (err, volume) {
                socket.emit("volume", volume);
            });
        });

        queue.on("change", function () {
            io.emit("playQueue", queue.getJson())
        })

        setInterval(function () {
            if (spotify.player.currentSecond != lastTime) {
                lastTime = spotify.player.currentSecond;
                io.emit("seek", lastTime);
            }
        }, 1000);
    }
});

function addTracks(tracks) {
    tracks.forEach(function (track) {
        queue.add(track).then(function () {
            if (queue.getTracks().length == 1) playTrack(queue.getCurrentTrack())
        });
    });
}

function updateAccessToken() {
    if (accessTokenTimeout) clearTimeout(accessTokenTimeout);
    request({
        url:     "https://accounts.spotify.com/api/token",
        method:  "POST",
        headers: {
            Authorization: "Basic " + (new Buffer(config.spotify.clientId + ":" + config.spotify.clientSecret)).toString("base64")
        },
        form:    {
            grant_type: "client_credentials"
        }
    }, function (err, message, response) {
        response = JSON.parse(response);
        io.emit("accessToken", response.access_token);
        accessToken = response.access_token;
        accessTokenTimeout = setTimeout(updateAccessToken, (response.expires_in - 60) * 1000); //Update 60 seconds before this one expires (about 59 minutes)
        console.log("Got access token %s", accessToken);
    });
}

console.log("Logging into spotify")

spotify.login(config.spotify.username, config.spotify.password)
updateAccessToken();

function playTrack(track) {
    currentTrack = track;
    if (!track) {
        spotify.player.stop();
        playing = false;
        io.emit("playState", playing)
        return;
    }

    if ("string" === typeof track) track = spotify.createFromLink(track)
    spotify.player.stop();
    if (track.isLoaded) {
        console.log('Playing: %s - %s', track.artists[0].name, track.name);
        spotify.player.play(track);
        playing = true;
        io.emit("playState", playing)
    } else {
        spotify.waitForLoaded([track], function () {
            playTrack(track);
        })
    }
}

<commit_msg>added variable phone volume<commit_after>console.log("Starting...")

var config = require("../config.json");

var Queue = new require("./Queue"),
    express = require("express"), app = express(),
    http = require("http"),
    server = http.Server(app),
    io = require("socket.io")(server),
    spotify = require('spotify')({
        appkeyFile: config.spotify.apiKeyLocation
    }),
    loudness = require('loudness'),
    request = require("request");

console.log("Loaded modules")

var queue, spotify, currentTrack, prePhoneVolume, phoneVolume = 65, lastTime, accessToken, accessTokenTimeout;
var playing = false;

spotify.on({
    ready: function () {
        console.log("Logged in!");

        queue = new Queue(spotify);

        spotify.player.on({
            endOfTrack: function () {
                playTrack(queue.next());
            }
        });

        server.listen(config.http.port, config.http.ip);
        console.log("Started on port %s:%s", config.http.ip, config.http.port);

        app.use(express.static(__dirname + "/public"));

        io.on('connection', function (socket) {
            socket.on("pause", function () {
                console.log("pause")
                spotify.player.pause();
                playing = false;
                io.emit("playState", playing)
            });
            socket.on("play", function () {
                console.log("play")
                if (!currentTrack) {
                    //Not currently playing anything
                    playTrack(queue.getCurrentTrack());
                } else {
                    spotify.player.resume();
                    playing = true;
                    io.emit("playState", playing)
                }
            });
            socket.on("skip", function () {
                playTrack(queue.next());
            });
            socket.on("skipBack", function () {
                playTrack(queue.previous());
            });
            socket.on("addTrack", function (trackURI) {
                console.log("addTrack", trackURI)
                queue.add(trackURI).then(function () {
                    if (queue.getTracks().length == 1) playTrack(queue.getCurrentTrack())
                });
            })
            socket.on("addTracks", function (tracks) {
                console.log("addTracks", tracks)
                addTracks(tracks);
            })
            socket.on("addPlaylist", function (playlistURI) {
                console.log("addPlaylist", playlistURI)
                var playlist = spotify.createFromLink(playlistURI);
                if (playlist.isLoaded) {
                    addTracks(playlist.getTracks());
                } else {
                    spotify.waitForLoaded([playlist], function () {
                        addTracks(playlist.getTracks());
                    })
                }
            });
            socket.on("getQueue", function () {
                socket.emit("playQueue", queue.getJson()) //No validation needed
            })
            socket.on("toggleShuffle", function (on) {
                queue.toggleShuffle(on); //Validation done in toggleShuffle
            })
            socket.on("repeat", function (repeat) {
                queue.setRepeat(repeat); //TODO add some validation
            })
            socket.on("setVolume", function (volume) {
                loudness.setVolume(volume, function (err) {
                }); //Set power to inverse square (trying to make the slider more linear)
                io.emit("volume", volume);
            })
            socket.on("setPhoneVolume", function (volume) {
                phoneVolume = parseInt(volume);
            })
            socket.on("seek", function (seconds) {
                spotify.player.seek(parseInt(seconds));
            })
            socket.on("phone", function () {
                if (!prePhoneVolume) {
                    loudness.getVolume(function (err, volume) {
                        prePhoneVolume = volume;
                        loudness.setVolume(phoneVolume, function () {
                        });
                    })
                } else {
                    loudness.setVolume(prePhoneVolume, function () {
                        prePhoneVolume = false;
                    });
                }
            })
            socket.emit("playQueue", queue.getJson())
            socket.emit("playState", playing)
            socket.emit("accessToken", accessToken);
            loudness.getVolume(function (err, volume) {
                socket.emit("volume", volume);
            });
        });

        queue.on("change", function () {
            io.emit("playQueue", queue.getJson())
        })

        setInterval(function () {
            if (spotify.player.currentSecond != lastTime) {
                lastTime = spotify.player.currentSecond;
                io.emit("seek", lastTime);
            }
        }, 1000);
    }
});

function addTracks(tracks) {
    tracks.forEach(function (track) {
        queue.add(track).then(function () {
            if (queue.getTracks().length == 1) playTrack(queue.getCurrentTrack())
        });
    });
}

function updateAccessToken() {
    if (accessTokenTimeout) clearTimeout(accessTokenTimeout);
    request({
        url:     "https://accounts.spotify.com/api/token",
        method:  "POST",
        headers: {
            Authorization: "Basic " + (new Buffer(config.spotify.clientId + ":" + config.spotify.clientSecret)).toString("base64")
        },
        form:    {
            grant_type: "client_credentials"
        }
    }, function (err, message, response) {
        response = JSON.parse(response);
        io.emit("accessToken", response.access_token);
        accessToken = response.access_token;
        accessTokenTimeout = setTimeout(updateAccessToken, (response.expires_in - 60) * 1000); //Update 60 seconds before this one expires (about 59 minutes)
        console.log("Got access token %s", accessToken);
    });
}

console.log("Logging into spotify")

spotify.login(config.spotify.username, config.spotify.password)
updateAccessToken();

function playTrack(track) {
    currentTrack = track;
    if (!track) {
        spotify.player.stop();
        playing = false;
        io.emit("playState", playing)
        return;
    }

    if ("string" === typeof track) track = spotify.createFromLink(track)
    spotify.player.stop();
    if (track.isLoaded) {
        console.log('Playing: %s - %s', track.artists[0].name, track.name);
        spotify.player.play(track);
        playing = true;
        io.emit("playState", playing)
    } else {
        spotify.waitForLoaded([track], function () {
            playTrack(track);
        })
    }
}

<|endoftext|>


<commit_before>import { createElement } from 'react';
import Proptypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { deburrUpper } from 'app/utils';

import AutocompleteSearchComponent from './autocomplete-search-component';
import actions from './autocomplete-search-actions';
import { getFilteredCountriesWithPath } from './autocomplete-search-selectors';

export { default as component } from './autocomplete-search-component';
export { initialState } from './autocomplete-search-reducers';
export { default as reducers } from './autocomplete-search-reducers';
export { default as styles } from './autocomplete-search-styles';
export { default as actions } from './autocomplete-search-actions';

const mapStateToProps = (state) => {
  const { query } = state.autocompleteSearch;
  return {
    query: deburrUpper(query),
    searchList: getFilteredCountriesWithPath(state.autocompleteSearch)
  };
};

const AutocompleteSearchContainer = (props) => {
  const onOptionClick = (selected) => {
    const { history } = props;
    if (selected) {
      history.push(`ndcs/${selected.value}`);
    }
  };

  return createElement(AutocompleteSearchComponent, {
    ...props,
    onOptionClick
  });
};

AutocompleteSearchContainer.propTypes = {
  query: Proptypes.string,
  history: Proptypes.object
};

export default withRouter(
  connect(mapStateToProps, actions)(AutocompleteSearchContainer)
);
<commit_msg>Clear query on component unmount<commit_after>import { PureComponent, createElement } from 'react';
import Proptypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';

import AutocompleteSearchComponent from './autocomplete-search-component';
import actions from './autocomplete-search-actions';
import { getFilteredCountriesWithPath } from './autocomplete-search-selectors';

export { default as component } from './autocomplete-search-component';
export { initialState } from './autocomplete-search-reducers';
export { default as reducers } from './autocomplete-search-reducers';
export { default as styles } from './autocomplete-search-styles';
export { default as actions } from './autocomplete-search-actions';

const mapStateToProps = (state) => {
  const { autocompleteSearch } = state;
  return {
    query: getQueryUpper(autocompleteSearch),
    searchList: getFilteredCountriesWithPath(autocompleteSearch)
  };
};

class AutocompleteSearchContainer extends PureComponent {
  componentWillUnmount() {
    this.props.setAutocompleteSearch('');
  }

  onOptionClick = (selected) => {
    const { history } = this.props;
    if (selected) {
      history.push(`ndcs/${selected.value}`);
    }
  };

  render() {
    return createElement(AutocompleteSearchComponent, {
      ...this.props,
      onOptionClick: this.onOptionClick
    });
  }
}

AutocompleteSearchContainer.propTypes = {
  history: Proptypes.object,
  setAutocompleteSearch: Proptypes.func.isRequired
};

export default withRouter(
  connect(mapStateToProps, actions)(AutocompleteSearchContainer)
);
<|endoftext|>


<commit_before>this.GobiertoBudgetConsultations.ConsultationResponsesController = (function() {
  function ConsultationResponsesController() {}

  ConsultationResponsesController.prototype.new = function() {
    _runConsultationApplication();
  };

  function _runConsultationApplication() {
    $(document).on('click', '.not-allowed', function(e){
      $(this).tipsy({offset: -40, className: 'tip-warning', fade: true, html: true, gravity: isMobile() ? 'sw' : 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.budget-status-figure', function(e){
      $(this).tipsy({ offset: isMobile() ? -20 : 20, className: 'tip-info', fade: true, html: true, gravity: isMobile() ? 's' : 'n', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.consultation-status-error', function(e){
      $(this).tipsy({ className: 'tip-warning', fade: true, html: true, gravity: 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '[data-tipsy-close]', function(e){
      $('.tipsy').remove();
    });

    var bus = new Vue();

    Vue.component('card-description', {
      props: ['card', 'figures'],
      template: (isMobile() ? '#card-description-mobile' : '#card-description-desktop'),
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
        },
        enter: function (el, done) {
          $(el).velocity("transition.slideDownIn", {duration: 200, delay: 250, complete: function(){
            $('body').animate({
              scrollTop: $(el).offset().top - 85
            }, 400);
          }});
        },
        leave: function (el, done) {
          $(el).velocity("transition.slideUpOut", {duration: 200, complete: function(){}});
        }
      }
    });

    Vue.component('consultation-card', {
      props: ['card', 'active', 'figures'],
      template: (isMobile() ? '#card-mobile' : '#card-desktop'),
      computed: {
        iconForChoice: function(){
          if(this.card.choice === null) return;

          if(this.card.choice > 0) {
            return "fa-arrow-up";
          } else if (this.card.choice == 0){
            return "fa-circle";
          } else if (this.card.choice < 0){
            return "fa-arrow-down";
          }
        }
      },
      methods: {
        setActive: function(card, e) {
          $('.tipsy').remove();

          // Send the active event to the bus
          bus.$emit('active', card);

          card.toggleDesc = !card.toggleDesc;

          // Reset value
          card.hidden = null;

          // Stick it
          $(".desktop .consultation-info").stick_in_parent();
        }
      }
    });

    Vue.component('budget-box', {
      props: ['card', 'figures'],
      template: '#budget-box',
      methods: {
        showModal: function(d) {
          bus.$emit('open', d);
        },
        makeChoice: function(e) {
          e.preventDefault();
          $('.tipsy').remove();
          bus.$emit('cardOptionChosen', $(e.target), this.card);
        }
      }
    });

    Vue.component('budget-calculator', {
      props: ['active', 'next', 'statusText', 'status', 'statusClass'],
      template: '#budget-calculator',
      methods: {
        nextScreen: function(e){
          e.preventDefault();
          bus.$emit('cardOptionChosen', null, null);
        },
        submitConsultation: function(e){
          e.preventDefault();
          bus.$emit('submitConsultation');
        },
        showConsultationStatusError: function(e){
          e.preventDefault();
        }
      },
      updated: function(){
        var $el = $('[data-status-explanation]');
        $el.attr('title', $el.attr('title_' + this.status));
      }
    });

    Vue.component('description-modal', {
      props: ['current'],
      template: '#description-modal',
      methods: {
        hideModal: function() {
          bus.$emit('close');
        }
      }
    });

    var app = new Vue({
      el: (isMobile() ? "#consultation-mobile-app" : "#consultation-desktop-app"),
      data: {
        figures: false,
        active: false,
        modal: false,
        next: false,
        current: null,
        statusDifference: 0,
        cards: [],
      },
      computed: {
        statusText: function(){
          return I18n.t('gobierto_budget_consultations.consultation_statuses.' + this.status);
        },
        statusClass: function(){
          // Track difference between status
          // The status class variable maxes out at 4 to be applied to the card class
          var classId = this.statusDifference;

          if (classId > 4)  classId = 4;
          if (classId < -4) classId = -4;

          if (classId < 0) return 'surplus surplus-' + Math.abs(classId);
          if (classId > 0) return 'deficit deficit-' + Math.abs(classId);
        },
        status: function(){
          if(this.statusDifference === 0) return 'balance';
          if (this.statusDifference < 0)  return 'surplus';
          return 'deficit';
        }
      },
      methods: {
        fetchData: function(){
          var self = this;
          var url = $(self.$options.el).data('data-url');
          $.ajax({
            url: url,
            dataType: 'json',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            },
            success: function(response, textStatus, jqXHR){
              if(jqXHR.status == 200){
                Vue.set(self, 'cards', response);
              } else {
                // TODO: handle errors
              }
            },
          });
        },
        cardOptionChosenHandler: function($el, currentCard){
          this.choiceCardAndOpenNext($el, currentCard);
          var allSelected = true;
          app.$data.cards.forEach(function(card){
            if(card.choice === null)
              allSelected = false;
          });

          if(allSelected){
            Vue.set(app, 'next', true);
            $('.consultation-confirm').css('width', $('.description').width() - 79);

            $('body').animate({
              scrollTop: $(app.$el).offset().top - 25
            }, 500);
          }
        },
        choiceCardAndOpenNext: function($el, currentCard){
          if(currentCard !== null){
            var positiveCards = 0;
            var negativeCards = 0;
            app.$data.cards.forEach(function(card){
              if(currentCard === card) {
                card.choice = $el.data('value');
                card.toggleDesc = false;
              }
              if(card.choice > 0) {
                positiveCards++;
              } else if (card.choice < 0) {
                negativeCards++;
              }
            });
          }
          this.statusDifference = positiveCards - negativeCards;

          var found = false;
          app.$data.cards.forEach(function(card){
            if(!found && card.choice === null){
              card.toggleDesc = true;
              found = true;
              bus.$emit('active', card);
            }
          });
        },
        submitConsultation: function(){
          var self = this;
          var url = $(self.$options.el).data('submit-url');
          var data = app.$data.cards.map(function(card){
            return {
              item_id: card.id,
              selected_option: card.choice
            }
          });
          $.ajax({
            type: "POST",
            data: {
              consultation_response: {
                selected_options: data
              }
            },
            url: url,
            dataType: 'script',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            }
          });
        }
      },
      created: function() {
        $(this.$options.el).show();
        this.fetchData();

        bus.$on('active', function(currentCard) {
          Vue.set(app, 'active', true);

          app.$data.cards.forEach(function(card){
            if(currentCard != card)
              card.toggleDesc = false;
          });

          if (app.$data.next) {
            $('.consultation-confirm').addClass('slim');
            $('.slim').css('top', 0);
          }

          var $target = $('[data-card-id="'+currentCard.id+'"]');
          var $targetDescription = $('[data-card-description-id="'+currentCard.id+'"]');
          if($targetDescription.length){
            if ($('.card-wrapper').css('top') === 'auto') {
              var offset = $target.offset().top - 220;
            } else {
              var offset = $target.offset().top - 250;
            }
            $targetDescription.css({ top: offset + 'px' });
          }
        });

        bus.$on('open', function(d) {
          Vue.set(app, 'current', d);
          Vue.set(app, 'modal', true);
        });

        bus.$on('close', function() {
          Vue.set(app, 'modal', false);
        });

        bus.$on('cardOptionChosen', this.cardOptionChosenHandler);

        bus.$on('submitConsultation', this.submitConsultation);
      },
    });
  }

  return ConsultationResponsesController;
})();

this.GobiertoBudgetConsultations.consultation_responses_controller = new GobiertoBudgetConsultations.ConsultationResponsesController;
<commit_msg>Disable submit button<commit_after>this.GobiertoBudgetConsultations.ConsultationResponsesController = (function() {
  function ConsultationResponsesController() {}

  ConsultationResponsesController.prototype.new = function() {
    _runConsultationApplication();
  };

  function _runConsultationApplication() {
    $(document).on('click', '.not-allowed', function(e){
      $(this).tipsy({offset: -40, className: 'tip-warning', fade: true, html: true, gravity: isMobile() ? 'sw' : 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.budget-status-figure', function(e){
      $(this).tipsy({ offset: isMobile() ? -20 : 20, className: 'tip-info', fade: true, html: true, gravity: isMobile() ? 's' : 'n', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '.consultation-status-error', function(e){
      $(this).tipsy({ className: 'tip-warning', fade: true, html: true, gravity: 's', opacity: 1, trigger: 'manual' });
      $(this).tipsy('show');
    });

    $(document).on('click', '[data-tipsy-close]', function(e){
      $('.tipsy').remove();
    });

    var bus = new Vue();

    Vue.component('card-description', {
      props: ['card', 'figures'],
      template: (isMobile() ? '#card-description-mobile' : '#card-description-desktop'),
      methods: {
        beforeEnter: function (el) {
          el.style.opacity = 0
        },
        enter: function (el, done) {
          $(el).velocity("transition.slideDownIn", {duration: 200, delay: 250, complete: function(){
            $('body').animate({
              scrollTop: $(el).offset().top - 85
            }, 400);
          }});
        },
        leave: function (el, done) {
          $(el).velocity("transition.slideUpOut", {duration: 200, complete: function(){}});
        }
      }
    });

    Vue.component('consultation-card', {
      props: ['card', 'active', 'figures'],
      template: (isMobile() ? '#card-mobile' : '#card-desktop'),
      computed: {
        iconForChoice: function(){
          if(this.card.choice === null) return;

          if(this.card.choice > 0) {
            return "fa-arrow-up";
          } else if (this.card.choice == 0){
            return "fa-circle";
          } else if (this.card.choice < 0){
            return "fa-arrow-down";
          }
        }
      },
      methods: {
        setActive: function(card, e) {
          $('.tipsy').remove();

          // Send the active event to the bus
          bus.$emit('active', card);

          card.toggleDesc = !card.toggleDesc;

          // Reset value
          card.hidden = null;

          // Stick it
          $(".desktop .consultation-info").stick_in_parent();
        }
      }
    });

    Vue.component('budget-box', {
      props: ['card', 'figures'],
      template: '#budget-box',
      methods: {
        showModal: function(d) {
          bus.$emit('open', d);
        },
        makeChoice: function(e) {
          e.preventDefault();
          $('.tipsy').remove();
          bus.$emit('cardOptionChosen', $(e.target), this.card);
        }
      }
    });

    Vue.component('budget-calculator', {
      props: ['active', 'next', 'statusText', 'status', 'statusClass'],
      template: '#budget-calculator',
      methods: {
        nextScreen: function(e){
          e.preventDefault();
          bus.$emit('cardOptionChosen', null, null);
        },
        submitConsultation: function(e){
          e.preventDefault();
          $(e.target).prop('disabled', true);
          bus.$emit('submitConsultation');
        },
        showConsultationStatusError: function(e){
          e.preventDefault();
        }
      },
      updated: function(){
        var $el = $('[data-status-explanation]');
        $el.attr('title', $el.attr('title_' + this.status));
      }
    });

    Vue.component('description-modal', {
      props: ['current'],
      template: '#description-modal',
      methods: {
        hideModal: function() {
          bus.$emit('close');
        }
      }
    });

    var app = new Vue({
      el: (isMobile() ? "#consultation-mobile-app" : "#consultation-desktop-app"),
      data: {
        figures: false,
        active: false,
        modal: false,
        next: false,
        current: null,
        statusDifference: 0,
        cards: [],
      },
      computed: {
        statusText: function(){
          return I18n.t('gobierto_budget_consultations.consultation_statuses.' + this.status);
        },
        statusClass: function(){
          // Track difference between status
          // The status class variable maxes out at 4 to be applied to the card class
          var classId = this.statusDifference;

          if (classId > 4)  classId = 4;
          if (classId < -4) classId = -4;

          if (classId < 0) return 'surplus surplus-' + Math.abs(classId);
          if (classId > 0) return 'deficit deficit-' + Math.abs(classId);
        },
        status: function(){
          if(this.statusDifference === 0) return 'balance';
          if (this.statusDifference < 0)  return 'surplus';
          return 'deficit';
        }
      },
      methods: {
        fetchData: function(){
          var self = this;
          var url = $(self.$options.el).data('data-url');
          $.ajax({
            url: url,
            dataType: 'json',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            },
            success: function(response, textStatus, jqXHR){
              if(jqXHR.status == 200){
                Vue.set(self, 'cards', response);
              } else {
                // TODO: handle errors
              }
            },
          });
        },
        cardOptionChosenHandler: function($el, currentCard){
          this.choiceCardAndOpenNext($el, currentCard);
          var allSelected = true;
          app.$data.cards.forEach(function(card){
            if(card.choice === null)
              allSelected = false;
          });

          if(allSelected){
            Vue.set(app, 'next', true);
            $('.consultation-confirm').css('width', $('.description').width() - 79);

            $('body').animate({
              scrollTop: $(app.$el).offset().top - 25
            }, 500);
          }
        },
        choiceCardAndOpenNext: function($el, currentCard){
          if(currentCard !== null){
            var positiveCards = 0;
            var negativeCards = 0;
            app.$data.cards.forEach(function(card){
              if(currentCard === card) {
                card.choice = $el.data('value');
                card.toggleDesc = false;
              }
              if(card.choice > 0) {
                positiveCards++;
              } else if (card.choice < 0) {
                negativeCards++;
              }
            });
          }
          this.statusDifference = positiveCards - negativeCards;

          var found = false;
          app.$data.cards.forEach(function(card){
            if(!found && card.choice === null){
              card.toggleDesc = true;
              found = true;
              bus.$emit('active', card);
            }
          });
        },
        submitConsultation: function(e){
          if(e !== undefined)
            $(e.target).prop('disabled', true);

          var self = this;
          var url = $(self.$options.el).data('submit-url');
          var data = app.$data.cards.map(function(card){
            return {
              item_id: card.id,
              selected_option: card.choice
            }
          });
          $.ajax({
            type: "POST",
            data: {
              consultation_response: {
                selected_options: data
              }
            },
            url: url,
            dataType: 'script',
            beforeSend: function(xhr){
              xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            }
          });
        }
      },
      created: function() {
        $(this.$options.el).show();
        this.fetchData();

        bus.$on('active', function(currentCard) {
          Vue.set(app, 'active', true);

          app.$data.cards.forEach(function(card){
            if(currentCard != card)
              card.toggleDesc = false;
          });

          if (app.$data.next) {
            $('.consultation-confirm').addClass('slim');
            $('.slim').css('top', 0);
          }

          var $target = $('[data-card-id="'+currentCard.id+'"]');
          var $targetDescription = $('[data-card-description-id="'+currentCard.id+'"]');
          if($targetDescription.length){
            if ($('.card-wrapper').css('top') === 'auto') {
              var offset = $target.offset().top - 220;
            } else {
              var offset = $target.offset().top - 250;
            }
            $targetDescription.css({ top: offset + 'px' });
          }
        });

        bus.$on('open', function(d) {
          Vue.set(app, 'current', d);
          Vue.set(app, 'modal', true);
        });

        bus.$on('close', function() {
          Vue.set(app, 'modal', false);
        });

        bus.$on('cardOptionChosen', this.cardOptionChosenHandler);

        bus.$on('submitConsultation', this.submitConsultation);
      },
    });
  }

  return ConsultationResponsesController;
})();

this.GobiertoBudgetConsultations.consultation_responses_controller = new GobiertoBudgetConsultations.ConsultationResponsesController;
<|endoftext|>


<commit_before>var assert = require('assert'),
    fs = require('fs'),
    files = require('../src/scripts/files'),
    parser = require('../src/scripts/parser'),
    processor = require('../src/scripts/processor'),
    sinon = require('sinon');

describe('processor', function () {
    describe('processOptions', function () {
        describe('reverse === false', function () {
            var opts = {
                reverse: false,
                config: { src: 'src/path', dist: 'dist/path' }
            };

            it('Should retrieve the json files in the src directory', function () {
                files.getJsonFiles = sinon.stub().returns([]);

                processor.processOptions(opts);
                assert(files.getJsonFiles.calledWith('src/path'));
            });

            it('Should convert the json files into properties files', function () {
                files.getJsonFiles = sinon.stub().returns([ 'file1.json', 'file2.json' ]);
                files.getFileDataAsString = sinon.stub().returns('data');
                files.writeAsProperties = sinon.spy();

                JSON.parse = sinon.stub().returns({ some: 'key' });
                parser.deflate = sinon.stub().returns([ 'entry1', 'entry2' ]);

                processor.processOptions(opts);

                assert(files.getFileDataAsString.calledWith('src/path', 'file1.json'));
                assert(files.getFileDataAsString.calledWith('src/path', 'file2.json'));

                assert(JSON.parse.calledWith('data'));
                assert(parser.deflate.calledWith({ some: 'key' }));

                assert(files.writeAsProperties.calledWith('dist/path', 'file1.json', [ 'entry1', 'entry2' ]));
                assert(files.writeAsProperties.calledWith('dist/path', 'file2.json', [ 'entry1', 'entry2' ]));
            });
        });

        describe('reverse === true', function () {
            var opts = {
                reverse: true,
                config: { src: 'src/path', dist: 'dist/path' },
                spaces: 2
            };

            it('Should retrieve the properties files in the src directory', function () {
                files.getPropertiesFiles = sinon.stub().returns([]);

                processor.processOptions(opts);
                assert(files.getPropertiesFiles.calledWith('src/path'));
            });

            it('Should convert the properties files into json files', function (done) {
                files.getPropertiesFiles = sinon.stub().returns([ 'file1.properties', 'file2.properties' ]);

                var promise = Promise.resolve([ 'line1', 'line2' ]);
                files.getFileDataAsLines = sinon.stub().returns(promise);
                files.writeAsJson = sinon.spy();

                JSON.stringify = sinon.stub().returns('somevalue');
                parser.inflate = sinon.stub().returns({ key: 'value' });

                processor.processOptions(opts);
                promise.then(function () {
                    assert(JSON.stringify.calledWith({ key: 'value' }, null, 2));
                    assert(parser.inflate.calledWith([ 'line1', 'line2' ]));

                    assert(files.writeAsJson.calledWith('dist/path', 'file1.properties', 'somevalue'));
                    assert(files.writeAsJson.calledWith('dist/path', 'file2.properties', 'somevalue'));
                }).then(done, done);

                assert(files.getFileDataAsLines.calledWith('src/path', 'file1.properties'));
                assert(files.getFileDataAsLines.calledWith('src/path', 'file2.properties'));
            });
        });
    });

    describe('process', function () {
        it('Should call process options with the default options if non are provided', function () {
            process.cwd = sinon.stub().returns('some/path');
            processor.processOptions = sinon.spy();

            processor.process({});
            var defaultOpts = {
                config: { src: 'some/path', dist: 'some/path' },
                reverse: false,
                spaces: 4
            };
            assert(processor.processOptions.calledWith(defaultOpts));
        });

        it('Should call process options with the provided options', function () {
            processor.processOptions = sinon.spy();

            processor.process({ config: { src: 'path/one', dist: 'path/two' } });
            var opts = {
                config: { src: 'path/one', dist: 'path/two' },
                reverse: false,
                spaces: 4
            };
            assert(processor.processOptions.calledWith(opts));
        });
    });
});<commit_msg>- Fixed broken tests<commit_after>var assert = require('assert'),
    fs = require('fs'),
    files = require('../src/scripts/files'),
    parser = require('../src/scripts/parser'),
    processor = require('../src/scripts/processor'),
    sinon = require('sinon');

describe('processor', function () {
    describe('processOptions', function () {
        describe('reverse === false', function () {
            var opts = {
                reverse: false,
                config: { src: 'src/path', dist: 'dist/path' }
            };

            it('Should retrieve the json files in the src directory', function () {
                files.getJsonFiles = sinon.stub().returns([]);

                processor.processOptions(opts);
                assert(files.getJsonFiles.calledWith('src/path'));
            });

            it('Should convert the json files into properties files', function () {
                files.getJsonFiles = sinon.stub().returns([ 'file1.json', 'file2.json' ]);
                files.getFileDataAsString = sinon.stub().returns('data');
                files.writeAsProperties = sinon.spy();

                JSON.parse = sinon.stub().returns({ some: 'key' });
                parser.deflate = sinon.stub().returns([ 'entry1', 'entry2' ]);

                processor.processOptions(opts);

                assert(files.getFileDataAsString.calledWith('src/path', 'file1.json'));
                assert(files.getFileDataAsString.calledWith('src/path', 'file2.json'));

                assert(JSON.parse.calledWith('data'));
                assert(parser.deflate.calledWith({ some: 'key' }));

                assert(files.writeAsProperties.calledWith('dist/path', 'file1.json', [ 'entry1', 'entry2' ]));
                assert(files.writeAsProperties.calledWith('dist/path', 'file2.json', [ 'entry1', 'entry2' ]));
            });
        });

        describe('reverse === true', function () {
            var opts = {
                reverse: true,
                config: { src: 'src/path', dist: 'dist/path' },
                spaces: 2
            };

            it('Should retrieve the properties files in the src directory', function () {
                files.getPropertiesFiles = sinon.stub().returns([]);

                processor.processOptions(opts);
                assert(files.getPropertiesFiles.calledWith('src/path'));
            });

            it('Should convert the properties files into json files', function (done) {
                files.getPropertiesFiles = sinon.stub().returns([ 'file1.properties', 'file2.properties' ]);

                var promise = Promise.resolve([ 'line1', 'line2' ]);
                files.getFileDataAsLines = sinon.stub().returns(promise);
                files.writeAsJson = sinon.spy();

                JSON.stringify = sinon.stub().returns('somevalue');
                parser.inflate = sinon.stub().returns({ key: 'value' });

                processor.processOptions(opts);
                promise.then(function () {
                    assert(JSON.stringify.calledWith({ key: 'value' }, null, 2));
                    assert(parser.inflate.calledWith([ 'line1', 'line2' ]));

                    assert(files.writeAsJson.calledWith('dist/path', 'file1.properties', 'somevalue'));
                    assert(files.writeAsJson.calledWith('dist/path', 'file2.properties', 'somevalue'));
                }).then(done, done);

                assert(files.getFileDataAsLines.calledWith('src/path', 'file1.properties'));
                assert(files.getFileDataAsLines.calledWith('src/path', 'file2.properties'));
            });
        });
    });

    describe('process', function () {
        it('Should call process options with the default options if non are provided', function () {
            process.cwd = sinon.stub().returns('some/path');
            processor.processOptions = sinon.spy();

            processor.process({});
            var defaultOpts = {
                config: { src: 'some/path', dist: 'some/path' },
                reverse: false,
                spaces: 4,
                merge: ''
            };
            assert(processor.processOptions.calledWith(defaultOpts));
        });

        it('Should call process options with the provided options', function () {
            processor.processOptions = sinon.spy();

            processor.process({ config: { src: 'path/one', dist: 'path/two' } });
            var opts = {
                config: { src: 'path/one', dist: 'path/two' },
                reverse: false,
                spaces: 4,
                merge: ''
            };
            assert(processor.processOptions.calledWith(opts));
        });
    });
});<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

/**
 * Serve que quality of a required package using mongodb
 * (C) 2015 Diego Lafuente.
 */

// requires
var path = require('path');
var config = require('../config.js');
var express = require('express');
var db = require('../lib/db.js');
var badges = require('../lib/badges.js');
var Log = require('log');

// globals
var log = new Log(config.logLevel);
var packagesCollection;
var server;

exports.startServer = function(port, callback) {
	if (typeof port === 'function') {
		// no port
		callback = port;
		port = config.expressPort;
	}
	var app = express();
	// Static files
	app.use(express.static(path.join(__dirname, '..', 'app')));
	// Enable JSONP
	app.set('jsonp callback', true);
	// GET requests
	app.get('/package/:package', serve);
	app.get('/packages', servePackagesList);
    app.get('/badge/:package', serveBadge);
	// connect to database
	db.addCallback(function(error, result) {
		if (error) {
            return callback(error);
        }
		packagesCollection = result.collection(config.packagesCollection);
		// serve
		server = app.listen(port, callback);
	});
};

exports.stopServer = function(callback) {
	if (!server) {
		log.info('No server to close');
		return callback(null);
	}
	server.close(function() {
		log.info('Server closed');
		callback(null);
	});
};

function serveBadge (request, response) {
	var packageName = request.params['package'];
	badges.compileBadge(packageName, (Math.random() * 10).toFixed(1), function (err, str) {
		response.send('');
	});
}

function servePackagesList (request, response) {
	packagesCollection.find({}, {name: true}).toArray(function(error, result) {
		if (error) {
			response.send(500);
			return;
		}
		var packages = (result || []).map(function (pkg) {
			return pkg.name;
		});
		response.send(packages);
	});
}

function serve (request, response) {
	var npmPackage = request.params.package;
	packagesCollection.findOne({name: npmPackage}, function(error, result) {
		if (error || !result) {
			delete result._id;
			return response.status(403).send({error: 'package ' + npmPackage + ' not found.'});
		}
		return response.jsonp(result);
	});
}

<commit_msg>Show the real quality in the badge<commit_after>#!/usr/bin/env node
'use strict';

/**
 * Serve que quality of a required package using mongodb
 * (C) 2015 Diego Lafuente.
 */

// requires
var path = require('path');
var config = require('../config.js');
var express = require('express');
var db = require('../lib/db.js');
var badges = require('../lib/badges.js');
var Log = require('log');

// globals
var log = new Log(config.logLevel);
var packagesCollection;
var server;

exports.startServer = function(port, callback) {
	if (typeof port === 'function') {
		// no port
		callback = port;
		port = config.expressPort;
	}
	var app = express();
	// Static files
	app.use(express.static(path.join(__dirname, '..', 'app')));
	// Enable JSONP
	app.set('jsonp callback', true);
	// GET requests
	app.get('/package/:package', serve);
	app.get('/packages', servePackagesList);
    app.get('/badge/:package', serveBadge);
	// connect to database
	db.addCallback(function(error, result) {
		if (error) {
            return callback(error);
        }
		packagesCollection = result.collection(config.packagesCollection);
		// serve
		server = app.listen(port, callback);
	});
};

exports.stopServer = function(callback) {
	if (!server) {
		log.info('No server to close');
		return callback(null);
	}
	server.close(function() {
		log.info('Server closed');
		callback(null);
	});
};

function serveBadge (request, response) {
	var packageName = request.params['package'];
	packagesCollection.findOne({name: packageName}, function(error, result) {
		if (error || !result) {
			delete result._id;
			return response.status(403).send({error: 'package ' + packageName + ' not found.'});
		}
		badges.compileBadge(packageName, parseInt(result.quality * 100, 10), function (err, str) {
			response.send('');
		});
	});
}

function servePackagesList (request, response) {
	packagesCollection.find({}, {name: true}).toArray(function(error, result) {
		if (error) {
			response.send(500);
			return;
		}
		var packages = (result || []).map(function (pkg) {
			return pkg.name;
		});
		response.send(packages);
	});
}

function serve (request, response) {
	var npmPackage = request.params.package;
	packagesCollection.findOne({name: npmPackage}, function(error, result) {
		if (error || !result) {
			delete result._id;
			return response.status(403).send({error: 'package ' + npmPackage + ' not found.'});
		}
		return response.jsonp(result);
	});
}

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
//var badges = ['E1:C1:21:A2:B2:E0','D1:90:32:2F:F1:4B'];
var badges = ['E1:C1:21:A2:B2:E0'];
var badgesTimeouts = {};
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
        detailPage.hidden = true;
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
        refreshButton.addEventListener('touchstart', this.refreshDeviceList, false);
        connectButton.addEventListener('touchstart', this.connect, false);
        disconnectButton.addEventListener('touchstart', this.disconnect, false);
        autogoButton.addEventListener('touchstart', this.autogo, false);
        /*
        sendButton.addEventListener('click', this.sendData, false);
        isConnectedButton.addEventListener('touchstart', this.isConnected, false);
        disconnectButton.addEventListener('touchstart', this.disconnect, false);
        deviceList.addEventListener('touchstart', this.connect, false); // assume not scrolling

        */
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        console.log("HERE!");

        // populate intervals dict
        for (var i = 0; i < badges.length; ++i) {
            console.log("Adding: "+badges[i]);
            badgesTimeouts[badges[i]]=null;
        }

        bluetoothle.initialize(
            app.initializeSuccess,
            {request: true,statusReceiver: true}
        );
    },
    initializeSuccess: function (obj) {
        console.log('Success');

        // Android v6.0 required requestPermissions. If it's Android < 5.0 there'll
        // be an error, but don't worry about it.
        if (cordova.platformId === 'android') {
            console.log('Asking for permissions');
            bluetoothle.requestPermission(
            function(obj) {
                console.log('prem ok');
            },
            function(obj) {
                console.log('prem err');
            }
            );
        }
    },
    refreshDeviceList: function() {
        console.log('Start scan');
        deviceList.innerHTML = ''; // empties the list

        bluetoothle.startScan(app.startScanSuccess, app.startScanError, {});
        console.log('Start scan call end');
    },
    startScanSuccess: function(obj) {
        if (obj.status == "scanResult")
        {
            console.log("Found - "+obj.address);
            console.log("Found - "+Object.keys(obj));

            //console.log("Stopping scan..");
            //bluetoothle.stopScan(stopScanSuccess, stopScanError);
            //clearScanTimeout();

            //window.localStorage.setItem(addressKey, obj.address);
            //    connectDevice(obj.address);

            var listItem = document.createElement('li'),
                html = '' + obj.name + '
' +
                    'RSSI: ' + obj.rssi + ' | ' +
                    obj.address;

            //if (device.name == "BADGE") {
            if (badges.indexOf(obj.address) != -1) {
                console.log('Found: '+ obj.address);
                //app.connectToDevice(device.id);

                listItem.dataset.deviceId = obj.address;
                listItem.innerHTML = html;
                deviceList.appendChild(listItem);
            }
        }
        else if (obj.status == "scanStarted")
        {
            console.log("Scan was started successfully, stopping in 10");
            scanTimer = setTimeout(app.scanTimeout, 10000);
        }
        else
        {
            console.log("Unexpected start scan status: " + obj.status);
        }
    },
    startScanError: function(obj) {
      console.log("Start scan error: " + obj.error + " - " + obj.message);
    },
    scanTimeout: function()
    {
        function stopScanError(obj) {
            console.log("Stop scan error: " + obj.error + " - " + obj.message);
        ;}
        var stopScanSuccess = function(obj){
          if (obj.status == "scanStopped")
          {
            console.log("Scan was stopped successfully");
          }
          else
          {
            console.log("Unexpected stop scan status: " + obj.status);
          }
        };
        console.log("Scanning time out, stopping");
        bluetoothle.stopScan(stopScanSuccess, stopScanError);
    },
    connect: function() {
        app.connectDevice(badges[0]);
    },
    /*
    Connect to a Bluetooth LE device. The app should use a timer to limit the connecting time in case connecting
    is never successful. Once a device is connected, it may disconnect without user intervention. The original
    connection callback will be called again and receive an object with status => disconnected. To reconnect to
    the device, use the reconnect method. If a timeout occurs, the connection attempt should be canceled using
    disconnect(). For simplicity, I recommend just using connect() and close(), don't use reconnect() or disconnect().
    */
    connectDevice: function(address)
    {
        var connectError = function(obj){
            console.log("Connect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
            app.closeDevice(obj.address,true); //Best practice is to close on connection error
        };

        var connectSuccess = function(obj){
            console.log("Connected: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));

            //todo: check status. If status is disconnceted it means that the device disconnected
            // for some reason so we need to close()... or do we?

            // Closes the device after we are done
            if (obj.status == "connected") {
                console.log("Done. Call disconnect")
                app.closeDevice(obj.address, true);
            } else {
                console.log("Disconnected for some reason.")
                app.closeDevice(obj.address,false); //Best practice is to close on connection error
            }
        };

        console.log("Beginning connection to: " + address);
        var paramsObj = {"address":address};
        bluetoothle.connect(connectSuccess, connectError, paramsObj);
    },
    disconnect: function() {
        app.closeDevice(badges[0],false);
    },
    closeDevice: function(address,reconnect)
    {
        var onCloseReconnectError = function(obj){
            console.log("Close with reconnect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
            // setting a timeout with several seconds before reconecting
            setTimeout(app.connectToDeviceWrap(obj.address),2000);
        };

        var onCloseNoReconnectError = function(obj){
            console.log("Close without reconnect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
        };

        var onCloseReconnect = function(obj){
            console.log("Close with reconnect: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));
            // setting a timeout with several seconds before reconecting
            setTimeout(app.connectToDeviceWrap(obj.address),2000);
        };

        var onCloseNoReconnect = function(obj){
            console.log("Close without reconnect: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));
        };

        console.log("Beginning close from: " + address + " Reconnect: "+reconnect);
        var paramsObj = {"address":address};
        if (reconnect) {
            bluetoothle.close(onCloseReconnect, onCloseReconnectError, paramsObj);
        } else {
            bluetoothle.close(onCloseNoReconnect, onCloseNoReconnectError, paramsObj);
        }

    },
    connectToDeviceWrap : function(deviceId){
        return function() {
            app.connectDevice(deviceId);
        }
    },
    autogo: function() {
        for (var i = 0; i < badges.length; ++i) {
            var badge=badges[i];
            var f = app.connectToDeviceWrap(badge);
            console.log("initializing connection to "+badge);
            //var interval = setInterval(f,1000);
            f();

            //var f2 = app.disconnectFromDeviceWrap(badge);
            //console.log("Starting timer for disconnecting from "+badge);
            //var interval2 = setInterval(f2,1500);
        }
    }
};

app.initialize();<commit_msg>added connection timeout. doesn't look promising though<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
//var badges = ['E1:C1:21:A2:B2:E0','D1:90:32:2F:F1:4B'];
var badges = ['E1:C1:21:A2:B2:E0'];
var badgesTimeouts = {};
var connectTimer = null;

var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
        detailPage.hidden = true;
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
        refreshButton.addEventListener('touchstart', this.refreshDeviceList, false);
        connectButton.addEventListener('touchstart', this.connect, false);
        disconnectButton.addEventListener('touchstart', this.disconnect, false);
        autogoButton.addEventListener('touchstart', this.autogo, false);
        /*
        sendButton.addEventListener('click', this.sendData, false);
        isConnectedButton.addEventListener('touchstart', this.isConnected, false);
        disconnectButton.addEventListener('touchstart', this.disconnect, false);
        deviceList.addEventListener('touchstart', this.connect, false); // assume not scrolling

        */
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        console.log("HERE!");

        // populate intervals dict
        for (var i = 0; i < badges.length; ++i) {
            console.log("Adding: "+badges[i]);
            badgesTimeouts[badges[i]]=null;
        }

        bluetoothle.initialize(
            app.initializeSuccess,
            {request: true,statusReceiver: true}
        );
    },
    initializeSuccess: function (obj) {
        console.log('Success');

        // Android v6.0 required requestPermissions. If it's Android < 5.0 there'll
        // be an error, but don't worry about it.
        if (cordova.platformId === 'android') {
            console.log('Asking for permissions');
            bluetoothle.requestPermission(
            function(obj) {
                console.log('prem ok');
            },
            function(obj) {
                console.log('prem err');
            }
            );
        }
    },
    refreshDeviceList: function() {
        console.log('Start scan');
        deviceList.innerHTML = ''; // empties the list

        bluetoothle.startScan(app.startScanSuccess, app.startScanError, {});
        console.log('Start scan call end');
    },
    startScanSuccess: function(obj) {
        if (obj.status == "scanResult")
        {
            console.log("Found - "+obj.address);
            console.log("Found - "+Object.keys(obj));

            //console.log("Stopping scan..");
            //bluetoothle.stopScan(stopScanSuccess, stopScanError);
            //clearScanTimeout();

            //window.localStorage.setItem(addressKey, obj.address);
            //    connectDevice(obj.address);

            var listItem = document.createElement('li'),
                html = '' + obj.name + '
' +
                    'RSSI: ' + obj.rssi + ' | ' +
                    obj.address;

            //if (device.name == "BADGE") {
            if (badges.indexOf(obj.address) != -1) {
                console.log('Found: '+ obj.address);
                //app.connectToDevice(device.id);

                listItem.dataset.deviceId = obj.address;
                listItem.innerHTML = html;
                deviceList.appendChild(listItem);
            }
        }
        else if (obj.status == "scanStarted")
        {
            console.log("Scan was started successfully, stopping in 10");
            scanTimer = setTimeout(app.scanTimeout, 10000);
        }
        else
        {
            console.log("Unexpected start scan status: " + obj.status);
        }
    },
    startScanError: function(obj) {
      console.log("Start scan error: " + obj.error + " - " + obj.message);
    },
    scanTimeout: function()
    {
        function stopScanError(obj) {
            console.log("Stop scan error: " + obj.error + " - " + obj.message);
        ;}
        var stopScanSuccess = function(obj){
          if (obj.status == "scanStopped")
          {
            console.log("Scan was stopped successfully");
          }
          else
          {
            console.log("Unexpected stop scan status: " + obj.status);
          }
        };
        console.log("Scanning time out, stopping");
        bluetoothle.stopScan(stopScanSuccess, stopScanError);
    },
    connect: function() {
        app.connectDevice(badges[0]);
    },
    /*
    Connect to a Bluetooth LE device. The app should use a timer to limit the connecting time in case connecting
    is never successful. Once a device is connected, it may disconnect without user intervention. The original
    connection callback will be called again and receive an object with status => disconnected. To reconnect to
    the device, use the reconnect method. If a timeout occurs, the connection attempt should be canceled using
    disconnect(). For simplicity, I recommend just using connect() and close(), don't use reconnect() or disconnect().
    */
    connectDevice: function(address)
    {
        var connectError = function(obj){
            console.log("Connect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
            app.clearConnectTimeout();

            app.closeDevice(obj.address,true); //Best practice is to close on connection error. In our cae
                                               //we also want to reconnect afterwards
        };

        var connectSuccess = function(obj){
            console.log("Connected: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));
            app.clearConnectTimeout();

            // Closes the device after we are done
            if (obj.status == "connected") {
                console.log("Done. Call disconnect")

                app.closeDevice(obj.address, true);
            } else {
                console.log("Unexpected disconnected")
                app.closeDevice(obj.address,false); //Best practice is to close on connection error. No need to
                                                    //reconnect here, it seems.
            }
        };

        console.log("Beginning connection to: " + address);
        var paramsObj = {"address":address};
        bluetoothle.connect(connectSuccess, connectError, paramsObj);

        // timer for killing connections that take too long
        console.log("Setting timeout (timer was: "+connectTimer+")");
        //console.log("Setting timeout");
        connectTimer = setTimeout(app.connectTimeout, 5000);
    },
    connectTimeout: function()
    {
      console.log("Connection timed out");
      app.closeDevice(badges[0],true); //TODO - change to a parameter!
    },
    clearConnectTimeout: function()
    {
        console.log("Clearing connect timeout");
        if (connectTimer != null)
        {
            clearTimeout(connectTimer);
        }
    },

    disconnect: function() {
        app.closeDevice(badges[0],false);
    },
    closeDevice: function(address,reconnect)
    {
        var onCloseReconnectError = function(obj){
            console.log("Close with reconnect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
            // setting a timeout with several seconds before reconecting
            setTimeout(app.connectToDeviceWrap(obj.address),2000);
        };

        var onCloseNoReconnectError = function(obj){
            console.log("Close without reconnect error: " + obj.error + " - " + obj.message + " Keys: "+Object.keys(obj));
        };

        var onCloseReconnect = function(obj){
            console.log("Close with reconnect: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));
            // setting a timeout with several seconds before reconecting
            setTimeout(app.connectToDeviceWrap(obj.address),2000);
        };

        var onCloseNoReconnect = function(obj){
            console.log("Close without reconnect: " + obj.status + " - " + obj.address + " Keys: "+Object.keys(obj));
        };

        console.log("Beginning close from: " + address + " Reconnect: "+reconnect);
        var paramsObj = {"address":address};
        if (reconnect) {
            bluetoothle.close(onCloseReconnect, onCloseReconnectError, paramsObj);
        } else {
            bluetoothle.close(onCloseNoReconnect, onCloseNoReconnectError, paramsObj);
        }

    },
    connectToDeviceWrap : function(deviceId){
        return function() {
            app.connectDevice(deviceId);
        }
    },
    autogo: function() {
        for (var i = 0; i < badges.length; ++i) {
            var badge=badges[i];
            var f = app.connectToDeviceWrap(badge);
            console.log("initializing connection to "+badge);
            //var interval = setInterval(f,1000);
            f();

            //var f2 = app.disconnectFromDeviceWrap(badge);
            //console.log("Starting timer for disconnecting from "+badge);
            //var interval2 = setInterval(f2,1500);
        }
    }
};

app.initialize();<|endoftext|>