<commit_before>'use strict';

/**
 * Module dependencies.
 */
var users = require('../../app/controllers/users'),
	articles = require('../../app/controllers/articles');

module.exports = function(app) {
	// Article Routes
	app.route('/articles')
		.get(articles.list)
		.post(users.requiresLogin, articles.create);

	app.route('/articles/:articleId')
		.get(articles.read)
		.put(users.requiresLogin, articles.hasAuthorization, articles.update)
		.delete(users.requiresLogin, articles.hasAuthorization, articles.delete);

	// Finish by binding the article middleware
	app.param('articleId', articles.articleByID);
};<commit_msg>Added Multer<commit_after>'use strict';

/**
 * Module dependencies.
 */
var users = require('../../app/controllers/users'),
	articles = require('../../app/controllers/articles');
var multer =require('multer');
var fileHandler =require('../../app/controllers/local-file-handle');
var multerTemp=multer({ dest: config.filesTemp, limits: {
	fieldNameSize: 255,
	fields: 7,
	files: 1,
	fileSize:100000
}});

module.exports = function(app) {
	// Article Routes
	app.route('/articles')
		.get(articles.list)
		.post(users.requiresLogin, multerTemp, articles.create, fileHandler.uploadFile);

	app.route('/articles/:articleId')
		.get(articles.read)
		.put(users.requiresLogin, articles.hasAuthorization, articles.update)
		.delete(users.requiresLogin, articles.hasAuthorization, articles.delete);

	// Finish by binding the article middleware
	app.param('articleId', articles.articleByID);
};
<|endoftext|>


<commit_before>// 配置页面路由 'chat'
var app_router = angular.module( 'chat' , ['ngRoute']).run(function($rootScope,socket,$location) {
    $rootScope.pageH = document.documentElement.clientHeight-200;
    socket.on('connect',function(){
        // 连接成功
        console.log('连接消息服务器成功');
    });
    if (!$rootScope.login_status){
        var local_uid = localStorage.getItem('UID');
        if (local_uid){
            socket.emit('login',{'uid': local_uid})
        }else{
            $location.path('/login/');
        }
    }
    socket.on('disconnect', function(){});
});

// 配置页面
app_router.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/recently/', {
            templateUrl: 'views/recently.html',
            controller: 'recentlyPageController'
        }).
        when('/contacts/', {
            templateUrl: 'views/contacts.html',
            controller: 'contactsPageController'
        }).
        when('/settings/', {
            templateUrl: 'views/settings.html',
            controller: 'settingsPageController'
        }).
        when('/login/', {
            templateUrl: 'views/login.html',
            controller: 'loginPageController'
        }).

        otherwise({redirectTo: '/recently/'});
}]);

app_router.factory('socket', function ($rootScope) {
    //var socket = io('http://www.tihub.cn:3000');
    var socket = io('http://127.0.0.1:3000');
    return {
        on: function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        },
        emit: function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            })
        }
    };
});

// 判断是否为手机号码
function isPhone(phone){
    var myreg = /^0\d{2,3}\d{7,8}$|^1[34578]\d{9}$|^147\d{8}/;
    if(!myreg.test(phone)){
        return false;
    }else{
        return true;
    }
}

// 判断是否为手机号码
function isEmail(email){
    var myreg = /[^\._-][\w\.-]+@(?:[A-Za-z0-9]+\.)+[A-Za-z]+/;
    if(!myreg.test(email)){
        return false;
    }else{
        return true;
    }
}

// 扩展ng-enter指令
app_router.directive('ngEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.ngEnter);
                });
                event.preventDefault();
            }
        });
    };
});

angular.module('chat').controller(
    'recentlyPageController',
    function recentlyPageController($scope, $rootScope, $http, socket) {
        $rootScope.link_index = 1;
        $scope.contact_index = 2;

        $scope.message_list = [
            {
                from : '21',
                to : '12',
                content : "你好",
                time : new Date().getTime()
            }
        ];

        socket.emit('recently_list',{'uid':'12'});
        socket.on('recently_list', function(data){
            console.log("发送回去最近聊天列表...");
        });
        socket.on('recently_list_response', function(data){
            console.log("获取z最近聊天列表成功",data);
            var contacts = data['recent_list'];
            $scope.contacts = contacts;
        });

        // 发送消息
        $scope.sendMessage = function(){
            var message = $scope.message;
            if (!message){
                return;
            }
            // 将消息显示在消息列表中
            var msg = {
                from : $rootScope.uid,
                to : $scope.current.uid,
                content : message,
                time : new Date().getTime()
            };
            socket.emit('chat_message', msg);
            $scope.message_list.push(msg);
            $scope.message = '';
        };
        socket.on('chat_message', function(data){
            console.log("接受到聊天消息",data);
        });

        $scope.chatWith = function(obj){
            $scope.contact_index = obj.$index;

            // 当前选中的用户
            $scope.current = {
                uid : obj.contact.uid,
                name : obj.contact.name,
                avatar: obj.contact.avatar
            }
        };

    }
);

angular.module('chat').controller(
    'contactsPageController',
    function contactsPageController($scope, $rootScope, $http, socket) {
        $rootScope.link_index = 2;
        $scope.contact_index = 2;

        socket.emit('contact_list',{'uid':'12'});
        socket.on('contact_list', function(data){
            console.log("请求好友列表。。。",data);
        });
        socket.on('contact_list_response', function(data){
            console.log("获取好友列表成功",data);
            var contacts = data['contacts'];
            $scope.contacts = contacts;
        });

        $scope.chatWith = function(obj){
            $scope.contact_index = obj.$index;

            // 当前选中的用户
            $scope.current = {
                name : obj.contact.name,
                avatar: obj.contact.avatar
            }
        };

    }
);

angular.module('chat').controller(
    'settingsPageController',
    function settingsPageController($scope, $rootScope, $http) {
        $rootScope.link_index = 3;

    }
);

angular.module('chat').controller(
    'loginPageController',
    function loginPageController($scope, $rootScope, $http, socket, $location) {

        $rootScope.login = function(){
            var username = $rootScope.username;
            socket.emit('login',{'uid': username})
        };

        socket.on('login', function(data){
            console.log("发送登录请求...");
        });

        socket.on('login_response', function(data){
            console.log("登录成功",data);
            var uid = data['uid'];
            $rootScope.login_status = true;
            $rootScope.uid = uid;
            localStorage.setItem('UID',uid);
            $location.path('/recently/')
        });
    }
);

<commit_msg>修改前端数据<commit_after>// 配置页面路由 'chat'
var app_router = angular.module( 'chat' , ['ngRoute']).run(function($rootScope,socket,$location) {
    $rootScope.pageH = document.documentElement.clientHeight-200;
    socket.on('connect',function(){
        // 连接成功
        console.log('连接消息服务器成功');
    });
    if (!$rootScope.login_status){
        var local_uid = localStorage.getItem('UID');
        if (local_uid){
            socket.emit('login',{'uid': local_uid})
            socket.on('login_response', function(data){
                console.log("登录成功",data);
                var uid = data['uid'];
                $rootScope.login_status = true;
                $rootScope.uid = uid;
                $location.path('/recently/')
            });
        }else{
            $location.path('/login/');
        }
    }
    socket.on('disconnect', function(){});
});

// 配置页面
app_router.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/recently/', {
            templateUrl: 'views/recently.html',
            controller: 'recentlyPageController'
        }).
        when('/contacts/', {
            templateUrl: 'views/contacts.html',
            controller: 'contactsPageController'
        }).
        when('/settings/', {
            templateUrl: 'views/settings.html',
            controller: 'settingsPageController'
        }).
        when('/login/', {
            templateUrl: 'views/login.html',
            controller: 'loginPageController'
        }).

        otherwise({redirectTo: '/recently/'});
}]);

app_router.factory('socket', function ($rootScope) {
    //var socket = io('http://www.tihub.cn:3000');
    var socket = io('http://127.0.0.1:3000');
    return {
        on: function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        },
        emit: function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            })
        }
    };
});

// 判断是否为手机号码
function isPhone(phone){
    var myreg = /^0\d{2,3}\d{7,8}$|^1[34578]\d{9}$|^147\d{8}/;
    if(!myreg.test(phone)){
        return false;
    }else{
        return true;
    }
}

// 判断是否为手机号码
function isEmail(email){
    var myreg = /[^\._-][\w\.-]+@(?:[A-Za-z0-9]+\.)+[A-Za-z]+/;
    if(!myreg.test(email)){
        return false;
    }else{
        return true;
    }
}

// 扩展ng-enter指令
app_router.directive('ngEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.ngEnter);
                });
                event.preventDefault();
            }
        });
    };
});

angular.module('chat').controller(
    'recentlyPageController',
    function recentlyPageController($scope, $rootScope, $http, socket) {
        $rootScope.link_index = 1;
        $scope.contact_index = 2;

        $scope.message_list = [
            {
                from : '21',
                to : '12',
                content : "你好",
                time : new Date().getTime()
            }
        ];

        socket.emit('recently_list',{'uid':'12'});
        socket.on('recently_list', function(data){
            console.log("发送回去最近聊天列表...");
        });
        socket.on('recently_list_response', function(data){
            console.log("获取z最近聊天列表成功",data);
            var contacts = data['recent_list'];
            $scope.contacts = contacts;
        });

        // 发送消息
        $scope.sendMessage = function(){
            var message = $scope.message;
            if (!message){
                return;
            }
            // 将消息显示在消息列表中
            var msg = {
                from : $rootScope.uid,
                to : $scope.current.uid,
                content : message,
                time : new Date().getTime()
            };
            socket.emit('chat_message', msg);
            $scope.message_list.push(msg);
            $scope.message = '';
        };
        socket.on('chat_message', function(data){
            console.log("接受到聊天消息",data);
        });

        $scope.chatWith = function(obj){
            $scope.contact_index = obj.$index;

            // 当前选中的用户
            $scope.current = {
                uid : obj.contact.uid,
                name : obj.contact.name,
                avatar: obj.contact.avatar
            }
        };

    }
);

angular.module('chat').controller(
    'contactsPageController',
    function contactsPageController($scope, $rootScope, $http, socket) {
        $rootScope.link_index = 2;
        $scope.contact_index = 2;

        socket.emit('contact_list',{'uid':'12'});
        socket.on('contact_list', function(data){
            console.log("请求好友列表。。。",data);
        });
        socket.on('contact_list_response', function(data){
            console.log("获取好友列表成功",data);
            var contacts = data['contacts'];
            $scope.contacts = contacts;
        });

        $scope.chatWith = function(obj){
            $scope.contact_index = obj.$index;

            // 当前选中的用户
            $scope.current = {
                name : obj.contact.name,
                avatar: obj.contact.avatar
            }
        };

    }
);

angular.module('chat').controller(
    'settingsPageController',
    function settingsPageController($scope, $rootScope, $http) {
        $rootScope.link_index = 3;

    }
);

angular.module('chat').controller(
    'loginPageController',
    function loginPageController($scope, $rootScope, $http, socket, $location) {

        $rootScope.login = function(){
            var username = $rootScope.username;
            socket.emit('login',{'uid': username})
        };

        socket.on('login', function(data){
            console.log("发送登录请求...");
        });

        socket.on('login_response', function(data){
            console.log("登录成功",data);
            var uid = data['uid'];
            $rootScope.login_status = true;
            $rootScope.uid = uid;
            localStorage.setItem('UID',uid);
            $location.path('/recently/')
        });
    }
);

<|endoftext|>


<commit_before>'use strict';

angular
  .module('app.players')
  /**
   * @ngdoc controller
   * @name app.players.controller:PlayersController
   * @description
   * The controller for the players list.
   */
  .controller('PlayersController', [
    'PlayersAdapter',
    'PlayerFactory',
    function(PlayersAdapter, PlayerFactory) {
      var vm = this;

      // Exposes public methods
      vm.addNewPlayer = addNewPlayer;
      vm.areSelectedPlayersEnough = areSelectedPlayersEnough;
      vm.deselectPlayer = deselectPlayer;
      vm.isPlayerSelected = isPlayerSelected;
      vm.selectPlayer = selectPlayer;
      vm.togglePlayer = togglePlayer;

      /**
       * @ngdoc property
       * @name PlayersController#adapter
       * @type {Object}
       * @propertyOf app.players.controller:PlayersController
       */
      vm.adapter = PlayersAdapter;

      /**
       * @ngdoc method
       * @name PlayersController#isPlayerSelected
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The given player
       * @return {boolean} True if the given player has been already selected.
       * @description
       * Determines if the give player has been already selected or not.
       */
      function isPlayerSelected(player) {
        return vm.adapter.getSelectedPlayers().indexOf(player) >= 0;
      }

      /**
       * @ngdoc method
       * @name PlayersController#togglePlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The given player
       * @description
       * Add/remove selection from the give player.
       */
      function togglePlayer(player) {
        if (vm.isPlayerSelected(player)) {
          vm.deselectPlayer(player);
        }
        else {
          vm.selectPlayer(player);
        }
      }

      /**
       * @ngdoc method
       * @name PlayersController#areSelectedPlayersEnough
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @return {boolean} True if user selected enough players.
       * @description
       * Determines if user selected enough players to start match.
       */
      function areSelectedPlayersEnough() {
        return vm.adapter.getSelectedPlayers().length >= 2;
      }

      /**
       * @ngdoc method
       * @name PlayersController#deselectPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The player to remove from the selected players list.
       * @description
       * Remove the given player from the selected players list.
       */
      function deselectPlayer(player) {
        var selectedPlayers = vm.adapter.getSelectedPlayers();
        var offset = selectedPlayers.indexOf(player);
        selectedPlayers.splice(offset, 1);
        vm.adapter.persistSelectedPlayers(selectedPlayers);
      }

      /**
       * @ngdoc method
       * @name PlayersController#selectPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The player to add into the selected players list.
       * @description
       * Add the given player into the selected players list.
       */
      function selectPlayer(player) {
        var selectedPlayers = vm.adapter.getSelectedPlayers();
        selectedPlayers.push(player);
        vm.adapter.persistSelectedPlayers(selectedPlayers);
      }

      /**
       * @ngdoc method
       * @name PlayersController#addNewPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @description
       * Creates a new player and adds it into:
       * - selected players list
       * - saved players list
       */
      function addNewPlayer() {
        if (vm.newPlayerName) {
          var newPlayer = PlayerFactory.create(vm.newPlayerName);
          vm.newPlayerName = null;

          vm.selectPlayer(newPlayer);

          var savedPlayers = vm.adapter.getSavedPlayers();
          savedPlayers.push(newPlayer);
          vm.adapter.persistSavedPlayers(savedPlayers);
        }
      }

    }
  ]);
<commit_msg>fixed #36 isPlayerSelected does not work as expected<commit_after>'use strict';

angular
  .module('app.players')
  /**
   * @ngdoc controller
   * @name app.players.controller:PlayersController
   * @description
   * The controller for the players list.
   */
  .controller('PlayersController', [
    'PlayersAdapter',
    'PlayerFactory',
    function(PlayersAdapter, PlayerFactory) {
      var vm = this;

      // Exposes public methods
      vm.addNewPlayer = addNewPlayer;
      vm.areSelectedPlayersEnough = areSelectedPlayersEnough;
      vm.deselectPlayer = deselectPlayer;
      vm.isPlayerSelected = isPlayerSelected;
      vm.selectPlayer = selectPlayer;
      vm.togglePlayer = togglePlayer;

      /**
       * @ngdoc property
       * @name PlayersController#adapter
       * @type {Object}
       * @propertyOf app.players.controller:PlayersController
       */
      vm.adapter = PlayersAdapter;

      /**
       * @ngdoc method
       * @name PlayersController#isPlayerSelected
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The given player
       * @return {boolean} True if the given player has been already selected.
       * @description
       * Determines if the give player has been already selected or not.
       */
      function isPlayerSelected(player) {
        var isPlayerSelected = false;
        angular.forEach(vm.adapter.getSelectedPlayers(), function(selectedPlayer) {
          if (selectedPlayer.id === player.id) {
            isPlayerSelected = true;
          }
        });
        return isPlayerSelected;
      }

      /**
       * @ngdoc method
       * @name PlayersController#togglePlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The given player
       * @description
       * Add/remove selection from the give player.
       */
      function togglePlayer(player) {
        if (vm.isPlayerSelected(player)) {
          vm.deselectPlayer(player);
        }
        else {
          vm.selectPlayer(player);
        }
      }

      /**
       * @ngdoc method
       * @name PlayersController#areSelectedPlayersEnough
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @return {boolean} True if user selected enough players.
       * @description
       * Determines if user selected enough players to start match.
       */
      function areSelectedPlayersEnough() {
        return vm.adapter.getSelectedPlayers().length >= 2;
      }

      /**
       * @ngdoc method
       * @name PlayersController#deselectPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The player to remove from the selected players list.
       * @description
       * Remove the given player from the selected players list.
       */
      function deselectPlayer(player) {
        var selectedPlayers = vm.adapter.getSelectedPlayers();
        var offset = selectedPlayers.indexOf(player);
        selectedPlayers.splice(offset, 1);
        vm.adapter.persistSelectedPlayers(selectedPlayers);
      }

      /**
       * @ngdoc method
       * @name PlayersController#selectPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @param {Object} player The player to add into the selected players list.
       * @description
       * Add the given player into the selected players list.
       */
      function selectPlayer(player) {
        var selectedPlayers = vm.adapter.getSelectedPlayers();
        selectedPlayers.push(player);
        vm.adapter.persistSelectedPlayers(selectedPlayers);
      }

      /**
       * @ngdoc method
       * @name PlayersController#addNewPlayer
       * @kind function
       * @methodOf app.players.controller:PlayersController
       * @description
       * Creates a new player and adds it into:
       * - selected players list
       * - saved players list
       */
      function addNewPlayer() {
        if (vm.newPlayerName) {
          var newPlayer = PlayerFactory.create(vm.newPlayerName);
          vm.newPlayerName = null;

          vm.selectPlayer(newPlayer);

          var savedPlayers = vm.adapter.getSavedPlayers();
          savedPlayers.push(newPlayer);
          vm.adapter.persistSavedPlayers(savedPlayers);
        }
      }

    }
  ]);
<|endoftext|>


<commit_before>(function() {
     function AlbumCtrl(Fixtures) {
         this.albumData = [];
         for (var i=0; i < 12; i++) {
             this.albumData = Fixtures.getAlbum();
         }
     }

     angular
         .module('blocJams')
         .controller('AlbumCtrl', ['Fixtures', AlbumCtrl]);
 })();<commit_msg>services1 checkpoint completed.<commit_after>(function() {
     function AlbumCtrl(Fixtures) {
         this.albumData = [];
         for (var i=0; i < 12; i++) {
             this.albumData = Fixtures.getAlbum();

         }
     }

     angular
         .module('blocJams')
         .controller('AlbumCtrl', ['Fixtures', AlbumCtrl]);
 })();<|endoftext|>


<commit_before>'use strict';

const express = require('express');

const couples = require('./data/couples');
const checkToken = require('./middlewares/check-token');
const getCombinationId = require('./helpers/get-combination-id');
const getStats = require('./helpers/get-stats');

const { sequelize, Answer, Combination, Token } = require('./models');

sequelize.sync();

const port = process.env.PORT || 5000;
const app = express();
app.use(express.json());
app.use(express.static('../client/build'));

/** CHOOSE API */

app.get('/couples', async function(request, response) {
  const couple1 = couples.getRandom();
  const couple2 = couples.getRandom(couple1);

  const combination = getCombinationId(couple1.id, couple2.id);
  const token = await Token.create({ combination });
  response.json({ couples: [couple1, couple2], token: token.token });
});

app.get('/stats', async function(request, response) {
  const stats = await getStats();
  response.json(stats);
});

app.post('/answer', checkToken, async function(request, response) {
  const association1 = request.body.association1
    .split(',')
    .sort()
    .join(',');
  const association2 = request.body.association2
    .split(',')
    .sort()
    .join(',');
  const answerContent = [association1, association2].sort().join(';');

  try {
    let answer = await Answer.findOne({ where: { answer: answerContent } });
    if (!answer) {
      answer = await Answer.create({
        answer: answerContent,
        combination: request.combination,
      });
    }
    answer.count = answer.count + 1;
    await Answer.update({ count: answer.count }, { where: { id: answer.id } });

    let combination = await Combination.findOne({
      where: {
        combination: request.combination,
      },
    });
    if (!combination) {
      combination = await Combination.create({
        combination: request.combination,
      });
    }
    combination.count = combination.count + 1;
    await Combination.update(
      { count: combination.count },
      { where: { id: combination.id } }
    );

    const stats = await getStats();

    response
      .status(200)
      .json({ count: answer.count, total: combination.count, stats });
  } catch (error) {
    response.status(500).json({ error });
  }
});

/** BROWSE API */

app.get('/browse/couples', async function(request, response) {
  response.json({ couples: couples.getAll() });
});

app.listen(port, function() {
  process.stdout.write(`ASAW server is listening on port ${port}\n`);
});
<commit_msg>Add an API endpoint to return combination stats<commit_after>'use strict';

const express = require('express');

const couples = require('./data/couples');
const checkToken = require('./middlewares/check-token');
const getCombinationId = require('./helpers/get-combination-id');
const getStats = require('./helpers/get-stats');

const { sequelize, Answer, Combination, Token } = require('./models');

sequelize.sync();

const port = process.env.PORT || 5000;
const app = express();
app.use(express.json());
app.use(express.static('../client/build'));

async function getCombinationStats(combinationId) {
  const combination = await Combination.findOne({
    where: {
      combination: combinationId,
    },
  });
  const answers = await Answer.findAll({
    where: {
      combination: combinationId,
    }
  });

  return {
    combination: combination.combination,
    total: combination.count,
    answers: answers.map(({ answer, count }) => ({ answer, count })),
  };
}

/** CHOOSE API */

app.get('/couples', async function (request, response) {
  const couple1 = couples.getRandom();
  const couple2 = couples.getRandom(couple1);

  const combination = getCombinationId(couple1.id, couple2.id);
  const token = await Token.create({ combination });
  response.json({ couples: [couple1, couple2], token: token.token });
});

app.get('/stats', async function (request, response) {
  const stats = await getStats();
  response.json(stats);
});

app.post('/answer', checkToken, async function (request, response) {
  const association1 = request.body.association1.split(',').sort().join(',');
  const association2 = request.body.association2.split(',').sort().join(',');
  const answerContent = [association1, association2].sort().join(';');

  try {
    let answer = await Answer.findOne({ where: { answer: answerContent } });
    if (!answer) {
      answer = await Answer.create({
        answer: answerContent,
        combination: request.combination,
      });
    }
    answer.count = answer.count + 1;
    await Answer.update({ count: answer.count }, { where: { id: answer.id } });

    let combination = await Combination.findOne({
      where: {
        combination: request.combination,
      },
    });
    if (!combination) {
      combination = await Combination.create({
        combination: request.combination,
      });
    }
    combination.count = combination.count + 1;
    await Combination.update(
      { count: combination.count },
      { where: { id: combination.id } }
    );

    const stats = await getStats();

    response
      .status(200)
      .json({ count: answer.count, total: combination.count, stats });
  } catch (error) {
    response.status(500).json({ error: error.message });
  }
});

/** BROWSE API */

app.get('/browse/couples', async function (request, response) {
  response.json({ couples: couples.getAll() });
});

app.get('/browse/stats', async function (request, response) {
  try {
    const combinationId = getCombinationId(request.query.couple1, request.query.couple2);
    const stats = await getCombinationStats(combinationId);
    response.json({ stats });
  } catch (error) {
    response.status(500).json({ error: error.message });
  }
});

app.listen(port, function () {
  process.stdout.write(`ASAW server is listening on port ${port}\n`);
});
<|endoftext|>


<commit_before>var GUI = GUI || {};

/**
 *  start the application by closing this start button
 *  @param {function} callback
 */
GUI.StartButton = function(callback){
	this.element = $("
", {"class" : "StartButton"})
		.appendTo("#Container");
	this.button = $("<button>")
		.button({label: "\u25B6"})
		.click(this.buttonClicked.bind(this))
		.appendTo(this.element);
	this.callback = callback;
};

GUI.StartButton.prototype.buttonClicked = function(){
	this.element.fadeTo(500, 0, function(){
		$(this).remove();
	});
	this.callback();
};

/**
 *  a start button for mobile browsers which require a touchstart event
 *  to start the audio
 */
GUI.MobileStart = function(callback){
	if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
		this.element = $("
", {"class" : "StartButton"})
			.appendTo("#Container");
		this.button = $("<button>")
			.button({label: "\u25B6"})
			.click(this.buttonClicked.bind(this))
			.appendTo(this.element);
		this.callback = callback;
		//also make the explanation collapsed
		$("#Explanation").on("touchstart", function(){
			if ($(this).hasClass("Collapsed")){
				$(this).removeClass("Collapsed");
			} else {
				$(this).addClass("Collapsed");
			}
		});
	}
};

GUI.MobileStart.prototype.buttonClicked = function(){
	this.element.fadeTo(500, 0, function(){
		$(this).remove();
	});
	this.callback();
};

/**
 *  Tone.Envelope GUI
 *  @param {jQuery} container the jQuery object to put the gui in
 *  @param {Tone.Envelope} envelope  the envelope object
 */
GUI.Envelope = function(container, envelope, title){
	this.envelope = envelope;
	this.element = $("
", {"class" : "Envelope"})
		.appendTo(container);
	this.title = $("
", {"id" : "Title"})
		.appendTo(this.element)
		.text(title);
	this.attack = this.makeSlider("attack", 0.01, 0.3, "A");
	this.decay = this.makeSlider("decay", 0.01, 0.4, "D");
	this.sustain = this.makeSlider("sustain", 0, 1, "S");
	this.release = this.makeSlider("release", 0.2, 2, "R");
	this.render();
};

GUI.Envelope.prototype.render = function(){
	this.attack.slider({"value" : this.envelope.attack * 1000});
	this.decay.slider({"value" : this.envelope.decay * 1000});
	this.sustain.slider({"value" : this.envelope.sustain * 1000});
	this.release.slider({"value" : this.envelope.release * 1000});

};

GUI.Envelope.prototype.makeSlider = function(attr, min, max, name){
	var self = this;
	var startVal = this.envelope[attr]*1000;
	var slider = $("
", {"class" : "EnvelopeSlider"})
		.slider({
			orientation: "vertical",
			range: "min",
			min: min * 1000,
			max: max * 1000,
			value: startVal,
			slide: function(event, ui) {
				var settings = {};
				settings[attr] = ui.value / 1000;
				self.envelope.set(settings);
				label.text(settings[attr].toFixed(3));
			},
			change : function(e, ui){
				var settings = {};
				settings[attr] = ui.value / 1000;
				label.text(settings[attr].toFixed(3));
			}
		})
		.appendTo(this.element);
	var label = $("
", {"class" : "Label Bottom"})
		.text(startVal / 1000)
		.appendTo(slider);
	$("
", {"class" : "Label Top"})
		.text(name)
		.appendTo(slider);
	return slider;
};

/**
 *  invoke the callback on an update loop
 */
GUI.onupdate = function(callback){
	GUI._updateList.push(callback);
};

GUI._updateList = [];

GUI._update = function(){
	// requestAnimationFrame(GUI._update);
	setTimeout(GUI._update, 40);
	for (var i = GUI._updateList.length - 1; i >= 0; i--) {
		GUI._updateList[i]();
	}
};

//start it off
GUI._update();

/**
 *  Tone.Meter GUI
 */
GUI.LevelMeter = function(container, meter){
	this.element = $("
", {"class" : "LevelMeter"})
		.appendTo(container);
	this.meter = meter;
	this.channels = [];
	for (var i = 0; i < this.meter.channels; i++) {
		this.channels[i] = new GUI.LevelMeter.Channel(this.element, meter, i);
	}
	if (this.meter.channels === 2){
		this.channels[0].setStereo(0);
		this.channels[1].setStereo(1);
	} else {
		this.channels[0].setMono();
	}
};

/**
 *  a single channel of a level meter
 */
GUI.LevelMeter.Channel = function(container, meter, channelNumber){
	this.element = $("
", {"class" : "LevelMeterChannel"})
		.appendTo(container);
	this.background = $("
", {"id" : "Background"})
		.appendTo(this.element);
	this.level = $("
", {"id" : "Level"})
		.appendTo(this.background);
	this.clip = $("
", {"id" : "Clip"})
		.appendTo(this.element);
	this.meter = meter;
	this.channelNumber = channelNumber;
	GUI.onupdate(this.update.bind(this));
};

GUI.LevelMeter.Channel.prototype.update = function(){
	var height = Math.max(Math.min(Math.abs(this.meter.getDb(this.channelNumber)), 100), 0);
	this.level.height(height.toFixed(2) + "%");
	if(this.meter.isClipped()){
		this.clip.css({
			"opacity" : 1
		});
	} else {
		this.clip.css({
			"opacity" : 0
		});
	}
};

GUI.LevelMeter.Channel.prototype.setStereo = function(channel){
	if (channel === 0){
		this.element.addClass("Left");
	} else if (channel === 1){
		this.element.addClass("Right");
	}
};

GUI.LevelMeter.Channel.prototype.setMono = function(){
	this.element.addClass("Mono");
};

/**
 *  shows values
 */
GUI.Value = function(container, initial, label, units){
	this.element = $("
", {"class" : "Value"})
		.appendTo(container);
	this.label = $("
", {"id" : "Label"})
		.appendTo(this.element)
		.text(label);
	this.value = $("
", {"id" : "Value"})
		.appendTo(this.element);
	this.units = units || "";
	this.setValue(initial);
};

GUI.Value.prototype.setValue = function(val){
	if (typeof val === "number"){
		val = val.toFixed(2);
	}
	this.value.text(val + " " + this.units);
};

/**
 *  Tone.Meter GUI but for displaying meter values not levels
 */
GUI.ValueMeter = function(container, meter, label){
	this.meter = meter;
	this.element = $("
", {"class" : "ValueMeter"})
		.appendTo(container);
	this.value = new GUI.Value(this.element, 0, label);
	GUI.onupdate(this.update.bind(this));
};

GUI.ValueMeter.prototype.update = function(){
	this.value.setValue(this.meter.getValue().toFixed(2));
};

/**
 *  Top Bar with link to github page, menu with examples, and Master Meter
 *  @param {Tone} Tone a link to the Tone object
 */
GUI.TopBar = function(Tone){
	this.element = $("
", {"id" : "TopBar"})
		.appendTo("#Container");
	this.hompage = $("
", {"id" : "HomePage"})
		.appendTo(this.element)
		.append($("").attr("href", "https://github.com/TONEnoTONE/Tone.js").text("Tone.js"));
	this.meter = new Tone.Meter(2);
	Tone.Master.connect(this.meter);
	this.meterGUI = new GUI.LevelMeter(this.element, this.meter);
	this.makeDropDown();
	//and the mobile start button
	new GUI.MobileStart(Tone.startMobile);
};

GUI.TopBar.prototype.makeDropDown = function(){
	var fileName = window.location.pathname.split("/");
	fileName = fileName[fileName.length - 1];
	fileName = fileName.substr(0, fileName.indexOf("."));
	var restOfUrl = window.location.href.substr(0, window.location.href.indexOf(fileName));
	var dropdown = $("
", {"id" : "DropDown"})
		.appendTo(this.element);
	var list = $("<select>");
	for (var catName in ExampleList){
		var group = $("<optgroup>").attr("label", catName)
			.appendTo(list);
		var category = ExampleList[catName];
		for (var example in category){
			var option = $("<option>").attr("value", category[example])
				.appendTo(group)
				.text(example);
			if (category[example] === fileName){
				option.attr("selected", "selected");
			}
		}
	}
	// this.dropdown = list.
	list.appendTo(dropdown)
		.selectmenu({
			change: function( event, ui ) {
				window.location.href = restOfUrl + ui.item.value + ".html";
			},
			width : 160
		});
};

/**
 *  a start stop button
 */
GUI.Checkbox = function(container, callback, labelOff, labelOn){
	var checked = false;
	this.id = GUI.Checkbox._idCounter++;
	// var element = $("<input type='checkbox' id='noToneCheckbox"+this.id+"'>\
	// 	start")
	var element = $("
", {"class" : "Checkbox"})
		.appendTo(container)
		.text(labelOff)
		.button()
		.click(function(){
			checked = !checked;
			if (checked){
				element.addClass("pressed");
				element.button({
					"label" : labelOn
				});
			} else {
				element.removeClass("pressed");
				element.button({
					"label" : labelOff
				});
			}
			callback(checked);
		});
	this.element = element;
};

GUI.Checkbox._idCounter = 0;

GUI.Checkbox.prototype.enable = function() {
	this.element.button("enable");
};

GUI.Checkbox.prototype.disable = function() {
	this.element.button("disable");
};

GUI.Checkbox.prototype.check = function(bool){
	if (bool){
		this.element.addClass("pressed");
	} else {
		this.element.removeClass("pressed");
	}
};

GUI.Checkbox.prototype.isChecked = function(){
	return this.element.hasClass("pressed");
};

/**
 *  a start stop button
 */
GUI.Momentary = function(container, callback, labelOff, labelOn){
	var element = $("
", {"class" : "Momentary"})
		.text(labelOff)
		.button()
		.appendTo(container)
		.on("mousedown touchstart", function(){
			element.button({
				"label" : labelOn
			});
			callback(true);
		})
		.on("mouseup touchend mouseout", function(){
			element.button({
				"label" : labelOff
			});
			callback(false);
		});
	this.element = element;
};

/**
 *  A DROPDOWN MENU
 */
GUI.DropDown = function(container, options, callback){
	this.element = $("
", {"class" : "DropDown"})
		.appendTo(container);
	this.list = $("<select>");
	for (var i = 0; i < options.length; i++) {
		var optionName = options[i];
		$("<option>").attr("value", optionName)
			.appendTo(this.list)
			.text(optionName);
	}
	// this.dropdown = list.
	this.list.appendTo(this.element)
		.selectmenu({
			change: function( event, ui ) {
				callback(ui.item.value);
			}
		});
};

GUI.DropDown.prototype.select = function(option){
	this.element.find('option[value="'+option+'"]')[0].selected = true
	this.list.selectmenu("refresh");
};

/**
 *  OSCILLATOR
 */
GUI.Oscillator = function(container, oscillator, label){
	this.element = $("
", {"class" : "Oscillator"})
		.appendTo(container);
	this.oscillator = oscillator;
	this.label = $("
", {"id" : "Label"})
		.appendTo(this.element)
		.text(label);
	this.type = new GUI.DropDown(this.element, ["sine", "square", "sawtooth", "triangle"], function(option){
		oscillator.setType(option);
	});
};

GUI.Oscillator.prototype.render = function(){
	var type = this.oscillator.getType();
	this.type.select(type);
};

/**
 *  SLIDER + VALUE
 */
GUI.Slider = function(container, callback, initial, label, units){
	this.element = $("
", {"class" : "Slider"})
		.appendTo(container);
	this.slider = $("
", {"id" : "Input"})
		.appendTo(this.element)
		.slider({
			"min" : 0,
			"max" : 1000,
			"slide" : this.onslide.bind(this),
			"change" : this.onslide.bind(this)
		});
	this.value = new GUI.Value(this.element, initial, label, units);
	this.callback = callback;
};

GUI.Slider.prototype.onslide = function(e, ui){
	var val = ui.value / 1000;
	var ret = this.callback(val);
	if (ret !== undefined){
		this.value.setValue(ret);
	} else {
		this.value.setValue(val);
	}
};

GUI.Slider.prototype.render = function(value){
	this.slider.slider({"value" : value * 1000});
};
<commit_msg>envelope has exponential slider.<commit_after>var GUI = GUI || {};

/**
 *  start the application by closing this start button
 *  @param {function} callback
 */
GUI.StartButton = function(callback){
	this.element = $("
", {"class" : "StartButton"})
		.appendTo("#Container");
	this.button = $("<button>")
		.button({label: "\u25B6"})
		.click(this.buttonClicked.bind(this))
		.appendTo(this.element);
	this.callback = callback;
};

GUI.StartButton.prototype.buttonClicked = function(){
	this.element.fadeTo(500, 0, function(){
		$(this).remove();
	});
	this.callback();
};

/**
 *  a start button for mobile browsers which require a touchstart event
 *  to start the audio
 */
GUI.MobileStart = function(callback){
	if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
		this.element = $("
", {"class" : "StartButton"})
			.appendTo("#Container");
		this.button = $("<button>")
			.button({label: "\u25B6"})
			.click(this.buttonClicked.bind(this))
			.appendTo(this.element);
		this.callback = callback;
		//also make the explanation collapsed
		$("#Explanation").on("touchstart", function(){
			if ($(this).hasClass("Collapsed")){
				$(this).removeClass("Collapsed");
			} else {
				$(this).addClass("Collapsed");
			}
		});
	}
};

GUI.MobileStart.prototype.buttonClicked = function(){
	this.element.fadeTo(500, 0, function(){
		$(this).remove();
	});
	this.callback();
};

/**
 *  Tone.Envelope GUI
 *  @param {jQuery} container the jQuery object to put the gui in
 *  @param {Tone.Envelope} envelope  the envelope object
 */
GUI.Envelope = function(container, envelope, title){
	this.envelope = envelope;
	this.element = $("
", {"class" : "Envelope"})
		.appendTo(container);
	this.title = $("
", {"id" : "Title"})
		.appendTo(this.element)
		.text(title);
	this.attack = this.makeSlider("attack", 0.01, 1, "A");
	this.decay = this.makeSlider("decay", 0.01, 1, "D");
	this.sustain = this.makeSlider("sustain", 0, 1, "S");
	this.release = this.makeSlider("release", 0.2, 4, "R");
	this.render();
};

GUI.Envelope.prototype.render = function(){
	this.attack.slider({"value" : this.envelope.attack * 1000});
	this.decay.slider({"value" : this.envelope.decay * 1000});
	this.sustain.slider({"value" : this.envelope.sustain * 1000});
	this.release.slider({"value" : this.envelope.release * 1000});

};

GUI.Envelope.prototype.makeSlider = function(attr, min, max, name){
	var self = this;
	var startVal = this.envelope[attr]*1000;

	var envelope = this.envelope;

	//slider function
	function logSliderValue(val){
		var logged = Math.pow(val / 1000, 2);
		return envelope.interpolate(logged, min, max);
	}

	var slider = $("
", {"class" : "EnvelopeSlider"})
		.slider({
			orientation: "vertical",
			range: "min",
			min: 0,
			max: 1000,
			value: startVal,
			slide: function(event, ui) {
				var settings = {};
				settings[attr] = logSliderValue(ui.value);
				self.envelope.set(settings);
				label.text(settings[attr].toFixed(3));
			},
			change : function(e, ui){
				var settings = {};
				settings[attr] = logSliderValue(ui.value);
				label.text(settings[attr].toFixed(3));
			}
		})
		.appendTo(this.element);
	var label = $("
", {"class" : "Label Bottom"})
		.text(startVal / 1000)
		.appendTo(slider);
	$("
", {"class" : "Label Top"})
		.text(name)
		.appendTo(slider);
	return slider;
};

/**
 *  invoke the callback on an update loop
 */
GUI.onupdate = function(callback){
	GUI._updateList.push(callback);
};

GUI._updateList = [];

GUI._update = function(){
	// requestAnimationFrame(GUI._update);
	setTimeout(GUI._update, 40);
	for (var i = GUI._updateList.length - 1; i >= 0; i--) {
		GUI._updateList[i]();
	}
};

//start it off
GUI._update();

/**
 *  Tone.Meter GUI
 */
GUI.LevelMeter = function(container, meter){
	this.element = $("
", {"class" : "LevelMeter"})
		.appendTo(container);
	this.meter = meter;
	this.channels = [];
	for (var i = 0; i < this.meter.channels; i++) {
		this.channels[i] = new GUI.LevelMeter.Channel(this.element, meter, i);
	}
	if (this.meter.channels === 2){
		this.channels[0].setStereo(0);
		this.channels[1].setStereo(1);
	} else {
		this.channels[0].setMono();
	}
};

/**
 *  a single channel of a level meter
 */
GUI.LevelMeter.Channel = function(container, meter, channelNumber){
	this.element = $("
", {"class" : "LevelMeterChannel"})
		.appendTo(container);
	this.background = $("
", {"id" : "Background"})
		.appendTo(this.element);
	this.level = $("
", {"id" : "Level"})
		.appendTo(this.background);
	this.clip = $("
", {"id" : "Clip"})
		.appendTo(this.element);
	this.meter = meter;
	this.channelNumber = channelNumber;
	GUI.onupdate(this.update.bind(this));
};

GUI.LevelMeter.Channel.prototype.update = function(){
	var height = Math.max(Math.min(Math.abs(this.meter.getDb(this.channelNumber)), 100), 0);
	this.level.height(height.toFixed(2) + "%");
	if(this.meter.isClipped()){
		this.clip.css({
			"opacity" : 1
		});
	} else {
		this.clip.css({
			"opacity" : 0
		});
	}
};

GUI.LevelMeter.Channel.prototype.setStereo = function(channel){
	if (channel === 0){
		this.element.addClass("Left");
	} else if (channel === 1){
		this.element.addClass("Right");
	}
};

GUI.LevelMeter.Channel.prototype.setMono = function(){
	this.element.addClass("Mono");
};

/**
 *  shows values
 */
GUI.Value = function(container, initial, label, units){
	this.element = $("
", {"class" : "Value"})
		.appendTo(container);
	this.label = $("
", {"id" : "Label"})
		.appendTo(this.element)
		.text(label);
	this.value = $("
", {"id" : "Value"})
		.appendTo(this.element);
	this.units = units || "";
	this.setValue(initial);
};

GUI.Value.prototype.setValue = function(val){
	if (typeof val === "number"){
		val = val.toFixed(2);
	}
	this.value.text(val + " " + this.units);
};

/**
 *  Tone.Meter GUI but for displaying meter values not levels
 */
GUI.ValueMeter = function(container, meter, label){
	this.meter = meter;
	this.element = $("
", {"class" : "ValueMeter"})
		.appendTo(container);
	this.value = new GUI.Value(this.element, 0, label);
	GUI.onupdate(this.update.bind(this));
};

GUI.ValueMeter.prototype.update = function(){
	this.value.setValue(this.meter.getValue().toFixed(2));
};

/**
 *  Top Bar with link to github page, menu with examples, and Master Meter
 *  @param {Tone} Tone a link to the Tone object
 */
GUI.TopBar = function(Tone){
	this.element = $("
", {"id" : "TopBar"})
		.appendTo("#Container");
	this.hompage = $("
", {"id" : "HomePage"})
		.appendTo(this.element)
		.append($("").attr("href", "https://github.com/TONEnoTONE/Tone.js").text("Tone.js"));
	this.meter = new Tone.Meter(2);
	Tone.Master.connect(this.meter);
	this.meterGUI = new GUI.LevelMeter(this.element, this.meter);
	this.makeDropDown();
	//and the mobile start button
	new GUI.MobileStart(Tone.startMobile);
};

GUI.TopBar.prototype.makeDropDown = function(){
	var fileName = window.location.pathname.split("/");
	fileName = fileName[fileName.length - 1];
	fileName = fileName.substr(0, fileName.indexOf("."));
	var restOfUrl = window.location.href.substr(0, window.location.href.indexOf(fileName));
	var dropdown = $("
", {"id" : "DropDown"})
		.appendTo(this.element);
	var list = $("<select>");
	for (var catName in ExampleList){
		var group = $("<optgroup>").attr("label", catName)
			.appendTo(list);
		var category = ExampleList[catName];
		for (var example in category){
			var option = $("<option>").attr("value", category[example])
				.appendTo(group)
				.text(example);
			if (category[example] === fileName){
				option.attr("selected", "selected");
			}
		}
	}
	// this.dropdown = list.
	list.appendTo(dropdown)
		.selectmenu({
			change: function( event, ui ) {
				window.location.href = restOfUrl + ui.item.value + ".html";
			},
			width : 160
		});
};

/**
 *  a start stop button
 */
GUI.Checkbox = function(container, callback, labelOff, labelOn){
	var checked = false;
	this.id = GUI.Checkbox._idCounter++;
	// var element = $("<input type='checkbox' id='noToneCheckbox"+this.id+"'>\
	// 	start")
	var element = $("
", {"class" : "Checkbox"})
		.appendTo(container)
		.text(labelOff)
		.button()
		.click(function(){
			checked = !checked;
			if (checked){
				element.addClass("pressed");
				element.button({
					"label" : labelOn
				});
			} else {
				element.removeClass("pressed");
				element.button({
					"label" : labelOff
				});
			}
			callback(checked);
		});
	this.element = element;
};

GUI.Checkbox._idCounter = 0;

GUI.Checkbox.prototype.enable = function() {
	this.element.button("enable");
};

GUI.Checkbox.prototype.disable = function() {
	this.element.button("disable");
};

GUI.Checkbox.prototype.check = function(bool){
	if (bool){
		this.element.addClass("pressed");
	} else {
		this.element.removeClass("pressed");
	}
};

GUI.Checkbox.prototype.isChecked = function(){
	return this.element.hasClass("pressed");
};

/**
 *  a start stop button
 */
GUI.Momentary = function(container, callback, labelOff, labelOn){
	var element = $("
", {"class" : "Momentary"})
		.text(labelOff)
		.button()
		.appendTo(container)
		.on("mousedown touchstart", function(){
			element.button({
				"label" : labelOn
			});
			callback(true);
		})
		.on("mouseup touchend mouseout", function(){
			element.button({
				"label" : labelOff
			});
			callback(false);
		});
	this.element = element;
};

/**
 *  A DROPDOWN MENU
 */
GUI.DropDown = function(container, options, callback){
	this.element = $("
", {"class" : "DropDown"})
		.appendTo(container);
	this.list = $("<select>");
	for (var i = 0; i < options.length; i++) {
		var optionName = options[i];
		$("<option>").attr("value", optionName)
			.appendTo(this.list)
			.text(optionName);
	}
	// this.dropdown = list.
	this.list.appendTo(this.element)
		.selectmenu({
			change: function( event, ui ) {
				callback(ui.item.value);
			}
		});
};

GUI.DropDown.prototype.select = function(option){
	this.element.find('option[value="'+option+'"]')[0].selected = true
	this.list.selectmenu("refresh");
};

/**
 *  OSCILLATOR
 */
GUI.Oscillator = function(container, oscillator, label){
	this.element = $("
", {"class" : "Oscillator"})
		.appendTo(container);
	this.oscillator = oscillator;
	this.label = $("
", {"id" : "Label"})
		.appendTo(this.element)
		.text(label);
	this.type = new GUI.DropDown(this.element, ["sine", "square", "sawtooth", "triangle"], function(option){
		oscillator.setType(option);
	});
};

GUI.Oscillator.prototype.render = function(){
	var type = this.oscillator.getType();
	this.type.select(type);
};

/**
 *  SLIDER + VALUE
 */
GUI.Slider = function(container, callback, initial, label, units){
	this.element = $("
", {"class" : "Slider"})
		.appendTo(container);
	this.slider = $("
", {"id" : "Input"})
		.appendTo(this.element)
		.slider({
			"min" : 0,
			"max" : 1000,
			"slide" : this.onslide.bind(this),
			"change" : this.onslide.bind(this)
		});
	this.value = new GUI.Value(this.element, initial, label, units);
	this.callback = callback;
};

GUI.Slider.prototype.onslide = function(e, ui){
	var val = ui.value / 1000;
	var ret = this.callback(val);
	if (ret !== undefined){
		this.value.setValue(ret);
	} else {
		this.value.setValue(val);
	}
};

GUI.Slider.prototype.render = function(value){
	this.slider.slider({"value" : value * 1000});
};
<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');

var app = express();

var publicPath = path.resolve('../client/public');

app.use(express.static(publicPath));
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
	res.set('Access-Control-Allow-Origin', 'http://localhost');
	res.set('Access-Control-Allow-Credentials', true);
	res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT');
	res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
	if (req.method === 'OPTIONS') {
		return res.send(200);
	} else {
		next();
	}
});

app.all('/*', function (req, res) {
	res.sendFile(publicPath + '/index.html');
});

var server = app.listen(3000, function () {
	var host = server.address().address;
	var port = server.address().port;

	console.log('Kidoikoiaki app listening at http://%s:%s', host, port);
});
<commit_msg>Update server.js<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');

var app = express();

var publicPath = path.resolve('../client/public');

app.use(express.static(publicPath));
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
	res.set('Access-Control-Allow-Origin', 'http://localhost');
	res.set('Access-Control-Allow-Credentials', true);
	res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT');
	res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
	if (req.method === 'OPTIONS') {
		return res.send(200);
	} else {
		next();
	}
});

app.all('/*', function (req, res) {
	res.sendFile(publicPath + '/index.html');
});

var server = app.listen(3000, function () {
	var host = server.address().address;
	var port = server.address().port;

	console.log('App listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var requireDir = require('require-dir');
var swig = require('swig');
var mongoose = require('mongoose');

var socketCount = 0;

var config = require('./config.js');

server.listen(process.env.PORT || config.port || 3000);

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
};

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(allowCrossDomain);
app.use(cookieParser());
app.use(app.router);

app.use('/jspm_packages', express.static(__dirname + '/../jspm_packages'));
app.use('/client', express.static(__dirname + '/../client'));
app.use('/assets', express.static(__dirname + '/../assets'));

app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', path.join(__dirname, 'views'));

io.on('connection', function(socket) {
    socketCount++;
    console.log('A user connected.');

    socket.on('disconnect', function() {
        socketCount--;
    });
});<commit_msg>fix(server): renaming import variables<commit_after>var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var requireDir = require('require-dir');
var swig = require('swig');
var mongoose = require('mongoose');

var socketCount = 0;

var config = require('./config.js');

server.listen(process.env.PORT || config.port || 3000);

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
};

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(allowCrossDomain);
app.use(cookieParser());
app.use(app.router);

app.use('/jspm_packages', express.static(__dirname + '/../jspm_packages'));
app.use('/client', express.static(__dirname + '/../client'));
app.use('/assets', express.static(__dirname + '/../assets'));

app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', path.join(__dirname, 'views'));

io.on('connection', function(socket) {
    socketCount++;
    console.log('A user connected.');

    socket.on('disconnect', function() {
        socketCount--;
    });
});<|endoftext|>


<commit_before>Meteor.methods({
	/* numVert: number of vertices
	 * vertices: array of vertices
	 * current: current location
	 *
	 * Determines if a given Point is located within a polygon of n vertices
	 * Algorithm from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */
	pointIncluded: function(vertices, current) {
		included = false;
		numVert = vertices.length;

		// create arrays of the x and y coordinates of the polygon
		var xArray = [];
		for (var i = 0; i < numVert; i++) {
			xArray.push(vertices[i].x);
		}

		var yArray = [];
		for (var i = 0; i < numVert; i++) {
			yArray.push(vertices[i].y);
		}

		for (var i = 0, j = numVert - 1; i < numVert; j = i++) {
			if ((yArray[i] >= current.y) != (yArray[j] >= current.y) &&
				(current.x <= (xArray[j] - xArray[i]) *
					(current.y - yArray[i]) / (yArray[j] - yArray[i]) +
					xArray[i])
				) {
				included = !included;

			}
		}

		return included;
	},

	/* Search through all locations to see where you are */
	searchLocations: function(current) {
		location = null;
		locatedHere = null;

		for (var i = 0; i < Locations.find().count(); i++) {
			// if the given Point is in the location, return the location
			Meteor.call("pointIncluded",Locations.find().fetch()[i].coordinates.coordinates[0],current,
				function(error, data) {
					if (error) {
						console.log(error);
					}
					else {
						locatedHere = data;
					}
			});

			if (locatedHere) {
				location = [Locations.find().fetch()[i], "in"];
				break;
			}

		}

		// call getNearest
		// pass current
		//console.log(locatedHere);
		if (!locatedHere) {
			Meteor.call("getNearest",
				current,
				function (error, data) {
					if (error) {
						console.log(error);
					}
					else {
						//console.log("got the nearest location: " + data.name);
						location = [data[0], "near", data[1]];

					}
				});
		}

		return location;
	},

	getNearest: function(location) {
		var nearestPoint = Intersections.find({
			coordinate:{
				$near: {
					$geometry: {
						type: "Point" ,
						coordinates: [ location.y , location.x ]
					},
					$maxDistance: 0,
					$minDistance: 100
				}
			}
		});
		console.log(nearestPoint[0]);

		var theNearest = nearestPoint[0];
		var theNearestDistance = 0;
		Meteor.call("distance",
			location,
			theNearest.coordinate.coordinates,
			function(error,data) {
				if (error) {
					console.log(error);
				}
				else {
					theNearestDistance = data;
					if (theNearestDistance < 1000000) {
						return [theNearest,theNearestDistance];
					}
					else {
						console.log("You are off campus");
						return;
					}
				}
			}
		);

		// hold the current iteration
		// nearLocationDistance is the distance to the point
		// nearLocation is the object itself containing a point and a name
		// previousClosest is the previous nearestLocation
		// previousClosestDistance is the previous location's distance

		// theNearest
		// theNearestDistance

		// previousClosest = points[0];
		// previousClosestDistance = 1000000000000;
		// theNearestDistance = 100000000000;

		// for (var i = 0; i < points.length; i++) {
		// 	//console.log(JSON.stringify(location)+JSON.stringify(points[i]));
		// 	Meteor.call("distance",
		// 		location,
		// 		points[i].point,
		// 		function(error,data) {
		// 			if (error) {
		// 				console.log(error);
		// 			}
		// 			else {
		// 				//console.log(data);
		// 				nearLocationDistance = data;
		// 			}
		// 		}
		// 		);
		// 	nearLocation = points[i];
		// 	//console.log(nearLocationDistance + "<" + theNearestDistance);
		// 	if (nearLocationDistance < theNearestDistance) {
		// 		theNearest = nearLocation;
		// 		theNearestDistance = nearLocationDistance;
		// 	}
		// 	previousClosest = nearLocation;
		// 	previousClosestDistance = nearLocationDistance;
		// }
		// //console.log("nearest distance location:" + theNearestDistance + JSON.stringify(theNearest));
		// if (theNearestDistance < 10000000) {
		// 	// console.log(JSON.stringify(theNearest));
		// 	return [theNearest,theNearestDistance];
		// }
		// else {
		// 	console.log("You are off campus.");
		// 	return;
		// }

	},

	/* returns the distance between two points
	* adapted from http://www.movable-type.co.uk/scripts/latlong.html */
	distance: function(start, end) {
		//console.log(JSON.stringify(start)+JSON.stringify(end));
		var R = 6371000; // metres
		//console.log(start.point+end.point);

		var lat1 = start[0];
		var lat2 = end[0];
		var lon1 = start[1];
		var lon2 = end[1];

		var p1 = lat1 * (Math.PI / 180);
		var p2 = lat2 * (Math.PI / 180);
		var dp = (lat2-lat1) * (Math.PI / 180);
		var dl = (lon2-lon1) * (Math.PI / 180);

		var a = Math.sin(dp/2) * Math.sin(dp/2) +
		        Math.cos(p1) * Math.cos(p2) *
		        Math.sin(dl/2) * Math.sin(dl/2);
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

		var d = R * c;
		//console.log(d);

		return d;
	}

});<commit_msg>trace nearestPoint<commit_after>Meteor.methods({
	/* numVert: number of vertices
	 * vertices: array of vertices
	 * current: current location
	 *
	 * Determines if a given Point is located within a polygon of n vertices
	 * Algorithm from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */
	pointIncluded: function(vertices, current) {
		included = false;
		numVert = vertices.length;

		// create arrays of the x and y coordinates of the polygon
		var xArray = [];
		for (var i = 0; i < numVert; i++) {
			xArray.push(vertices[i].x);
		}

		var yArray = [];
		for (var i = 0; i < numVert; i++) {
			yArray.push(vertices[i].y);
		}

		for (var i = 0, j = numVert - 1; i < numVert; j = i++) {
			if ((yArray[i] >= current.y) != (yArray[j] >= current.y) &&
				(current.x <= (xArray[j] - xArray[i]) *
					(current.y - yArray[i]) / (yArray[j] - yArray[i]) +
					xArray[i])
				) {
				included = !included;

			}
		}

		return included;
	},

	/* Search through all locations to see where you are */
	searchLocations: function(current) {
		location = null;
		locatedHere = null;

		for (var i = 0; i < Locations.find().count(); i++) {
			// if the given Point is in the location, return the location
			Meteor.call("pointIncluded",Locations.find().fetch()[i].coordinates.coordinates[0],current,
				function(error, data) {
					if (error) {
						console.log(error);
					}
					else {
						locatedHere = data;
					}
			});

			if (locatedHere) {
				location = [Locations.find().fetch()[i], "in"];
				break;
			}

		}

		// call getNearest
		// pass current
		//console.log(locatedHere);
		if (!locatedHere) {
			Meteor.call("getNearest",
				current,
				function (error, data) {
					if (error) {
						console.log(error);
					}
					else {
						//console.log("got the nearest location: " + data.name);
						location = [data[0], "near", data[1]];

					}
				});
		}

		return location;
	},

	getNearest: function(location) {
		var nearestPoint = Intersections.find({
			coordinate:{
				$near: {
					$geometry: {
						type: "Point" ,
						coordinates: [ location.y , location.x ]
					},
					$maxDistance: 0,
					$minDistance: 10000
				}
			}
		});
		console.log(nearestPoint);

		var theNearest = nearestPoint[0];
		var theNearestDistance = 0;
		Meteor.call("distance",
			location,
			theNearest.coordinate.coordinates,
			function(error,data) {
				if (error) {
					console.log(error);
				}
				else {
					theNearestDistance = data;
					if (theNearestDistance < 1000000) {
						return [theNearest,theNearestDistance];
					}
					else {
						console.log("You are off campus");
						return;
					}
				}
			}
		);

		// hold the current iteration
		// nearLocationDistance is the distance to the point
		// nearLocation is the object itself containing a point and a name
		// previousClosest is the previous nearestLocation
		// previousClosestDistance is the previous location's distance

		// theNearest
		// theNearestDistance

		// previousClosest = points[0];
		// previousClosestDistance = 1000000000000;
		// theNearestDistance = 100000000000;

		// for (var i = 0; i < points.length; i++) {
		// 	//console.log(JSON.stringify(location)+JSON.stringify(points[i]));
		// 	Meteor.call("distance",
		// 		location,
		// 		points[i].point,
		// 		function(error,data) {
		// 			if (error) {
		// 				console.log(error);
		// 			}
		// 			else {
		// 				//console.log(data);
		// 				nearLocationDistance = data;
		// 			}
		// 		}
		// 		);
		// 	nearLocation = points[i];
		// 	//console.log(nearLocationDistance + "<" + theNearestDistance);
		// 	if (nearLocationDistance < theNearestDistance) {
		// 		theNearest = nearLocation;
		// 		theNearestDistance = nearLocationDistance;
		// 	}
		// 	previousClosest = nearLocation;
		// 	previousClosestDistance = nearLocationDistance;
		// }
		// //console.log("nearest distance location:" + theNearestDistance + JSON.stringify(theNearest));
		// if (theNearestDistance < 10000000) {
		// 	// console.log(JSON.stringify(theNearest));
		// 	return [theNearest,theNearestDistance];
		// }
		// else {
		// 	console.log("You are off campus.");
		// 	return;
		// }

	},

	/* returns the distance between two points
	* adapted from http://www.movable-type.co.uk/scripts/latlong.html */
	distance: function(start, end) {
		//console.log(JSON.stringify(start)+JSON.stringify(end));
		var R = 6371000; // metres
		//console.log(start.point+end.point);

		var lat1 = start[0];
		var lat2 = end[0];
		var lon1 = start[1];
		var lon2 = end[1];

		var p1 = lat1 * (Math.PI / 180);
		var p2 = lat2 * (Math.PI / 180);
		var dp = (lat2-lat1) * (Math.PI / 180);
		var dl = (lon2-lon1) * (Math.PI / 180);

		var a = Math.sin(dp/2) * Math.sin(dp/2) +
		        Math.cos(p1) * Math.cos(p2) *
		        Math.sin(dl/2) * Math.sin(dl/2);
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

		var d = R * c;
		//console.log(d);

		return d;
	}

});<|endoftext|>


<commit_before>var http = require('http'),
    fs = require('fs'),
    index = fs.readFileSync(__dirname + '/../index.html');

var app = http.createServer(function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(index);
});

// Socket.io server listens to our app
var io = require('socket.io').listen(app);
var port = 3000;

// TODO(jose): extract protocols to general config file for server and client
var clients = require('./clients');
var rooms = require('./rooms');
var log = require('minilog');

// Socket impacts our server
io.sockets.on('connection', function(socket) {

    // Welcome our client
    // TODO(jose): protocol for clients
    // NOTE(jose): Are we fully sharing structs server/client?
    socket.user = clients.create('unknown player');
    socket.emit('server_join', socket.user);

    // NOTE(jose): Temporal logic for first iterations
    var test_room = rooms.get(1);
    if (test_room == undefined) {
        rooms.create(io, socket, 'test room');
    }

    // client disconnect
    socket.on('disconnect', function() {
        rooms.disconnect(io, socket);
    });

    // client joins room
    socket.on('room_join', function(data) {
        if (socket.room == undefined) {
            rooms.join(io, socket, rooms.get(data.id));
        }
    });

    // client leaves room
    socket.on('room_leave', function(data) {
        rooms.leave(io, socket);
    });

    // Game in progress
    socket.on('room_message', function(action, data) {
        var room = socket.room;
        switch(action) {
        case 'game_start':
            io.to(room.id).emit('room_message', action, data);
            break;
        case 'game_inputs':
            io.to(room.id).emit('room_message', action, data);
            break;
        case 'game_update':
            // TODO(jose): Simulate with inputs
            io.to(room.id).emit('room_message', action, data);
            break;
        }
        log().info('user ( ' + socket.user.id + ' ) sent message ( ' + action + ' ) to room ( ' + room.id + ' )');
    });
});

app.listen(port);
log().info('Server running ( port: ' + port + ' )');
<commit_msg>Avoid spamm on server.js about input/update messages<commit_after>var http = require('http'),
    fs = require('fs'),
    index = fs.readFileSync(__dirname + '/../index.html');

var app = http.createServer(function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(index);
});

// Socket.io server listens to our app
var io = require('socket.io').listen(app);
var port = 3000;

// TODO(jose): extract protocols to general config file for server and client
var clients = require('./clients');
var rooms = require('./rooms');
var log = require('minilog');

// Socket impacts our server
io.sockets.on('connection', function(socket) {

    // Welcome our client
    // TODO(jose): protocol for clients
    // NOTE(jose): Are we fully sharing structs server/client?
    socket.user = clients.create('unknown player');
    socket.emit('server_join', socket.user);

    // NOTE(jose): Temporal logic for first iterations
    var test_room = rooms.get(1);
    if (test_room == undefined) {
        rooms.create(io, socket, 'test room');
    }

    // client disconnect
    socket.on('disconnect', function() {
        rooms.disconnect(io, socket);
    });

    // client joins room
    socket.on('room_join', function(data) {
        if (socket.room == undefined) {
            rooms.join(io, socket, rooms.get(data.id));
        }
    });

    // client leaves room
    socket.on('room_leave', function(data) {
        rooms.leave(io, socket);
    });

    // Game in progress
    socket.on('room_message', function(action, data) {
        var room = socket.room;
        switch(action) {
        case 'game_start':
            io.to(room.id).emit('room_message', action, data);
            break;
        case 'game_inputs':
            io.to(room.id).emit('room_message', action, data);
            break;
        case 'game_update':
            // TODO(jose): Simulate with inputs
            io.to(room.id).emit('room_message', action, data);
            break;
        }
        // log().debug('user ( ' + socket.user.id + ' ) sent message ( ' + action + ' ) to room ( ' + room.id + ' )');
    });
});

app.listen(port);
log().info('Server running ( port: ' + port + ' )');
<|endoftext|>


<commit_before>const express = require('express');
const path = require('path');
const request = require('request');

const app = express();
const port = process.env.PORT || 8000;

app.use(express.static(path.join(__dirname, '../client')));

app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../client/index.html')));

/**
 * Function to return data from spotify API
 * @param  {string} url [url of spotify api endpoint]
 * @param  {object} res [response from api endpoint]
 * @param  {object} parameters [object of parameters]
 */
function getData(url, res, parameters) {
  request({
    url,
    qs: parameters,
  }, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      res.end(body);
    } else {
      console.log('API is returning an error, or status code is not 200');
      res.end('error');
    }
  });
}

/**
 * Route to get artist information
 * If route is invoked from search (no artistId), run first route
 * Otherwise, if route is invoked from clicking related artist,
 * Run second route with artistId for accuracy
 */
app.get('/artist', (req, res) => {
  var url;
  var parameters;
  if (req.query.artistId === 'none') {
    url = 'https://api.spotify.com/v1/search';
    parameters = { query: req.query.artist, type: 'artist' };
  } else {
    url = `https://api.spotify.com/v1/artists/${req.query.artistId}`;
  }
  getData(url, res, parameters);
});

/**
 * Route to get artist's top ten tracks
 */
app.get('/tracks', (req, res) => {
  const url = `https://api.spotify.com/v1/artists/${req.query.artistId}/top-tracks?country=US`;
  const parameters = { country: 'US' };
  getData(url, res, parameters);
});

/**
 * Route to get artist's albums
 * It uses artistName instead of artistId because of better album results (no duplicates)
 */
app.get('/albums', (req, res) => {
  const url = 'https://api.spotify.com/v1/search';
  const parameters = { query: req.query.artistName, type: 'album', market: 'US', limit: '50' };
  getData(url, res, parameters);
});

/**
 * Route to get album tracks
 */
app.get('/albumTracks', (req, res) => {
  const url = `https://api.spotify.com/v1/albums/${req.query.albumId}/tracks`;
  getData(url, res);
});

/**
 * Route to get related artists
 */
app.get('/relatedArtists', (req, res) => {
  const url = `https://api.spotify.com/v1/artists/${req.query.artistId}/related-artists`;
  getData(url, res);
});

app.listen(port, () => console.log(`App is listening on port ${port}!`));
<commit_msg>(refactor) Change var to let, and added 'use strict'<commit_after>'use strict';
const express = require('express');
const path = require('path');
const request = require('request');

const app = express();
const port = process.env.PORT || 8000;

app.use(express.static(path.join(__dirname, '../client')));

app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../client/index.html')));

/**
 * Function to return data from spotify API
 * @param  {string} url [url of spotify api endpoint]
 * @param  {object} res [response from api endpoint]
 * @param  {object} parameters [object of parameters]
 */
function getData(url, res, parameters) {
  request({
    url,
    qs: parameters,
  }, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      res.end(body);
    } else {
      console.log('API is returning an error, or status code is not 200');
      res.end('error');
    }
  });
}

/**
 * Route to get artist information
 * If route is invoked from search (no artistId), run first route
 * Otherwise, if route is invoked from clicking related artist,
 * Run second route with artistId for accuracy
 */
app.get('/artist', (req, res) => {
  let url;
  let parameters;
  if (req.query.artistId === 'none') {
    url = 'https://api.spotify.com/v1/search';
    parameters = { query: req.query.artist, type: 'artist' };
  } else {
    url = `https://api.spotify.com/v1/artists/${req.query.artistId}`;
  }
  getData(url, res, parameters);
});

/**
 * Route to get artist's top ten tracks
 */
app.get('/tracks', (req, res) => {
  const url = `https://api.spotify.com/v1/artists/${req.query.artistId}/top-tracks?country=US`;
  const parameters = { country: 'US' };
  getData(url, res, parameters);
});

/**
 * Route to get artist's albums
 * It uses artistName instead of artistId because of better album results (no duplicates)
 */
app.get('/albums', (req, res) => {
  const url = 'https://api.spotify.com/v1/search';
  const parameters = { query: req.query.artistName, type: 'album', market: 'US', limit: '50' };
  getData(url, res, parameters);
});

/**
 * Route to get album tracks
 */
app.get('/albumTracks', (req, res) => {
  const url = `https://api.spotify.com/v1/albums/${req.query.albumId}/tracks`;
  getData(url, res);
});

/**
 * Route to get related artists
 */
app.get('/relatedArtists', (req, res) => {
  const url = `https://api.spotify.com/v1/artists/${req.query.artistId}/related-artists`;
  getData(url, res);
});

app.listen(port, () => console.log(`App is listening on port ${port}!`));
<|endoftext|>


<commit_before>var server;

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'POST');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

module.exports = {
    start: function (albumCache, updater, startedCallback) {
        var express = require("express");
        var bodyParser = require("body-parser");
        var app = express();

        const PORT=8079;

        app.use(bodyParser.json());
        app.use(allowCrossDomain);

        app.post("/v1/albums", function(request, res) {
            if(request.body.constructor !== Array)
            {
                res.status(400);
                res.send({ error: "Unable to parse request data" });
                return;
            }

            var uncached = albumCache.filterUncached(request.body);
            if(uncached.length > 0)
            {
                res.status(202);
                res.send({
                    error: "Tags not cached, try again later",
                    data: uncached
                });
                updater.queueTags(uncached);
                return;
            }

            var albums = albumCache
                .getAlbumsByTags(request.body)
                .slice(0, 50);

            res.setHeader("Content-Type", "application/json");
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.status(200);
            res.send(JSON.stringify(albums));
        });

        server = app.listen(PORT, function(){
            startedCallback();
        });
      },

    stop: function(stoppedCallback) {
        server.close(stoppedCallback);
    },
};<commit_msg>Added debug endpoint for reading total cached tagcount<commit_after>var server;

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'POST');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

module.exports = {
    start: function (albumCache, updater, startedCallback) {
        var express = require("express");
        var bodyParser = require("body-parser");
        var app = express();

        const PORT=8079;

        app.use(bodyParser.json());
        app.use(allowCrossDomain);

        app.post("/v1/albums", function(request, res) {
            if(request.body.constructor !== Array)
            {
                res.status(400);
                res.send({ error: "Unable to parse request data" });
                return;
            }

            var uncached = albumCache.filterUncached(request.body);
            if(uncached.length > 0)
            {
                res.status(202);
                res.send({
                    error: "Tags not cached, try again later",
                    data: uncached
                });
                updater.queueTags(uncached);
                return;
            }

            var albums = albumCache
                .getAlbumsByTags(request.body)
                .slice(0, 50);

            res.setHeader("Content-Type", "application/json");
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.status(200);
            res.send(JSON.stringify(albums));
        });

        app.get("/debug/tagcount", function(request, res) {
            res.status(200);
            res.send(JSON.stringify(Object.keys(albumCache.albums).length));
        });

        server = app.listen(PORT, function(){
            startedCallback();
        });
      },

    stop: function(stoppedCallback) {
        server.close(stoppedCallback);
    },
};<|endoftext|>


<commit_before>// Requirements
var http = require('http');
var express = require('express');
var ejs = require('ejs');
var path = require('path');
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var CollectionDriver = require('./collectionDriver').CollectionDriver;
var bodyParser = require('body-parser');
var sessions = require('client-sessions');
var app = express();

// Express settings
app.set('port', process.env.PORT || 8080);
app.use(express.static(path.join(__dirname, '../client')));
app.use(bodyParser.json());
app.set('views', __dirname + '/../client');
app.engine('html', ejs.renderFile);
app.set('view engine', 'html');

// Sets up our session variable definitions
app.use(sessions({
  cookieName: 'session',
  secret: 'random_string_goes_here',
  duration: 30 * 60 * 1000, // 30 minutes
  activeDuration: 5 * 60 * 1000, // 5 minutes
  ephemeral: true
}));

// Mongo settings
var mongoHost = '127.0.0.1';
var mongoPort = 27017;
var mongoDatabase = 'kanbosal';
var url = 'mongodb://' + mongoHost + ':' + mongoPort + '/' + mongoDatabase;

var collectionDriver;

/* Connects to our mongo database running at url. */
MongoClient.connect(url, function(error, db) {
      assert.equal(null, error);
      console.log("Connected correctly to mongodb server at database " + mongoDatabase + ".");

      collectionDriver = new CollectionDriver(db);
});

/* Checks if a user is in our session variable otherwise redirects to home page. */
var authenticate = function(req, res, next) {
    if (req.session.user)
        next();
    else
        res.redirect('/');
}

/* Checks if the user in session is an admin */
var authenticateAdmin = function(req, res, next) {
    if (req.session.user) {
        if (req.session.user.permissions.level == 1)
            next();
        else
            res.redirect('/');
    }
    else
        res.redirect('/');
}

/* Loads homepage. */
app.get('/', function(req, res) {
    res.render('index.html');
})

/* GET: find a user by email and set session variable. */
app.get('/login', function(req, res) {
    var email = req.query.email;

    if (email) {
        collectionDriver.getEmail(email, function(error, results) {
            if (error)
                res.status(400).send(error);
            else {
                req.session.user = results;
                res.json(results);
            }
        });
    }
    else
        res.status(400).send({error: 'bad url', url: req.url});
});

/* Deletes the current session variable and redirects to homepage. */
app.get('/logout', function(req, res) {
    req.session.reset();
    res.redirect('/');
});

/* Returns the current user stored in the session */
app.get('/currentUser', authenticate, function(req, res) {
    res.json(req.session.user);
});

/* Loads overview. */
app.get('/overview', authenticate, function(req, res) {
    res.render('overview.html');
});

/* GET: returns the grants the user can see. */
app.get('/getOverview', authenticate, function(req, res) {
    var userId = req.session.user._id;

    if (userId) {
        collectionDriver.getGrants(userId, function(error, results) {
            if (error)
                res.status(400).send(error);
            else {
                var overview = {
                    user: req.session.user,
                    grants: results
                };
                res.json(overview);
            }
        });
    }
    else
        res.status(400).send({error: 'bad user id'});
});

/* Loads detail. */
app.get('/detail', authenticate, function(req, res) {
    if (req.session.grantLoadId)
        res.render('detail.html');
    else
        res.redirect('/');
});

/* Sets the grant to load in the session. */
app.get('/detail/:id', authenticate, function(req, res) {
    req.session.grantLoadId = req.params.id;
    res.redirect('/detail');
});

/* GET: returns the cards belonging to the grant the user can see */
app.get('/getDetail', authenticate, function(req, res) {
    if (!req.session.grantLoadId)
        res.redirect('/overview');

    var userPermissionId = req.session.user.permissions.stage;
    var grantId = req.session.grantLoadId;

    collectionDriver.getCards(grantId, userPermissionId, function(error, results) {
        if (error)
            res.status(400).send(error);
        else{
            var detailView = {
                user: req.session.user,
                cards: results
            };
            res.json(detailView);
        }
    });
});

/* Loads admin */
app.get('/admin', function(req, res) {
    res.render('admin.html');
});

/* GET: returns users with specified stage permissions */
app.get('/manageUsers', function(req, res) {
    var query = req.query;

    if (query.hasOwnProperty('permissions.stage'))  // uri only reads string values
        query['permissions.stage'] = parseInt(query['permissions.stage'], 10);

    collectionDriver.getUsersByDept(query, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* GET: findAll of collection. or enter query to narrow down list*/
app.get('/:collection', function(req, res) {
    var collectionName = req.params.collection;

    collectionDriver.findAll(collectionName, function(error, results) {
        if (error)
            res.status(400).send(error);
        else {
            res.status(200).send(results);
        }
    });
});

/* GET: find id in collection. */
app.get('/:collection/:id', function(req, res) {
    var collection = req.params.collection;
    var id = req.params.id;

    if (id) {
        collectionDriver.get(collection, id, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.json(results);
        });
    }
    else
        res.status(400).send({error: 'bad url', url: req.url});
});

/* PUT: insert document in collection. */
app.put('/:collection', function(req, res) {
    var doc = req.body;
    var collection = req.params.collection;

    collectionDriver.save(collection, doc, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.json(results);
     });
});

/* Sets the stage of an admin to the desired stage they want to view */
app.post('/setAdminStage', authenticateAdmin, function(req, res) {
    var newStage = req.query.stage;

    if (newStage) {
        req.session.user.permissions.stage = newStage;
        res.status(200).send(true);
    }
    else
        res.status(400).send({error: 'bad query'})
});

/* Moves the card given from curCol to newCol */
app.post('/moveCard/:id', authenticate, function(req, res) {
    var card = {
        id: req.params.id,
        curStage: req.session.user.permissions.stage,
        curCol: req.query.curCol,
        newStage: req.session.user.permissions.stage,
        newCol: req.query.newCol
    };
    var grantId = req.session.grantLoadId;
    var userPermissionId = req.session.user.permissions.stage;

    collectionDriver.moveCard(grantId, card, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* Allows admins to move the card from the current stage to the next one */
app.post('/moveCardStage/:id', authenticateAdmin, function(req, res) {
    var card = {
        id: req.params.id,
        curStage: req.session.user.permissions.stage,
        curCol: "complete",
        newStage: req.session.user.permissions.stage + 1,
        newCol: "toDo"
    };
    var grantId = req.session.grantLoadId;
    var userPermissionId = req.session.user.permissions.stage;

    collectionDriver.moveCard(grantId, card, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* Updates the grant in session. */
app.post('/updateGrant', function(req, res) {
    var docUpdates = req.body;
    var grantId = req.session.grantLoadId;
    var userId = req.session.user._id;

    collectionDriver.update("grants", docUpdates, grantId, userId, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send("Updated grant " + grantId + " with " + results + ".");
    });
});

/* POST: updates a document with id in the collection. */
app.post('/:collection/:id', authenticate, function(req, res) {
    var userId = req.session.user._id;
    var docUpdates = req.body;
    var id = req.params.id;
    var collection = req.params.collection;

    if (id) {
        collectionDriver.update(collection, docUpdates, id, userId, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.status(200).send("Updated id " + id + " at collection " + collection + ".");
        });
    }
    else {
        var error = { "message" : "Cannot POST a whole collection" };
        res.status(400).send(error);
    }
});

/* DELETE: deletes a document with id in the collection. */
app.delete('/:collection/:id', function(req, res) {
    var id = req.params.id;
    var collection = req.params.collection;

    if (id) {
        collectionDriver.delete(collection, id, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.status(200).send(results);
        });
    } else {
        var error = { "message" : "Cannot DELETE a whole collection" };
        res.status(400).send(error);
   }
});

app.use(function (req,res) {
    res.render('404', {url: req.url});
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>Cleanup unused variables<commit_after>// Requirements
var http = require('http');
var express = require('express');
var ejs = require('ejs');
var path = require('path');
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var CollectionDriver = require('./collectionDriver').CollectionDriver;
var bodyParser = require('body-parser');
var sessions = require('client-sessions');
var app = express();

// Express settings
app.set('port', process.env.PORT || 8080);
app.use(express.static(path.join(__dirname, '../client')));
app.use(bodyParser.json());
app.set('views', __dirname + '/../client');
app.engine('html', ejs.renderFile);
app.set('view engine', 'html');

// Sets up our session variable definitions
app.use(sessions({
  cookieName: 'session',
  secret: 'random_string_goes_here',
  duration: 30 * 60 * 1000, // 30 minutes
  activeDuration: 5 * 60 * 1000, // 5 minutes
  ephemeral: true
}));

// Mongo settings
var mongoHost = '127.0.0.1';
var mongoPort = 27017;
var mongoDatabase = 'kanbosal';
var url = 'mongodb://' + mongoHost + ':' + mongoPort + '/' + mongoDatabase;

var collectionDriver;

/* Connects to our mongo database running at url. */
MongoClient.connect(url, function(error, db) {
      assert.equal(null, error);
      console.log("Connected correctly to mongodb server at database " + mongoDatabase + ".");

      collectionDriver = new CollectionDriver(db);
});

/* Checks if a user is in our session variable otherwise redirects to home page. */
var authenticate = function(req, res, next) {
    if (req.session.user)
        next();
    else
        res.redirect('/');
}

/* Checks if the user in session is an admin */
var authenticateAdmin = function(req, res, next) {
    if (req.session.user) {
        if (req.session.user.permissions.level == 1)
            next();
        else
            res.redirect('/');
    }
    else
        res.redirect('/');
}

/* Loads homepage. */
app.get('/', function(req, res) {
    res.render('index.html');
})

/* GET: find a user by email and set session variable. */
app.get('/login', function(req, res) {
    var email = req.query.email;

    if (email) {
        collectionDriver.getEmail(email, function(error, results) {
            if (error)
                res.status(400).send(error);
            else {
                req.session.user = results;
                res.json(results);
            }
        });
    }
    else
        res.status(400).send({error: 'bad url', url: req.url});
});

/* Deletes the current session variable and redirects to homepage. */
app.get('/logout', function(req, res) {
    req.session.reset();
    res.redirect('/');
});

/* Returns the current user stored in the session */
app.get('/currentUser', authenticate, function(req, res) {
    res.json(req.session.user);
});

/* Loads overview. */
app.get('/overview', authenticate, function(req, res) {
    res.render('overview.html');
});

/* GET: returns the grants the user can see. */
app.get('/getOverview', authenticate, function(req, res) {
    var userId = req.session.user._id;

    if (userId) {
        collectionDriver.getGrants(userId, function(error, results) {
            if (error)
                res.status(400).send(error);
            else {
                var overview = {
                    user: req.session.user,
                    grants: results
                };
                res.json(overview);
            }
        });
    }
    else
        res.status(400).send({error: 'bad user id'});
});

/* Loads detail. */
app.get('/detail', authenticate, function(req, res) {
    if (req.session.grantLoadId)
        res.render('detail.html');
    else
        res.redirect('/');
});

/* Sets the grant to load in the session. */
app.get('/detail/:id', authenticate, function(req, res) {
    req.session.grantLoadId = req.params.id;
    res.redirect('/detail');
});

/* GET: returns the cards belonging to the grant the user can see */
app.get('/getDetail', authenticate, function(req, res) {
    if (!req.session.grantLoadId)
        res.redirect('/overview');

    var userPermissionId = req.session.user.permissions.stage;
    var grantId = req.session.grantLoadId;

    collectionDriver.getCards(grantId, userPermissionId, function(error, results) {
        if (error)
            res.status(400).send(error);
        else{
            var detailView = {
                user: req.session.user,
                cards: results
            };
            res.json(detailView);
        }
    });
});

/* Loads admin */
app.get('/admin', function(req, res) {
    res.render('admin.html');
});

/* GET: returns users with specified stage permissions */
app.get('/manageUsers', function(req, res) {
    var query = req.query;

    if (query.hasOwnProperty('permissions.stage'))  // uri only reads string values
        query['permissions.stage'] = parseInt(query['permissions.stage'], 10);

    collectionDriver.getUsersByDept(query, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* GET: findAll of collection. or enter query to narrow down list*/
app.get('/:collection', function(req, res) {
    var collectionName = req.params.collection;

    collectionDriver.findAll(collectionName, function(error, results) {
        if (error)
            res.status(400).send(error);
        else {
            res.status(200).send(results);
        }
    });
});

/* GET: find id in collection. */
app.get('/:collection/:id', function(req, res) {
    var collection = req.params.collection;
    var id = req.params.id;

    if (id) {
        collectionDriver.get(collection, id, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.json(results);
        });
    }
    else
        res.status(400).send({error: 'bad url', url: req.url});
});

/* PUT: insert document in collection. */
app.put('/:collection', function(req, res) {
    var doc = req.body;
    var collection = req.params.collection;

    collectionDriver.save(collection, doc, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.json(results);
     });
});

/* Sets the stage of an admin to the desired stage they want to view */
app.post('/setAdminStage', authenticateAdmin, function(req, res) {
    var newStage = req.query.stage;

    if (newStage) {
        req.session.user.permissions.stage = newStage;
        res.status(200).send(true);
    }
    else
        res.status(400).send({error: 'bad query'})
});

/* Moves the card given from curCol to newCol */
app.post('/moveCard/:id', authenticate, function(req, res) {
    var card = {
        id: req.params.id,
        curStage: req.session.user.permissions.stage,
        curCol: req.query.curCol,
        newStage: req.session.user.permissions.stage,
        newCol: req.query.newCol
    };
    var grantId = req.session.grantLoadId;

    collectionDriver.moveCard(grantId, card, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* Allows admins to move the card from the current stage to the next one */
app.post('/moveCardStage/:id', authenticateAdmin, function(req, res) {
    var stage = req.session.user.permissions.stage;
    var card = {
        id: req.params.id,
        curStage: stage,
        curCol: "complete",
        newStage: stage + 1,
        newCol: "toDo"
    };
    var grantId = req.session.grantLoadId;

    collectionDriver.moveCard(grantId, card, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send(results);
    });
});

/* Updates the grant in session. */
app.post('/updateGrant', function(req, res) {
    var docUpdates = req.body;
    var grantId = req.session.grantLoadId;
    var userId = req.session.user._id;

    collectionDriver.update("grants", docUpdates, grantId, userId, function(error, results) {
        if (error)
            res.status(400).send(error);
        else
            res.status(200).send("Updated grant " + grantId + " with " + results + ".");
    });
});

/* POST: updates a document with id in the collection. */
app.post('/:collection/:id', authenticate, function(req, res) {
    var userId = req.session.user._id;
    var docUpdates = req.body;
    var id = req.params.id;
    var collection = req.params.collection;

    if (id) {
        collectionDriver.update(collection, docUpdates, id, userId, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.status(200).send("Updated id " + id + " at collection " + collection + ".");
        });
    }
    else {
        var error = { "message" : "Cannot POST a whole collection" };
        res.status(400).send(error);
    }
});

/* DELETE: deletes a document with id in the collection. */
app.delete('/:collection/:id', function(req, res) {
    var id = req.params.id;
    var collection = req.params.collection;

    if (id) {
        collectionDriver.delete(collection, id, function(error, results) {
            if (error)
                res.status(400).send(error);
            else
                res.status(200).send(results);
        });
    } else {
        var error = { "message" : "Cannot DELETE a whole collection" };
        res.status(400).send(error);
   }
});

app.use(function (req,res) {
    res.render('404', {url: req.url});
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>