<commit_before>define(['app', 'lodash', 'authentication'], function(app, _) { 'use strict';

    return ['$scope', '$http', '$route', '$location', '$filter', '$q', function($scope, $http, $route, $location, $filter, $q) {

    $scope.pageSize = 25;
    $scope.tabSetSize = 10;
    $scope.set = 0;
    updatePager(0);

  $http.get('/api/v2013/roles', { cache: true }).then(function (response) {
    		var map = {};
    		response.data.forEach(function (role) {
    			map[role.roleId] = role;
    		});
    		$scope.roles = map;
	});//  $http.get('/api/v2013/roles', { cache: true }).

  $http.get('/api/v2013/countries', { cache: true }).then(function (response) {
  		var map = {};
  		response.data.forEach(function (country) {
  			country.name = country.name.en;
  			map[country.code] = country;
  		});

  		map.EUR = map.EUR || map.EU;

  		$scope.countries = map;
      $scope.countriesList=[];

      $filter('orderBy')(response.data, 'name').forEach(function (country) {
          $scope.countriesList.push({ code : country.code.toLowerCase(), name: country.name });
      });
	});//  $http.get('/api/v2013/countries',

  $http.get("/api/v2013/roles", { cache: true }).then(function(response) {
      $scope.roleList = [];
      $filter('orderBy')(response.data, 'name').forEach(function (o) {
          $scope.roleList.push({ roleId : o.roleId, name: o.name });
      });
  });//$http.get("/api/v2013/roles", {

  var cancelPopulate;

	function populate () {

        if(cancelPopulate) {
            cancelPopulate.resolve();
            cancelPopulate = undefined;
        }

        cancelPopulate = $q.defer();

        return $http.get('/api/v2013/users', { params: { q: $scope.freetext, sk: $scope.currentPage*25, l: 25 , government : $scope.government, role: $scope.roleFilter }, timeout: cancelPopulate.promise }).then(function (response) {

            $scope.userCount =  parseInt(response.headers("record-count"));

            var users = _.map(response.data, function (user) {

                if(user.government)
                    user.government = user.government.toUpperCase();

                return user;
    		});

            $scope.users = users;

            return users;

        }).then(function(users){

            updatePager();

            return users;
        });
	}

  //============================================================
	//
	//
	//============================================================
  function setPage (page) {

      $scope.currentPage = Math.max(0, Math.min($scope.pageCount-1, page|0));
	}

  //============================================================
  //
  //
  //============================================================
    function calcSet (page) {

        var sets = _.range(0,$scope.pageCount,$scope.tabSetSize);
        return  _.find(sets, function(setStart){
                      return (page >= setStart && page < setStart+($scope.tabSetSize)); });
  }//calcSet (page) {

  //============================================================
	//
	//
	//============================================================
    function updatePager(currentPage) {

        var userCount = $scope.userCount || ($scope.users || []).length || $scope.tabSetSize;
        $scope.pageCount = Math.ceil(userCount / 25);
        $scope.set=calcSet(currentPage || $scope.currentPage || 0);
        $scope.pages     = _.range($scope.pageCount).splice($scope.set,($scope.tabSetSize));
        if(currentPage!==undefined)
            setPage (currentPage);

	}//updatePager(currentPage)

	//============================================================
	//
	//
	//============================================================
	$scope.actionDelete = function actionDelete (userID) {

    		if (confirm('Are you sure you want to delete this user account?')) {

                $http.delete('/api/v2013/users/' + userID).success(function () {
    				populate();
    				alert('The user account has been deleted.');
    	        }).error(function (data) {
        	    	alert(data);
            	});
    	  }
	};//$scope.actionDelete = function actionDelete (userID)

  $scope.actionSetPage = setPage;
  $scope.$watch('government',  populate);
  $scope.$watch('roleFilter',  populate);
	$scope.$watch('currentPage', populate);

	$scope.$watch('freetext',  _.debounce(function(){
        setPage(0);
        populate();
    }, 250));
  }];
});
<commit_msg>Debounce search<commit_after>define(['app', 'lodash', 'authentication'], function(app, _) { 'use strict';

    return ['$scope', '$http', '$route', '$location', '$filter', '$q', function($scope, $http, $route, $location, $filter, $q) {

    $scope.pageSize = 25;
    $scope.tabSetSize = 10;
    $scope.set = 0;
    updatePager(0);

  $http.get('/api/v2013/roles', { cache: true }).then(function (response) {
    		var map = {};
    		response.data.forEach(function (role) {
    			map[role.roleId] = role;
    		});
    		$scope.roles = map;
	});//  $http.get('/api/v2013/roles', { cache: true }).

  $http.get('/api/v2013/countries', { cache: true }).then(function (response) {
  		var map = {};
  		response.data.forEach(function (country) {
  			country.name = country.name.en;
  			map[country.code] = country;
  		});

  		map.EUR = map.EUR || map.EU;

  		$scope.countries = map;
      $scope.countriesList=[];

      $filter('orderBy')(response.data, 'name').forEach(function (country) {
          $scope.countriesList.push({ code : country.code.toLowerCase(), name: country.name });
      });
	});//  $http.get('/api/v2013/countries',

  $http.get("/api/v2013/roles", { cache: true }).then(function(response) {
      $scope.roleList = [];
      $filter('orderBy')(response.data, 'name').forEach(function (o) {
          $scope.roleList.push({ roleId : o.roleId, name: o.name });
      });
  });//$http.get("/api/v2013/roles", {

  var cancelPopulate;
  var debouncedPopulate = _.debounce(populate, 250);

	function populate () {

        if(cancelPopulate) {
            cancelPopulate.resolve();
            cancelPopulate = undefined;
        }

        cancelPopulate = $q.defer();

        return $http.get('/api/v2013/users', { params: { q: $scope.freetext, sk: $scope.currentPage*25, l: 25 , government : $scope.government, role: $scope.roleFilter }, timeout: cancelPopulate.promise }).then(function (response) {

            $scope.userCount =  parseInt(response.headers("record-count"));

            var users = _.map(response.data, function (user) {

                if(user.government)
                    user.government = user.government.toUpperCase();

                return user;
    		});

            $scope.users = users;

            return users;

        }).then(function(users){

            updatePager();

            return users;
        });
	}

  //============================================================
	//
	//
	//============================================================
  function setPage (page) {

      $scope.currentPage = Math.max(0, Math.min($scope.pageCount-1, page|0));
	}

  //============================================================
  //
  //
  //============================================================
    function calcSet (page) {

        var sets = _.range(0,$scope.pageCount,$scope.tabSetSize);
        return  _.find(sets, function(setStart){
                      return (page >= setStart && page < setStart+($scope.tabSetSize)); });
  }//calcSet (page) {

  //============================================================
	//
	//
	//============================================================
    function updatePager(currentPage) {

        var userCount = $scope.userCount || ($scope.users || []).length || $scope.tabSetSize;
        $scope.pageCount = Math.ceil(userCount / 25);
        $scope.set=calcSet(currentPage || $scope.currentPage || 0);
        $scope.pages     = _.range($scope.pageCount).splice($scope.set,($scope.tabSetSize));
        if(currentPage!==undefined)
            setPage (currentPage);

	}//updatePager(currentPage)

	//============================================================
	//
	//
	//============================================================
	$scope.actionDelete = function actionDelete (userID) {

    		if (confirm('Are you sure you want to delete this user account?')) {

                $http.delete('/api/v2013/users/' + userID).success(function () {
    				populate();
    				alert('The user account has been deleted.');
    	        }).error(function (data) {
        	    	alert(data);
            	});
    	  }
	};//$scope.actionDelete = function actionDelete (userID)

  $scope.actionSetPage = setPage;
  $scope.$watch('government',  debouncedPopulate);
  $scope.$watch('roleFilter',  debouncedPopulate);
  $scope.$watch('currentPage', debouncedPopulate);
  $scope.$watch('freetext',  _.debounce(function(){
        setPage(0);
        populate();
    }, 250));
  }];
});
<|endoftext|>


<commit_before>Bloob.MapScene = function(game, loop) {
	Bloob.Scene.apply(this, arguments);

	this.game = game;
	this.canvas = this.game.canvas;
	this.loop = loop;

	this.map = new Bloob.Map().initDatGui(game.datGui);
	this.logic = this.map.logic;
	this.world = this.map.world;

	this.camera = new Bloob.Camera(
		this.canvas,
		this.logic,
		this.world,
		this.world.mWorldLimits.Max.y - this.world.mWorldLimits.Min.y
	);
	this.renderer = new DebugDraw(this.canvas, this.camera)
		.setObjectToDraw(this.world);
	this.camera.update();

	// mouseInteraction
	this.mouse = this.initMouseInteraction();
};

//inheritance
var chain = function() {};
chain.prototype = Bloob.Scene.prototype;
Bloob.MapScene.prototype = new chain();
// enable static method inheritance
Bloob.MapScene.__proto__ = Bloob.Scene;
Bloob.MapScene.prototype.constructor = chain;
Bloob.MapScene.prototype.parent = Bloob.Scene.prototype;

Bloob.MapScene.prototype.update = function(timePassed) {
	// entities/map
	this.world.update(timePassed);
	this.logic.update(timePassed);
	// rendering
	this.camera.update(timePassed);
	this.renderer.draw(timePassed);
	// interaction
	this.mouse.update(timePassed);
};

// TODO: rename to onReady
Bloob.MapScene.prototype.onMapLoaded = function(callback) {
	this.map.onBuildFinished(callback);
	return this;
};

Bloob.MapScene.prototype.loadMap = function(mapToLoadName) {
	this.map.build(mapToLoadName);
	return this;
};

Bloob.MapScene.prototype.initMouseInteraction = function() {
	var tecDragBody = Bloob.InteractionHandler.Builder.buildDragBodyInWorld(this.world, this.camera);
	var tecSpawnCube = Bloob.InteractionHandler.Builder.buildSpawnCubeInWorld(this.world, this.camera);
	var tecSelectBody = Bloob.InteractionHandler.Builder.buildSelectBodyInWorld(this.world, this.camera);
	var tecPauseScene = Bloob.InteractionHandler.Builder.buildPauseScene(this);
	var tecCallCallback = new Bloob.InteractionHandler()
		.name("CALL_CALLBACK")
		.onPressed(function() {
			Scarlet.log("hallo");
		});
	var tecChangeMap = new Bloob.InteractionHandler()
		.name("CHANGE_MAP")
		.onPressed(function() {
			Scarlet.log("CHANGE_MAP");
		});
	var tecCreateGroundBody = new Bloob.InteractionHandler()
		.name("CREATE_GROUND_BODY")
		.context({
			world: this.world,
			camera: this.camera,
			shape: new ClosedShape().begin().addVertex(Vector2.Zero.copy()),
			counter: 0
		})
		.onPressed(function(timePassed, mouse) {
			var maxEdges = 4;
			if(this.counter == 0)
				this.shape = new ClosedShape().begin();
			if(this.counter < maxEdges) {
				this.shape.addVertex(this.camera.screenToWorldCoordinates(mouse.input.mouse));
				this.counter++;
			}
			else
			{
				Bloob.BodyFactory.createBluePrint(SpringBody)
					.world(this.world)
					.shape(this.shape.finish())
					.pointMasses(1)
					.translate(this.camera.screenToWorldCoordinates(mouse.input.mouse))
					.rotate(0)
					.scale(Vector2.One.copy())
					.isKinematic(false)
					.edgeSpringK(300.0)
					.edgeSpringDamp(5.0)
					.shapeSpringK(150.0)
					.shapeSpringDamp(5.0)
					.addInternalSpring(0, 2, 300, 10)
					.addInternalSpring(1, 3, 300, 10)
					.build();

				this.counter = 0;
			}
		});
	var interactionTechniquesforDatGui = [
		tecDragBody,
		tecSpawnCube,
		tecSelectBody,
		tecPauseScene,
		tecCallCallback,
		tecChangeMap,
		tecCreateGroundBody
	];

	var mouse = new Bloob.Mouse(this.game.canvas)
		.onLeftClick(tecDragBody)
		.onRightClick(tecCreateGroundBody)
		.initDatGui(this.game.datGui, interactionTechniquesforDatGui);

	return mouse;
};
<commit_msg>added test method for changing of maps<commit_after>Bloob.MapScene = function(game, loop) {
	Bloob.Scene.apply(this, arguments);

	this.game = game;
	this.canvas = this.game.canvas;
	this.loop = loop;

	this.map = new Bloob.Map().initDatGui(game.datGui);
	this.logic = this.map.logic;
	this.world = this.map.world;

	this.camera = new Bloob.Camera(
		this.canvas,
		this.logic,
		this.world,
		this.world.mWorldLimits.Max.y - this.world.mWorldLimits.Min.y
	);
	this.renderer = new DebugDraw(this.canvas, this.camera)
		.setObjectToDraw(this.world);
	this.camera.update();

	// mouseInteraction
	this.mouse = this.initMouseInteraction();

	this.game.datGui.add(this, "testChangeMap").name('change map');
};

//inheritance
var chain = function() {};
chain.prototype = Bloob.Scene.prototype;
Bloob.MapScene.prototype = new chain();
// enable static method inheritance
Bloob.MapScene.__proto__ = Bloob.Scene;
Bloob.MapScene.prototype.constructor = chain;
Bloob.MapScene.prototype.parent = Bloob.Scene.prototype;

Bloob.MapScene.prototype.update = function(timePassed) {
	// entities/map
	this.world.update(timePassed);
	this.logic.update(timePassed);
	// rendering
	this.camera.update(timePassed);
	this.renderer.draw(timePassed);
	// interaction
	this.mouse.update(timePassed);
};

// TODO: rename to onReady
Bloob.MapScene.prototype.onMapLoaded = function(callback) {
	this.map.onBuildFinished(callback);
	return this;
};

Bloob.MapScene.prototype.loadMap = function(mapToLoadName) {
	this.map.build(mapToLoadName);
	return this;
};

Bloob.MapScene.prototype.initMouseInteraction = function() {
	var tecDragBody = Bloob.InteractionHandler.Builder.buildDragBodyInWorld(this.world, this.camera);
	var tecSpawnCube = Bloob.InteractionHandler.Builder.buildSpawnCubeInWorld(this.world, this.camera);
	var tecSelectBody = Bloob.InteractionHandler.Builder.buildSelectBodyInWorld(this.world, this.camera);
	var tecPauseScene = Bloob.InteractionHandler.Builder.buildPauseScene(this);
	var tecCallCallback = new Bloob.InteractionHandler()
		.name("CALL_CALLBACK")
		.onPressed(function() {
			Scarlet.log("hallo");
		});
	var tecChangeMap = new Bloob.InteractionHandler()
		.name("CHANGE_MAP")
		.onPressed(function() {
			Scarlet.log("CHANGE_MAP");
		});
	var tecCreateGroundBody = new Bloob.InteractionHandler()
		.name("CREATE_GROUND_BODY")
		.context({
			world: this.world,
			camera: this.camera,
			shape: new ClosedShape().begin().addVertex(Vector2.Zero.copy()),
			counter: 0
		})
		.onPressed(function(timePassed, mouse) {
			var maxEdges = 4;
			if(this.counter == 0)
				this.shape = new ClosedShape().begin();
			if(this.counter < maxEdges) {
				this.shape.addVertex(this.camera.screenToWorldCoordinates(mouse.input.mouse));
				this.counter++;
			}
			else
			{
				Bloob.BodyFactory.createBluePrint(SpringBody)
					.world(this.world)
					.shape(this.shape.finish())
					.pointMasses(1)
					.translate(this.camera.screenToWorldCoordinates(mouse.input.mouse))
					.rotate(0)
					.scale(Vector2.One.copy())
					.isKinematic(false)
					.edgeSpringK(300.0)
					.edgeSpringDamp(5.0)
					.shapeSpringK(150.0)
					.shapeSpringDamp(5.0)
					.addInternalSpring(0, 2, 300, 10)
					.addInternalSpring(1, 3, 300, 10)
					.build();

				this.counter = 0;
			}
		});
	var interactionTechniquesforDatGui = [
		tecDragBody,
		tecSpawnCube,
		tecSelectBody,
		tecPauseScene,
		tecCallCallback,
		tecChangeMap,
		tecCreateGroundBody
	];

	var mouse = new Bloob.Mouse(this.game.canvas)
		.onLeftClick(tecDragBody)
		.onRightClick(tecCreateGroundBody)
		.initDatGui(this.game.datGui, interactionTechniquesforDatGui);

	return mouse;
};

Bloob.MapScene.prototype.testChangeMap = function() {
	Scarlet.log(arguments);
	// TODO: implement
};
<|endoftext|>


<commit_before>var http    = require('http'),
    cheerio = require('cheerio'),
    _       = require('lodash'),
    async   = require('async');

function ScraperBoknett() {}

_.extend(ScraperBoknett.prototype, {
    getReviewPage: function(offset, callback) {
        offset   = offset || 0;
        callback = callback || function() {};

        var data = '';

        var options = {
            host: 'www.boknett.no',
            path: '/Anmeldelser/(offset)/' + offset
        };

        http.get(options, function(res) {
            res.on('data', function(chunk) {
                data += chunk;
            }).on('end', function() {
                callback(null, data);
            }).on('error', function(err) {
                callback(true, []);
            });
        });
    },

    normalizeSource: function(source) {
        return source.toLowerCase().replace(" ", "-");
    },

    getReviewLinksFromPage: function(html) {
        var $       = cheerio.load(html),
            reviews = $('.reviews .review');

        if (!reviews.length) {
            return false;
        }

        return _.map(reviews, function(review) {
            var review = $(review);

            return {
                url: review.find('a').attr('href'),
                author: review.find('h2').text(),
                title: review.find('h1').text(),
                source: this.normalizeSource(review.find('.source em').text())
            };
        }.bind(this));
    },

    getReviewUrls: function(limit, sources, callback) {
        var highestOffset = 0,
            result        = [],
            resultLength  = 0,
            stop          = false;

        // Set up the queue and worker
        var queue = async.queue(function(task, done) {
            this.getReviewPage(task.offset, function(err, res) {
                var reviews = this.getReviewLinksFromPage(res);

                if (!reviews) {
                    stop = true;
                    queue.empty();
                    done();

                    return;
                }

                result = result.concat(_.filter(reviews, function(review) {
                    return _.contains(sources, review.source);
                }));

                resultLength = result.length;

                done();
            }.bind(this));
        }.bind(this), 10);

        // Callback called when queue is emptied by the worker
        queue.empty = function() {
            if (stop || resultLength >= limit) {
                if (stop) {
                    queue.kill();
                }

                if (resultLength >= limit) {
                    result = result.slice(0, limit);
                }

                callback(null, result);
            } else if (resultLength < limit) {
                for (var i = 0; i < 10; i++) {
                    queue.push({ offset: (highestOffset += 30)});
                }
            }
        };

        // Add ten tasks to the queue
        for (var i = 0; i < 10; i++) {
            queue.push({ offset: (highestOffset += 30)});
        }
    }
});

module.exports = ScraperBoknett;
<commit_msg>Revert "Rewrote the logic. No longer using stone age timeout, but the empty callback triggered by async.queue".<commit_after>var http    = require('http'),
    cheerio = require('cheerio'),
    _       = require('lodash'),
    async   = require('async');

function ScraperBoknett() {}

_.extend(ScraperBoknett.prototype, {
    getReviewPage: function(offset, callback) {
        offset   = offset || 0;
        callback = callback || function() {};

        var data = '';

        var options = {
            host: 'www.boknett.no',
            path: '/Anmeldelser/(offset)/' + offset
        };

        http.get(options, function(res) {
            res.on('data', function(chunk) {
                data += chunk;
            }).on('end', function() {
                callback(null, data);
            }).on('error', function(err) {
                callback(true, []);
            });
        });
    },

    normalizeSource: function(source) {
        return source.toLowerCase().replace(" ", "-");
    },

    getReviewLinksFromPage: function(html) {
        var $       = cheerio.load(html),
            reviews = $('.reviews .review');

        if (!reviews.length) {
            return false;
        }

        return _.map(reviews, function(review) {
            var review = $(review);

            return {
                url: review.find('a').attr('href'),
                author: review.find('h2').text(),
                title: review.find('h1').text(),
                source: this.normalizeSource(review.find('.source em').text())
            };
        }.bind(this));
    },

    getReviewUrls: function(limit, sources, callback) {
        var highestOffset = 0,
            result        = [],
            resultLength  = 0,
            stop          = false;

        var queue = async.queue(function(task, done) {
            this.getReviewPage(task.offset, function(err, res) {
                var reviews = this.getReviewLinksFromPage(res);

                if (!reviews) {
                    stop = true;
                    queue.kill();
                    done();

                    return;
                }

                result = result.concat(_.filter(reviews, function(review) {
                    return _.contains(sources, review.source);
                }));

                resultLength = result.length;

                done();
            }.bind(this));
        }.bind(this), 10);

        var intervalId = setInterval(function() {
            if (!queue.idle()) {
                return;
            }

            if (stop) {
                clearInterval(intervalId);
                callback(null, result);
            } else if (resultLength >= limit) {
                clearInterval(intervalId);
                callback(null, result.slice(0, limit));
            } else if (resultLength < limit) {
                for (var i = 0; i < 10; i++) {
                    queue.push({ offset: (highestOffset += 30)});
                }
            }
        }, 50);
    }
});

module.exports = ScraperBoknett;
<|endoftext|>


<commit_before>// Load in modules
var system = require('system'),
    fs = require('fs'),
    webpage = require('webpage');

// Grab the arguments
var args = system.args,
    filepath = args[1],
    encodedArg = fs.read(filepath);

// If there is no image, throw an error
if (!encodedArg) {
  throw new Error('No argument was specified.');
}

// Load the compose webpage
var page = webpage.create();
page.open(phantom.libraryPath + '/compose.html', function (status) {
  // Grab the arguments
  var arg = decodeURIComponent(encodedArg),
      params = JSON.parse(arg);

  // Run our method
  page.evaluate(function (params) {
    window.processCommand(params);
  }, params);

  // Wait for retStr to exit
  var count = 0;
  function checkForRetStr() {
    // Pluck out the data png
    var retStr = page.evaluate(function () {
      return window.retStr;
    });

    if (!retStr) {
      count += 1;
      if (count > 100) {
        console.log('Images not loaded within 10 seconds. Timing out script.');
        return phantom.exit(1);
      }
      return setTimeout(checkForRetStr, 100);
    }

    // Export the pixel values
    console.log(retStr);

    // Leave the program
    phantom.exit();
  }
  checkForRetStr();
});
<commit_msg>Added option for timeout override<commit_after>// Load in modules
var system = require('system'),
    fs = require('fs'),
    webpage = require('webpage');

// Grab the arguments
var args = system.args,
    filepath = args[1],
    encodedArg = fs.read(filepath);

// If there is no image, throw an error
if (!encodedArg) {
  throw new Error('No argument was specified.');
}

// Load the compose webpage
var page = webpage.create();
page.open(phantom.libraryPath + '/compose.html', function (status) {
  // Grab the arguments
  var arg = decodeURIComponent(encodedArg),
      params = JSON.parse(arg);

  // Run our method
  page.evaluate(function (params) {
    window.processCommand(params);
  }, params);

  // Fallback options
  var options = params.options || {};

  // Wait for retStr to exit with a default timeout of 10 seconds
  var count = 0,
      timeout = (options.timeout || 10e3) / 100;
  function checkForRetStr() {
    // Pluck out the data png
    var retStr = page.evaluate(function () {
      return window.retStr;
    });

    if (!retStr) {
      count += 1;
      if (count > timeout) {
        console.log('Images not loaded within 10 seconds. Timing out script.');
        return phantom.exit(1);
      }
      return setTimeout(checkForRetStr, 100);
    }

    // Export the pixel values
    console.log(retStr);

    // Leave the program
    phantom.exit();
  }
  checkForRetStr();
});
<|endoftext|>


<commit_before>var scontext = require('search-context');
var searchIndexLogger = require('../logger/searchIndexLogger');
var stopwords = require('natural').stopwords;
var totalDocs = 0;

//used on startup
exports.setTotalDocs = function (td) {
  totalDocs = td;
}

exports.search = function (indexes, indexesMultiply, q, callback) {

  var cleanQuery = getCleanQuery(q);
  var filterKeySet = getFilterKeySet(q);
  var keySet = getKeySet(q, cleanQuery);

  getDocumentFreqencies(indexesMultiply, q, keySet, function(err, frequencies) {
    if (err) return callback(getEmptyResultSet());
    getFacets(q, indexes, function(facets) {
      var response = {};
      response['totalDocs'] = frequencies.allDocsIDsInResultSet.length;
      response['facets'] = facets;
      response['hits'] = [];
      //Key an RIKeyset in descending order of document frequency
      var RIKeySet = [];
      for (var k in frequencies.docFreqs)
        RIKeySet.push(k.replace(/^TF~/,'RI~'));
      var unsortedHits = {};
      indexesMultiply.get(RIKeySet, function(err, data) {
        //preserve the order of frequency (least frequent first)
        for (var j = 0; j < RIKeySet.length; j++) {
          var thisKey = RIKeySet[j];
          if (!data[thisKey]) return callback(getEmptyResultSet());
          var firstPass = false;
          if (j == 0) firstPass = true;
          var lastPass = false;
          if (j == (RIKeySet.length - 1)) lastPass = true;
          //account for weighting
          var fieldWeight = 1;
          var fieldName = thisKey.split('~')[1];
          if (q.weight)
            if (q.weight[fieldName])
              fieldWeight = q.weight[fieldName];

          //How far down the frequency set you want to look.
          //Bigger == more accurate, smaller == faster.
          var seekCutOff = 500;

          //if there is only one key in the set, and only one query term
          //set cutoff to be the same length as the page
          if (RIKeySet.length == 1) seekCutOff = (q.pageSize + q.offset);

          var thisSeekCounter = 0;
          for (var i = 0; ((i < data[thisKey].length) && (thisSeekCounter < seekCutOff)); i++) {
            //insert all of this stuff into a sorted array so that
            //subsequent passes can
            var docID = data[thisKey][i][1];
            if (frequencies.allDocsIDsInResultSet.indexOf(docID) != -1) {
              thisSeekCounter++;
              var tuple = [thisKey, (fieldWeight*data[thisKey][i][0])];
              if (firstPass) {
                unsortedHits[docID] = [tuple];
              }
              else {
                if (unsortedHits[docID]) {
                  if (unsortedHits[docID].length == j)
                    unsortedHits[docID].push(tuple);
                  else
                    delete unsortedHits[docID];
                }
              }
            }
//            if ((lastPass) && (Object.keys(unsortedHits).length > maxUnsortedHits)) break;
          }
        }
        //Iterate through object, calculating scores, account for weighting
        var sortedHits = [];
        for (var k in unsortedHits) {
          var score = 0;
          for (var i = 0; i < unsortedHits[k].length; i++)
            score += unsortedHits[k][i][1];
          sortedHits.push([k, score]);
        }
        sortedHits = sortedHits.sort(function(a,b) {
          if (a[1]  b[1])
            return -1;
          return 0;
        });

        //set offset and pagesize
        var offset = 0;
        if (q.offset) offset = q.offset;
        var pageSize = 100;
        if (q.pageSize) pageSize = q.pageSize;
        sortedHits = sortedHits.slice(offset, (offset + pageSize));

        var IDsToBeGlued = [];
        var IDsToBeGluedWithScores = {};
        //get ids of results to glue
        for (var i = 0; i < sortedHits.length; i++) {
          IDsToBeGlued.push('DOCUMENT~' + sortedHits[i][0] + '~');
          IDsToBeGluedWithScores['DOCUMENT~' + sortedHits[i][0] + '~'] = sortedHits[i][1];
        }

        //Glue docs to IDs and send resultset

        indexesMultiply.get(IDsToBeGlued, function(err, data) {
          for (var k in data) {
            var hit = {};
            hit['id'] = k.split('~')[1];
            hit['score'] = IDsToBeGluedWithScores[k];
            hit['document'] = JSON.parse(data[k]);
            var terms = q['query']['*'];
            if (q['query'][q.teaser])
              terms = q['query'][q.teaser];
            if (q.teaser && hit.document[q.teaser]) {
              try {
                hit.document['teaser'] =
                  scontext(hit.document[q.teaser],
                           terms, 400,
                           function hi (string) {
                             return '' + string + ''
                           });
              } catch (e) {
                searchIndexLogger.error('error with teaser generation: ' + e)
              }
            }
            delete hit['document']['*'];
            response["hits"].push(hit);
          }

          response['hits'] = response.hits.sort(function(a,b) {
            if (a.score  b.score)
              return -1;
            return 0;
          });
          response['totalHits'] = frequencies.allDocsIDsInResultSet.length;
          response['query'] = q;

          callback(response);

        });
      });
    });
  });
};

function intersectionDestructive(a, b) {
  var result = new Array();
  while( a.length > 0 && b.length > 0 ) {
     if      (a[0]  b[0]){ b.shift(); }
     else /* they're equal */ {
       result.push(a.shift());
       b.shift();
     }
  }
  return result;
}

var getCleanQuery = function(q) {
  var cleanQuery = {};
  //remove stopwords
  cleanQuery['query'] = {};
  for (var searchField in q['query']) {
    var cleanQueryFieldToken = searchField;
    cleanQuery['query'][cleanQueryFieldToken] = [];
    for (var k = 0; k < q['query'][searchField].length; k++) {
      cleanQuery['query'][cleanQueryFieldToken].push(q['query'][searchField][k]);
    }
  }
  if (q.weight) {
    cleanQuery['weight'] = q.weight;
  }
  return cleanQuery;
}

var getFilterKeySet = function(q) {
  var filterKeySet = [];
  for (k in q.filter) {
    for (var i = 0; i < q.filter[k].length; i++) {
      filterKeySet.push(k + '~' + q.filter[k][i]);
    }
  }
  return filterKeySet;
}

var getKeySet = function(q, cleanQuery) {
  //generate keyset
  var keySet = [];
  for (var queryField in cleanQuery.query) {
    for (var j = 0; j < cleanQuery.query[queryField].length; j++) {
      if (q.filter) {
        for (k in q.filter) {
          for (var i = 0; i < q.filter[k].length; i++) {
            keySet.push('TF~' + queryField + '~' + cleanQuery.query[queryField][j] + '~'
                        + k + '~' + q.filter[k][i]);
          }
        }
      }
      else {
        keySet.push('TF~' + queryField + '~' + cleanQuery.query[queryField][j] + '~~');
      }
    }
  }
  return keySet;
}

var getEmptyResultSet = function() {
  var resultSet = {};
  resultSet['hits'] = [];
  return resultSet;
}

var getDocumentFreqencies = function(indexesMultiply, q, keySet, callback) {
  //Check document frequencies
  var err = false;
  var docFreqs = {};
  var tfsets = [];
  var totalHits = 0;
  if (!q.pageSize)
    q.pageSize = 100; //default
  if (!q.offset)
    q.offset = 0;     //default
  indexesMultiply.get(keySet, function(err, data) {
    for (k in data) {
      if (data[k] == null) {
        //return a zero result
        docFreqs[keySet[i]] = 0;
        searchIndexLogger.debug('KEY ' + k + ' NOT FOUND IN DICTIONARY');
      }
      else {
        //    totalHits = data[k].length;
        docFreqs[k] = data[k].length;
        tfsets.push(data[k]);
      }
    }
    var intersection = tfsets[0];
    for (var i = 1; i < tfsets.length; i++) {
      intersection = intersectionDestructive(intersection, tfsets[i]);
    }

    if(intersection === undefined)
      err = true;
    else
      totalHits = intersection.length;
    callback(err, {docFreqs:docFreqs, allDocsIDsInResultSet:intersection});
  });
};

var getFacets = function(q, indexes, callback) {
  //if no facet request callback and return
  if (!q.facets){callback({});return;}

  var facetLength = 10;
  if (q.facetLength) facetLength = q.facetLength;

  var sortOnValueDesc = function(a,b) {if (a.value  b.value) return -1; return 0;}
  var sortOnValueAsc = function(a,b) {if (a.value  b.value) return 1; return 0;}
  var sortOnKeyDesc = function(a,b) {if (a.key  b.key) return -1; return 0;}
  var sortOnKeyAsc = function(a,b) {if (a.key  b.key) return 1; return 0;}

  var facetKeySet = [];
  var filterKeySet = [];
  for (var searchField in q.query) {
    for (var h = 0; h < q.query[searchField].length; h++) {
      var queryToken = q.query[searchField][h];
      for (var i = 0; i < q.facets.length; i++) {
        var facetName = q.facets[i];
        facetKeySet.push('TF~'
                         + searchField + '~'
                         + queryToken + '~'
                         + facetName + '~');
        if (q.filter) {
          if (q.filter[facetName]) {
            thisFilterValues = q.filter[facetName];
            for (var l = 0; l < thisFilterValues.length; l++) {
              filterKeySet.push('TF~'
                                + searchField + '~'
                                + queryToken + '~'
                                + facetName + '~' + thisFilterValues[l]);
            }
          }
        }
      }
    }
  }

  var facetsSoFar = {};
  for (var i = 0; i < q.facets.length; i++)
    facetsSoFar[q.facets[i]] = {};

  //could be speeded up by always taking the least frequent keys first?
  var getFacetSets = function(facetks, filterks, counter) {
    var thisFacetCat = facetks[counter].split('~')[3];
    indexes.createReadStream({
      valueEncoding: 'json',
      limit: -1,
      start: facetks[counter],
      end: facetks[counter] + '~'})
      .on('data', function (data) {
        var thisFacetName = data.key.split('~')[4];

        var filteredFacetSet = data.value; //its actually unfiltered at this point
        //handle intersections for filters
        for (var i = 0; i < filterks.length; i++) {
          var filters = filterks[i].slice(0);
          filteredFacetSet = intersectionDestructive(filteredFacetSet, filters);
        }
        if (!facetsSoFar[thisFacetCat][thisFacetName]) {
          if (filteredFacetSet.length > 0)
            facetsSoFar[thisFacetCat][thisFacetName] = filteredFacetSet;
        }
        else {
          //handle intersections for multiword queries
          var intersection = intersectionDestructive(facetsSoFar[thisFacetCat][thisFacetName], filteredFacetSet);
          if (intersection.length > 0)
            facetsSoFar[thisFacetCat][thisFacetName] = intersection;
          else
            delete facetsSoFar[thisFacetCat][thisFacetName];
        }
      })
      .on('end', function () {
        if (++counter < facetks.length) {getFacetSets(facetKeySet, filterks, counter);}
        else {
          //flatten sets to counts
          var finalFacets = {};
          for (k in facetsSoFar) {
            finalFacets[k] = [];
            for (kk in facetsSoFar[k]) {

              //if facet is active add flag
              var thisFacetEntry = {'key':kk,'value':facetsSoFar[k][kk].length};
              if (q['filter']) if (q['filter'][k]) if (q['filter'][k].indexOf(kk) != -1)
                thisFacetEntry['active'] = true;

              finalFacets[k].push(thisFacetEntry);
            }
            if (q.facetSort) {
              if (q.facetSort == 'keyAsc') finalFacets[k].sort(sortOnKeyAsc);
              else if (q.facetSort == 'keyDesc') finalFacets[k].sort(sortOnKeyDesc);
              else if (q.facetSort == 'valueAsc') finalFacets[k].sort(sortOnValueAsc);
              else if (q.facetSort == 'valueDesc') finalFacets[k].sort(sortOnValueDesc);
            }
            else {
              finalFacets[k].sort(sortOnValueDesc);
            }
            finalFacets[k] = finalFacets[k].slice(0, facetLength);
          }
          //finished!
          callback(finalFacets);
        }
      });
  }
  indexesMultiply.get(filterKeySet, function (err, data) {
    var filters = [];
    for (var i in data)
      filters.push(data[i]);
    getFacetSets(facetKeySet, filters, 0);
  });
};
<commit_msg>tidying<commit_after>var scontext = require('search-context');
var searchIndexLogger = require('../logger/searchIndexLogger');
var stopwords = require('natural').stopwords;
var totalDocs = 0;

//used on startup
exports.setTotalDocs = function (td) {
  totalDocs = td;
}

exports.search = function (indexes, indexesMultiply, q, callback) {
  var filterKeySet = getFilterKeySet(q);
  var keySet = getKeySet(q);
  getDocumentFreqencies(indexesMultiply, q, keySet, function(err, frequencies) {
    if (err) return callback(getEmptyResultSet());
    getResults(q, frequencies, indexes, function(response) {
      getFacets(q, indexes, function(facets){
        response['facets'] = facets;
        return callback(response);
      });
    });
  });
};

function intersectionDestructive(a, b) {
  var result = new Array();
  while( a.length > 0 && b.length > 0 ) {
     if      (a[0]  b[0]){ b.shift(); }
     else /* they're equal */ {
       result.push(a.shift());
       b.shift();
     }
  }
  return result;
}

var getCleanQuery = function(q) {
  var cleanQuery = {};
  //remove stopwords
  cleanQuery['query'] = {};
  for (var searchField in q['query']) {
    var cleanQueryFieldToken = searchField;
    cleanQuery['query'][cleanQueryFieldToken] = [];
    for (var k = 0; k < q['query'][searchField].length; k++) {
      cleanQuery['query'][cleanQueryFieldToken].push(q['query'][searchField][k]);
    }
  }
  if (q.weight) {
    cleanQuery['weight'] = q.weight;
  }
  return cleanQuery;
}

var getFilterKeySet = function(q) {
  var filterKeySet = [];
  for (k in q.filter) {
    for (var i = 0; i < q.filter[k].length; i++) {
      filterKeySet.push(k + '~' + q.filter[k][i]);
    }
  }
  return filterKeySet;
}

var getKeySet = function(q) {
  //generate keyset
  cleanQuery = getCleanQuery(q);
  var keySet = [];
  for (var queryField in cleanQuery.query) {
    for (var j = 0; j < cleanQuery.query[queryField].length; j++) {
      if (q.filter) {
        for (k in q.filter) {
          for (var i = 0; i < q.filter[k].length; i++) {
            keySet.push('TF~' + queryField + '~' + cleanQuery.query[queryField][j] + '~'
                        + k + '~' + q.filter[k][i]);
          }
        }
      }
      else {
        keySet.push('TF~' + queryField + '~' + cleanQuery.query[queryField][j] + '~~');
      }
    }
  }
  return keySet;
}

var getEmptyResultSet = function() {
  var resultSet = {};
  resultSet['hits'] = [];
  return resultSet;
}

var getDocumentFreqencies = function(indexesMultiply, q, keySet, callback) {
  //Check document frequencies
  var err = false;
  var docFreqs = {};
  var tfsets = [];
  var totalHits = 0;
  if (!q.pageSize)
    q.pageSize = 100; //default
  if (!q.offset)
    q.offset = 0;     //default
  indexesMultiply.get(keySet, function(err, data) {
    for (k in data) {
      if (data[k] == null) {
        //return a zero result
        docFreqs[keySet[i]] = 0;
        searchIndexLogger.debug('KEY ' + k + ' NOT FOUND IN DICTIONARY');
      }
      else {
        //    totalHits = data[k].length;
        docFreqs[k] = data[k].length;
        tfsets.push(data[k]);
      }
    }
    var intersection = tfsets[0];
    for (var i = 1; i < tfsets.length; i++) {
      intersection = intersectionDestructive(intersection, tfsets[i]);
    }

    if(intersection === undefined)
      err = true;
    else
      totalHits = intersection.length;
    callback(err, {docFreqs:docFreqs, allDocsIDsInResultSet:intersection});
  });
};

var getFacets = function(q, indexes, callback) {
  //if no facet request callback and return
  if (!q.facets){callback({});return;}

  var facetLength = 10;
  if (q.facetLength) facetLength = q.facetLength;

  var sortOnValueDesc = function(a,b) {if (a.value  b.value) return -1; return 0;}
  var sortOnValueAsc = function(a,b) {if (a.value  b.value) return 1; return 0;}
  var sortOnKeyDesc = function(a,b) {if (a.key  b.key) return -1; return 0;}
  var sortOnKeyAsc = function(a,b) {if (a.key  b.key) return 1; return 0;}

  var facetKeySet = [];
  var filterKeySet = [];
  for (var searchField in q.query) {
    for (var h = 0; h < q.query[searchField].length; h++) {
      var queryToken = q.query[searchField][h];
      for (var i = 0; i < q.facets.length; i++) {
        var facetName = q.facets[i];
        facetKeySet.push('TF~'
                         + searchField + '~'
                         + queryToken + '~'
                         + facetName + '~');
        if (q.filter) {
          if (q.filter[facetName]) {
            thisFilterValues = q.filter[facetName];
            for (var l = 0; l < thisFilterValues.length; l++) {
              filterKeySet.push('TF~'
                                + searchField + '~'
                                + queryToken + '~'
                                + facetName + '~' + thisFilterValues[l]);
            }
          }
        }
      }
    }
  }

  var facetsSoFar = {};
  for (var i = 0; i < q.facets.length; i++)
    facetsSoFar[q.facets[i]] = {};

  //could be speeded up by always taking the least frequent keys first?
  var getFacetSets = function(facetks, filterks, counter) {
    var thisFacetCat = facetks[counter].split('~')[3];
    indexes.createReadStream({
      valueEncoding: 'json',
      limit: -1,
      start: facetks[counter],
      end: facetks[counter] + '~'})
      .on('data', function (data) {
        var thisFacetName = data.key.split('~')[4];

        var filteredFacetSet = data.value; //its actually unfiltered at this point
        //handle intersections for filters
        for (var i = 0; i < filterks.length; i++) {
          var filters = filterks[i].slice(0);
          filteredFacetSet = intersectionDestructive(filteredFacetSet, filters);
        }
        if (!facetsSoFar[thisFacetCat][thisFacetName]) {
          if (filteredFacetSet.length > 0)
            facetsSoFar[thisFacetCat][thisFacetName] = filteredFacetSet;
        }
        else {
          //handle intersections for multiword queries
          var intersection = intersectionDestructive(facetsSoFar[thisFacetCat][thisFacetName], filteredFacetSet);
          if (intersection.length > 0)
            facetsSoFar[thisFacetCat][thisFacetName] = intersection;
          else
            delete facetsSoFar[thisFacetCat][thisFacetName];
        }
      })
      .on('end', function () {
        if (++counter < facetks.length) {getFacetSets(facetKeySet, filterks, counter);}
        else {
          //flatten sets to counts
          var finalFacets = {};
          for (k in facetsSoFar) {
            finalFacets[k] = [];
            for (kk in facetsSoFar[k]) {

              //if facet is active add flag
              var thisFacetEntry = {'key':kk,'value':facetsSoFar[k][kk].length};
              if (q['filter']) if (q['filter'][k]) if (q['filter'][k].indexOf(kk) != -1)
                thisFacetEntry['active'] = true;

              finalFacets[k].push(thisFacetEntry);
            }
            if (q.facetSort) {
              if (q.facetSort == 'keyAsc') finalFacets[k].sort(sortOnKeyAsc);
              else if (q.facetSort == 'keyDesc') finalFacets[k].sort(sortOnKeyDesc);
              else if (q.facetSort == 'valueAsc') finalFacets[k].sort(sortOnValueAsc);
              else if (q.facetSort == 'valueDesc') finalFacets[k].sort(sortOnValueDesc);
            }
            else {
              finalFacets[k].sort(sortOnValueDesc);
            }
            finalFacets[k] = finalFacets[k].slice(0, facetLength);
          }
          //finished!
          callback(finalFacets);
        }
      });
  }
  indexesMultiply.get(filterKeySet, function (err, data) {
    var filters = [];
    for (var i in data)
      filters.push(data[i]);
    getFacetSets(facetKeySet, filters, 0);
  });
};

var getResults = function(q, frequencies, indexes, callback) {
  var response = {};
  response['totalDocs'] = frequencies.allDocsIDsInResultSet.length;
//  response['facets'] = facets;
  response['hits'] = [];
  //Key an RIKeyset in descending order of document frequency
  var RIKeySet = [];
  for (var k in frequencies.docFreqs)
    RIKeySet.push(k.replace(/^TF~/,'RI~'));
  var unsortedHits = {};
  indexesMultiply.get(RIKeySet, function(err, data) {
    //preserve the order of frequency (least frequent first)
    for (var j = 0; j < RIKeySet.length; j++) {
      var thisKey = RIKeySet[j];
      if (!data[thisKey]) return callback(getEmptyResultSet());
      var firstPass = false;
      if (j == 0) firstPass = true;
      var lastPass = false;
      if (j == (RIKeySet.length - 1)) lastPass = true;
      //account for weighting
      var fieldWeight = 1;
      var fieldName = thisKey.split('~')[1];
      if (q.weight)
        if (q.weight[fieldName])
          fieldWeight = q.weight[fieldName];

      //How far down the frequency set you want to look.
      //Bigger == more accurate, smaller == faster.
      var seekCutOff = 500;

      //if there is only one key in the set, and only one query term
      //set cutoff to be the same length as the page
      if (RIKeySet.length == 1) seekCutOff = (q.pageSize + q.offset);

      var thisSeekCounter = 0;
      for (var i = 0; ((i < data[thisKey].length) && (thisSeekCounter < seekCutOff)); i++) {
        //insert all of this stuff into a sorted array so that
        //subsequent passes can
        var docID = data[thisKey][i][1];
        if (frequencies.allDocsIDsInResultSet.indexOf(docID) != -1) {
          thisSeekCounter++;
          var tuple = [thisKey, (fieldWeight*data[thisKey][i][0])];
          if (firstPass) {
            unsortedHits[docID] = [tuple];
          }
          else {
            if (unsortedHits[docID]) {
              if (unsortedHits[docID].length == j)
                unsortedHits[docID].push(tuple);
              else
                delete unsortedHits[docID];
            }
          }
        }
        //            if ((lastPass) && (Object.keys(unsortedHits).length > maxUnsortedHits)) break;
      }
    }
    //Iterate through object, calculating scores, account for weighting
    var sortedHits = [];
    for (var k in unsortedHits) {
      var score = 0;
      for (var i = 0; i < unsortedHits[k].length; i++)
        score += unsortedHits[k][i][1];
      sortedHits.push([k, score]);
    }
    sortedHits = sortedHits.sort(function(a,b) {
      if (a[1]  b[1])
        return -1;
      return 0;
    });

    //set offset and pagesize
    var offset = 0;
    if (q.offset) offset = q.offset;
    var pageSize = 100;
    if (q.pageSize) pageSize = q.pageSize;
    sortedHits = sortedHits.slice(offset, (offset + pageSize));

    var IDsToBeGlued = [];
    var IDsToBeGluedWithScores = {};
    //get ids of results to glue
    for (var i = 0; i < sortedHits.length; i++) {
      IDsToBeGlued.push('DOCUMENT~' + sortedHits[i][0] + '~');
      IDsToBeGluedWithScores['DOCUMENT~' + sortedHits[i][0] + '~'] = sortedHits[i][1];
    }

    //Glue docs to IDs and send resultset

    indexesMultiply.get(IDsToBeGlued, function(err, data) {
      for (var k in data) {
        var hit = {};
        hit['id'] = k.split('~')[1];
        hit['score'] = IDsToBeGluedWithScores[k];
        hit['document'] = JSON.parse(data[k]);
        var terms = q['query']['*'];
        if (q['query'][q.teaser])
          terms = q['query'][q.teaser];
        if (q.teaser && hit.document[q.teaser]) {
          try {
            hit.document['teaser'] =
              scontext(hit.document[q.teaser],
                       terms, 400,
                       function hi (string) {
                         return '' + string + ''
                       });
          } catch (e) {
            searchIndexLogger.error('error with teaser generation: ' + e)
          }
        }
        delete hit['document']['*'];
        response["hits"].push(hit);
      }

      response['hits'] = response.hits.sort(function(a,b) {
        if (a.score  b.score)
          return -1;
        return 0;
      });
      response['totalHits'] = frequencies.allDocsIDsInResultSet.length;
      response['query'] = q;

      callback(response);

    });
  });
}
<|endoftext|>


<commit_before>var View = require('./view');
var template = require('./templates/topbar');
var SignInModal = require("./templates/sign_in_modal");
var SignInView = require("./sign_in");
var SessionsView = require("./sessions_view");
var HangoutLink = require("./templates/hangout_link");
var AboutLink = require("./templates/about_link");

module.exports = View.extend({
    id:'top-bar',
    template:template,
    _autocompleteSources:[],
    sessionsView: new SessionsView(),

    events:{
        "click .signin": function() {
            this.$signInModal.modal("toggle");
            return false;
        }
    },

    initialize:function (options) {
        _.extend(this, options);
        _.bindAll(this, 'initSearchAutocomplete', 'addAutocompleteSource', 'initHangoutLink', 'initAboutLinks');
        _.defer(this.initHangoutLink);
        _.defer(this.initAboutLinks);
    },

    initHangoutLink: function() {
        var hangoutUrl = qed.Display.get("hangoutUrl");
        if (hangoutUrl) {
            this.$el.find(".hangout-container").html(HangoutLink({ "url": hangoutUrl }));
        }
    },

    initAboutLinks: function() {
        var aboutLinks = qed.Display.get("aboutLinks") || [];
        if (!_.isEmpty(aboutLinks)) {
            var UL = this.$el.find(".about-links");
            UL.empty();
            _.each(aboutLinks, function(aboutLink) {
                UL.append(AboutLink(aboutLink));
            });
        }
    },

    afterRender:function () {
        this.initSearchAutocomplete();
        this.initSignIn();

        this.$el.find(".titled").html(qed.Display.get("title") || "QED");
        this.$el.find(".sessions-container").html(this.sessionsView.render().el);
    },

    initSearchAutocomplete:function () {
        var queryEl = this.$el.find("#querySearchTerm");
        var resultsModal = this.$el.find("#searchResults");
        resultsModal.modal({ backdrop:false, show:false });

        var modalBody = resultsModal.find(".modal-body");
        var me = this;

        queryEl.typeahead({
            source:function (query) {
                modalBody.empty();

                _.each(me._autocompleteSources, function (src) {
                    if (src.autocomplete) {
                        var resultBin = function (results) {
                            if (results && results.length) {
                                resultsModal.modal('show');

                                var html = [];
                                html.push("
");
                                if (src.label) html.push("
" + src.label + "
");
                                _.each(_.uniq(results), function (result) {
                                    html.push("
" + result + "
");
                                });
                                html.push("
");
                                modalBody.append(html.join(""));

                                modalBody.find("li").find("a").click(function () {
                                    resultsModal.modal("hide");
                                });
                            }
                        };

                        src.autocomplete(query, resultBin);
                    }
                });
            }
        });
    },

    addAutocompleteSource:function (newSource) {
        this._autocompleteSources.push(newSource);
    },

    initSignIn:function () {
        this.$signInModal = $("body").append(SignInModal()).find(".signin-container");

        var _this = this;
        var addAuthProviders = function(json) {
            _.each(json.providers, function (provider) {
                var sign_in_view = new SignInView({ "provider":provider });
                _this.$signInModal.find(".modal-body").append(sign_in_view.render().el);
                _this.$signInModal.find(".signout-all").click(function() {
                    sign_in_view.signout();
                });
                if (provider.id == "google") {
                    if (provider.active) _this.$el.find(".requires-google-oauth").show();
                    sign_in_view.on("signout", function() {
                        _this.$el.find(".requires-google-oauth").hide();
                    });
                }
            });
        };

        // prepare sign in process in case of 403 (Forbidden)
        var signInProcessStart = _.once(function() {
            $.ajax({
                url: "svc/auth/providers",
                type: "GET",
                dataType: "json",
                success: function(json) {
                    addAuthProviders(json);
                    _this.$signInModal.modal("show");
                    _this.$signInModal.find(".signout-all").click();
                }
            });
        });

        this.$el.ajaxError(function(event, request) {
            if (request.status == 403) signInProcessStart();
        });

        $.ajax({ url:"svc/auth/whoami", method:"GET", context:this, success:addAuthProviders });
    }
});
<commit_msg>cleanup about links<commit_after>var View = require('./view');
var template = require('./templates/topbar');
var SignInModal = require("./templates/sign_in_modal");
var SignInView = require("./sign_in");
var SessionsView = require("./sessions_view");
var HangoutLink = require("./templates/hangout_link");
var AboutLink = require("./templates/about_link");

module.exports = View.extend({
    id:'top-bar',
    template:template,
    _autocompleteSources:[],
    sessionsView: new SessionsView(),

    events:{
        "click .signin": function() {
            this.$signInModal.modal("toggle");
            return false;
        }
    },

    initialize:function (options) {
        _.extend(this, options);
        _.bindAll(this, 'initSearchAutocomplete', 'addAutocompleteSource', 'initHangoutLink', 'initAboutLinks');
        _.defer(this.initHangoutLink);
        _.defer(this.initAboutLinks);
    },

    initHangoutLink: function() {
        var hangoutUrl = qed.Display.get("hangoutUrl");
        if (hangoutUrl) {
            this.$el.find(".hangout-container").html(HangoutLink({ "url": hangoutUrl }));
        }
    },

    initAboutLinks: function() {
        var aboutLinks = qed.Display.get("aboutLinks") || [];
        if (!_.isEmpty(aboutLinks)) {
            var UL = this.$el.find(".about-links");
            UL.empty();
            _.each(aboutLinks, function(aboutLink) {
                if (aboutLink.divider) {
                    UL.append("

");
                    if (aboutLink.header) {
                        UL.append("
" + aboutLink.header + "
");
                    }
                } else {
                    UL.append(AboutLink(aboutLink));
                }
            });
        }
    },

    afterRender:function () {
        this.initSearchAutocomplete();
        this.initSignIn();

        this.$el.find(".titled").html(qed.Display.get("title") || "QED");
        this.$el.find(".sessions-container").html(this.sessionsView.render().el);
    },

    initSearchAutocomplete:function () {
        var queryEl = this.$el.find("#querySearchTerm");
        var resultsModal = this.$el.find("#searchResults");
        resultsModal.modal({ backdrop:false, show:false });

        var modalBody = resultsModal.find(".modal-body");
        var me = this;

        queryEl.typeahead({
            source:function (query) {
                modalBody.empty();

                _.each(me._autocompleteSources, function (src) {
                    if (src.autocomplete) {
                        var resultBin = function (results) {
                            if (results && results.length) {
                                resultsModal.modal('show');

                                var html = [];
                                html.push("
");
                                if (src.label) html.push("
" + src.label + "
");
                                _.each(_.uniq(results), function (result) {
                                    html.push("
" + result + "
");
                                });
                                html.push("
");
                                modalBody.append(html.join(""));

                                modalBody.find("li").find("a").click(function () {
                                    resultsModal.modal("hide");
                                });
                            }
                        };

                        src.autocomplete(query, resultBin);
                    }
                });
            }
        });
    },

    addAutocompleteSource:function (newSource) {
        this._autocompleteSources.push(newSource);
    },

    initSignIn:function () {
        this.$signInModal = $("body").append(SignInModal()).find(".signin-container");

        var _this = this;
        var addAuthProviders = function(json) {
            _.each(json.providers, function (provider) {
                var sign_in_view = new SignInView({ "provider":provider });
                _this.$signInModal.find(".modal-body").append(sign_in_view.render().el);
                _this.$signInModal.find(".signout-all").click(function() {
                    sign_in_view.signout();
                });
                if (provider.id == "google") {
                    if (provider.active) _this.$el.find(".requires-google-oauth").show();
                    sign_in_view.on("signout", function() {
                        _this.$el.find(".requires-google-oauth").hide();
                    });
                }
            });
        };

        // prepare sign in process in case of 403 (Forbidden)
        var signInProcessStart = _.once(function() {
            $.ajax({
                url: "svc/auth/providers",
                type: "GET",
                dataType: "json",
                success: function(json) {
                    addAuthProviders(json);
                    _this.$signInModal.modal("show");
                    _this.$signInModal.find(".signout-all").click();
                }
            });
        });

        this.$el.ajaxError(function(event, request) {
            if (request.status == 403) signInProcessStart();
        });

        $.ajax({ url:"svc/auth/whoami", method:"GET", context:this, success:addAuthProviders });
    }
});
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2013, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Application, Window, GUI, Dialogs) {

  function formatTime(secs) {
    var hr  = Math.floor(secs / 3600);
    var min = Math.floor((secs - (hr * 3600))/60);
    var sec = Math.floor(secs - (hr * 3600) -  (min * 60));

    if (min < 10){
      min = "0" + min;
    }
    if (sec < 10){
      sec  = "0" + sec;
    }

    return min + ':' + sec;
  }

  /////////////////////////////////////////////////////////////////////////////
  // WINDOWS
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Main Window
   */
  var ApplicationMusicPlayerWindow = function(app) {
    Window.apply(this, ['ApplicationMusicPlayerWindow', {width: 322, height: 225}, app]);

    this.title            = "Music Player";
    this.$buttons         = {};
    this.$labels          = {};
    this.$audio           = null;
    this.currentFilename  = '';
    this.seeking          = false;

    // Set window properties here
    this._title = this.title;
    this._icon  = "status/audio-volume-high.png";

    this._properties.allow_drop     = true;
    this._properties.allow_resize   = false;
    this._properties.allow_maximize = false;
  };

  ApplicationMusicPlayerWindow.prototype = Object.create(Window.prototype);

  ApplicationMusicPlayerWindow.prototype.init = function(wmRef, app) {
    var root = Window.prototype.init.apply(this, arguments);
    var self = this;

    var _createButton = function(img, onclick) {
      var b = document.createElement('button');
      var i = document.createElement('img');
      i.alt = '';
      i.src = OSjs.API.getThemeResource('actions/' + img + '.png', 'icon', '32x32');
      b.onclick = onclick;
      b.disabled = "disabled";
      b.appendChild(i);

      self.$buttons[img.split('_')[1]] = b;

      return b;
    };

    var menuBar = this._addGUIElement(new OSjs.GUI.MenuBar('ApplicationTextpadMenuBar'), root);
    menuBar.addItem("File", [
      {title: 'Open', name: 'Open', onClick: function() {
        app._createDialog('File', [{type: 'open', mimes: ['^audio']}, function(btn, fname, fmime) {
          if ( btn !== 'ok' ) return;
          app.play(fname, fmime);
        }], self);
      }},
      {title: 'Close', name: 'Close', onClick: function() {
        self._close();
      }}
    ]);

    var container = document.createElement('div');
    container.className = 'Container';

    // Audio
    this.$audio = document.createElement('audio');
    this.$audio.style.display = 'none';
    this.$audio.style.position = 'absolute';
    this.$audio.style.top = '-10000px';
    this.$audio.style.left = '-10000px';

    // Info
    var info = document.createElement('div');
    info.className = 'Info';

    var lblArtist = document.createElement('div');
    var spanArtist = document.createElement('span');
    var infoArtist = document.createElement('span');
    spanArtist.className = 'Label';
    spanArtist.innerHTML = 'Artist';
    infoArtist.innerHTML = '-';
    lblArtist.appendChild(spanArtist);
    lblArtist.appendChild(infoArtist);
    info.appendChild(lblArtist);
    this.$labels.Artist = infoArtist;

    var lblAlbum = document.createElement('div');
    var spanAlbum = document.createElement('span');
    var infoAlbum = document.createElement('span');
    spanAlbum.className = 'Label';
    spanAlbum.innerHTML = 'Album';
    infoAlbum.innerHTML = '-';
    lblAlbum.appendChild(spanAlbum);
    lblAlbum.appendChild(infoAlbum);
    info.appendChild(lblAlbum);
    this.$labels.Album = infoAlbum;

    var lblTrack = document.createElement('div');
    var spanTrack = document.createElement('span');
    var infoTrack = document.createElement('span');
    spanTrack.className = 'Label';
    spanTrack.innerHTML = 'Track';
    infoTrack.innerHTML = '-';
    lblTrack.appendChild(spanTrack);
    lblTrack.appendChild(infoTrack);
    info.appendChild(lblTrack);
    this.$labels.Track = infoTrack;

    var lblTime = document.createElement('div');
    var spanTime = document.createElement('span');
    var infoTime = document.createElement('span');
    spanTime.className = 'Label';
    spanTime.innerHTML = 'Time';
    infoTime.innerHTML = '00:00 / 00:00';
    lblTime.appendChild(spanTime);
    lblTime.appendChild(infoTime);
    info.appendChild(lblTime);
    this.$labels.Time = infoTime;

    // Buttons
    var buttons = document.createElement('div');
    buttons.className = 'Buttons';

    buttons.appendChild(_createButton('player_start', function(ev) {
    }));
    buttons.appendChild(_createButton('player_rew', function(ev) {
    }));
    buttons.appendChild(_createButton('player_play', function(ev) {
      self.$audio.play();
    }));
    buttons.appendChild(_createButton('player_pause', function(ev) {
      self.$audio.pause();
    }));
    buttons.appendChild(_createButton('player_fwd', function(ev) {
    }));
    buttons.appendChild(_createButton('player_end', function(ev) {
    }));

    // Containers
    container.appendChild(info);
    var slider = this._addGUIElement(new OSjs.GUI.Slider('MusicPlayerSlider', {min:0, max:100, val:0}, function(val) {
      if ( val < 0 ) return;
      self.seek(val);
    }), container);
    container.appendChild(buttons);

    // FIXME: Remove event listeners
    this.$audio.addEventListener("loadeddata", function(ev) {
      self.updateInfo(ev, null, slider);
      app.info(self.currentFilename);
    });
    this.$audio.addEventListener("timeupdate", function(ev) {
      self.updateTime(ev, slider);
    });
    this.$audio.addEventListener("error", function(ev) {
      self.updateInfo(ev, null, slider);

      var msg;
      try {
        switch ( ev.target.error.code ) {
          case ev.target.error.MEDIA_ERR_ABORTED:
            msg = 'You aborted the video playback.';
            break;
          case ev.target.error.MEDIA_ERR_NETWORK:
            msg = 'A network error caused the audio download to fail.';
            break;
          case ev.target.error.MEDIA_ERR_DECODE:
            msg = 'The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.';
            break;
          case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
            msg = 'The video audio not be loaded, either because the server or network failed or because the format is not supported.';
            break;
          default:
            msg = "Unknown error";
            break;
        }
      } catch ( e ) {
        msg = "Fatal error: " + e;
      }

      self._error("Music Player error", "Failed to play file", msg);
    }, true);

    root.appendChild(container);
    root.appendChild(this.$audio);
    return root;
  };

  ApplicationMusicPlayerWindow.prototype.destroy = function() {
    // Destroy custom objects etc. here

    Window.prototype.destroy.apply(this, arguments);
  };

  ApplicationMusicPlayerWindow.prototype._onDndEvent = function(ev, type, item, args) {
    Window.prototype._onDndEvent.apply(this, arguments);
    if ( type === 'itemDrop' && item ) {
      var data = item.data;
      if ( data && data.type === 'file' && data.mime ) {
        this._appRef.play(data.path, data.mime);
      }
    }
  };

  ApplicationMusicPlayerWindow.prototype.play = function(filename, mime) {
    this.currentFilename = filename;

    try {
      this.$labels.Arist.innerHTML = filename;
      this.$labels.Album.innerHTML = mime;
    } catch ( e ) {
      console.warn("Failed to set labels", e);
    }

    try {
      this.$buttons.play.removeAttribute('disabled');
      this.$buttons.pause.removeAttribute('disabled');
    } catch ( e ) {
      console.warn("Failed toggle buttons", e);
    }

    this.$audio.src         = OSjs.API.getResourceURL(filename);
    this.$audio.volume      = 1.0;

    this.$audio.play();

    this._setTitle(this.title + ' - ' + OSjs.Utils.filename(filename));

    return true;
  };

  ApplicationMusicPlayerWindow.prototype.updateInfo = function(ev, info, slider) {
    if ( this.seeking ) return;
    if ( !this.$audio ) return;
    info = info || {};
    var msg = '-';
    if ( !info.Artist && !info.Album && !info.Track ) {
      msg = "Media information query failed";
    }
    this.$labels.Artist.innerHTML = info.Artist || msg;
    this.$labels.Album.innerHTML  = info.Album  || OSjs.Utils.dirname(this.currentFilename);
    this.$labels.Track.innerHTML  = info.Track  || OSjs.Utils.filename(this.currentFilename);
    this.updateTime(ev, slider);

    if ( slider ) {
      slider.min = 0;
      slider.max = 0;
      slider.setValue(0);
    }
  };

  ApplicationMusicPlayerWindow.prototype.updateTime = function(ev, slider, error) {
    if ( this.seeking ) return;
    if ( !this.$audio ) return;
    ev = ev || window.event;

    var total   = error ? 0 : this.$audio.duration;
    var current = error ? 0 : this.$audio.currentTime;
    var unknown = false;

    if ( isNaN(current) || !isFinite(current) ) current = 0.0;
    if ( isNaN(total) || !isFinite(total) ) {
      total = current;
      unknown = true;
    }

    var ftotal   = formatTime(total);
    var fcurrent = formatTime(current);
    if ( unknown ) {
      ftotal = '-' + ftotal + ' (seek unavailable in format)';
    }
    this.$labels.Time.innerHTML = fcurrent  + " / " + ftotal;

    if ( slider ) {
      slider.max = Math.round(total);
      slider.setValue(Math.round(current));
    }
  };

  ApplicationMusicPlayerWindow.prototype.seek = function(val) {
    this.seeking = true;
    try {
      this.$audio.currentTime = val;
    } catch ( e ) {
      console.warn("Failed to seek", e, val);
    }

    this.seeking = false;
  };

  /////////////////////////////////////////////////////////////////////////////
  // APPLICATION
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Application
   */
  var ApplicationMusicPlayer = function(args, metadata) {
    if ( !OSjs.Utils.getCompability().audio ) {
      throw "Your platform does not support Audio :(";
    }
    Application.apply(this, ['ApplicationMusicPlayer', args, metadata]);
    this.__dname = 'MusicPlayer';
  };

  ApplicationMusicPlayer.prototype = Object.create(Application.prototype);

  ApplicationMusicPlayer.prototype.destroy = function() {
    return Application.prototype.destroy.apply(this, []);
  };

  ApplicationMusicPlayer.prototype.init = function(core, session) {
    Application.prototype.init.apply(this, arguments);
    var self = this;

    this._addWindow(new ApplicationMusicPlayerWindow(this));

    var path = this._getArgument('file');
    var mime = this._getArgument('mime');
    if ( path ) {
      this.play(path, mime);
    }
  };

  ApplicationMusicPlayer.prototype._onMessage = function(obj, msg, args) {
    Application.prototype._onMessage.apply(this, arguments);

    if ( msg == 'destroyWindow' && obj._name === 'ApplicationMusicPlayerWindow' ) {
      this.destroy();
    } else if ( msg == 'attention' && args ) {
      this.play(args.file, args.mime);
    }
  };

  ApplicationMusicPlayer.prototype.play = function(filename, mime) {
    mime = mime || '';
    if ( !mime.match(/^audio/) ) {
      var msg = "The audio type is not supported: " + mime;
      var win = this._getWindow('ApplicationMusicPlayerWindow');
      win._error("Music Player error", "Failed to play file", msg);
      return;
    }

    var win = this._getWindow('ApplicationMusicPlayerWindow');
    if ( win ) {
      if ( win.play(filename, mime) ) {
        (function() {})();
      }
    }

    this._setArgument('file', filename);
    this._setArgument('mime', mime);
  };

  ApplicationMusicPlayer.prototype.info = function(filename) {
    var win = this._getWindow('ApplicationMusicPlayerWindow');
    if ( win ) {
      this._call('info', {filename: filename}, function(res) {
        var info = (res && res.result) ? res.result : null;
        win.updateInfo(null, info);
      });
    }
  };

  //
  // EXPORTS
  //
  OSjs.Applications = OSjs.Applications || {};
  OSjs.Applications.ApplicationMusicPlayer = ApplicationMusicPlayer;

})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Core.GUI, OSjs.Core.Dialogs);
<commit_msg>MusicPlayer: Error handling (3)<commit_after>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2013, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Application, Window, GUI, Dialogs) {

  function formatTime(secs) {
    var hr  = Math.floor(secs / 3600);
    var min = Math.floor((secs - (hr * 3600))/60);
    var sec = Math.floor(secs - (hr * 3600) -  (min * 60));

    if (min < 10){
      min = "0" + min;
    }
    if (sec < 10){
      sec  = "0" + sec;
    }

    return min + ':' + sec;
  }

  /////////////////////////////////////////////////////////////////////////////
  // WINDOWS
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Main Window
   */
  var ApplicationMusicPlayerWindow = function(app) {
    Window.apply(this, ['ApplicationMusicPlayerWindow', {width: 322, height: 225}, app]);

    this.title            = "Music Player";
    this.$buttons         = {};
    this.$labels          = {};
    this.$audio           = null;
    this.currentFilename  = '';
    this.seeking          = false;

    // Set window properties here
    this._title = this.title;
    this._icon  = "status/audio-volume-high.png";

    this._properties.allow_drop     = true;
    this._properties.allow_resize   = false;
    this._properties.allow_maximize = false;
  };

  ApplicationMusicPlayerWindow.prototype = Object.create(Window.prototype);

  ApplicationMusicPlayerWindow.prototype.init = function(wmRef, app) {
    var root = Window.prototype.init.apply(this, arguments);
    var self = this;

    var _createButton = function(img, onclick) {
      var b = document.createElement('button');
      var i = document.createElement('img');
      i.alt = '';
      i.src = OSjs.API.getThemeResource('actions/' + img + '.png', 'icon', '32x32');
      b.onclick = onclick;
      b.disabled = "disabled";
      b.appendChild(i);

      self.$buttons[img.split('_')[1]] = b;

      return b;
    };

    var menuBar = this._addGUIElement(new OSjs.GUI.MenuBar('ApplicationTextpadMenuBar'), root);
    menuBar.addItem("File", [
      {title: 'Open', name: 'Open', onClick: function() {
        app._createDialog('File', [{type: 'open', mimes: ['^audio']}, function(btn, fname, fmime) {
          if ( btn !== 'ok' ) return;
          app.play(fname, fmime);
        }], self);
      }},
      {title: 'Close', name: 'Close', onClick: function() {
        self._close();
      }}
    ]);

    var container = document.createElement('div');
    container.className = 'Container';

    // Audio
    this.$audio = document.createElement('audio');
    this.$audio.style.display = 'none';
    this.$audio.style.position = 'absolute';
    this.$audio.style.top = '-10000px';
    this.$audio.style.left = '-10000px';

    // Info
    var info = document.createElement('div');
    info.className = 'Info';

    var lblArtist = document.createElement('div');
    var spanArtist = document.createElement('span');
    var infoArtist = document.createElement('span');
    spanArtist.className = 'Label';
    spanArtist.innerHTML = 'Artist';
    infoArtist.innerHTML = '-';
    lblArtist.appendChild(spanArtist);
    lblArtist.appendChild(infoArtist);
    info.appendChild(lblArtist);
    this.$labels.Artist = infoArtist;

    var lblAlbum = document.createElement('div');
    var spanAlbum = document.createElement('span');
    var infoAlbum = document.createElement('span');
    spanAlbum.className = 'Label';
    spanAlbum.innerHTML = 'Album';
    infoAlbum.innerHTML = '-';
    lblAlbum.appendChild(spanAlbum);
    lblAlbum.appendChild(infoAlbum);
    info.appendChild(lblAlbum);
    this.$labels.Album = infoAlbum;

    var lblTrack = document.createElement('div');
    var spanTrack = document.createElement('span');
    var infoTrack = document.createElement('span');
    spanTrack.className = 'Label';
    spanTrack.innerHTML = 'Track';
    infoTrack.innerHTML = '-';
    lblTrack.appendChild(spanTrack);
    lblTrack.appendChild(infoTrack);
    info.appendChild(lblTrack);
    this.$labels.Track = infoTrack;

    var lblTime = document.createElement('div');
    var spanTime = document.createElement('span');
    var infoTime = document.createElement('span');
    spanTime.className = 'Label';
    spanTime.innerHTML = 'Time';
    infoTime.innerHTML = '00:00 / 00:00';
    lblTime.appendChild(spanTime);
    lblTime.appendChild(infoTime);
    info.appendChild(lblTime);
    this.$labels.Time = infoTime;

    // Buttons
    var buttons = document.createElement('div');
    buttons.className = 'Buttons';

    buttons.appendChild(_createButton('player_start', function(ev) {
    }));
    buttons.appendChild(_createButton('player_rew', function(ev) {
    }));
    buttons.appendChild(_createButton('player_play', function(ev) {
      self.$audio.play();
    }));
    buttons.appendChild(_createButton('player_pause', function(ev) {
      self.$audio.pause();
    }));
    buttons.appendChild(_createButton('player_fwd', function(ev) {
    }));
    buttons.appendChild(_createButton('player_end', function(ev) {
    }));

    // Containers
    container.appendChild(info);
    var slider = this._addGUIElement(new OSjs.GUI.Slider('MusicPlayerSlider', {min:0, max:100, val:0}, function(val) {
      if ( val < 0 ) return;
      self.seek(val);
    }), container);
    container.appendChild(buttons);

    // FIXME: Remove event listeners
    this.$audio.addEventListener("loadeddata", function(ev) {
      self.updateInfo(ev, null, slider);
      app.info(self.currentFilename);
    });
    this.$audio.addEventListener("timeupdate", function(ev) {
      self.updateTime(ev, slider);
    });
    this.$audio.addEventListener("error", function(ev) {
      self.updateInfo(ev, null, slider);

      var msg;
      try {
        switch ( ev.target.error.code ) {
          case ev.target.error.MEDIA_ERR_ABORTED:
            msg = 'You aborted the video playback.';
            break;
          case ev.target.error.MEDIA_ERR_NETWORK:
            msg = 'A network error caused the audio download to fail.';
            break;
          case ev.target.error.MEDIA_ERR_DECODE:
            msg = 'The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.';
            break;
          case ev.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
            msg = 'The video audio not be loaded, either because the server or network failed or because the format is not supported.';
            break;
          default:
            msg = "Unknown error";
            break;
        }
      } catch ( e ) {
        msg = "Fatal error: " + e;
      }

      self._error("Music Player error", "Failed to play file", msg);
    }, true);

    root.appendChild(container);
    root.appendChild(this.$audio);
    return root;
  };

  ApplicationMusicPlayerWindow.prototype.destroy = function() {
    // Destroy custom objects etc. here

    Window.prototype.destroy.apply(this, arguments);
  };

  ApplicationMusicPlayerWindow.prototype._onDndEvent = function(ev, type, item, args) {
    Window.prototype._onDndEvent.apply(this, arguments);
    if ( type === 'itemDrop' && item ) {
      var data = item.data;
      if ( data && data.type === 'file' && data.mime ) {
        this._appRef.play(data.path, data.mime);
      }
    }
  };

  ApplicationMusicPlayerWindow.prototype.play = function(filename, mime) {
    this.currentFilename = filename;

    try {
      this.$labels.Arist.innerHTML = filename;
      this.$labels.Album.innerHTML = mime;
    } catch ( e ) {
      console.warn("Failed to set labels", e);
    }

    try {
      this.$buttons.play.removeAttribute('disabled');
      this.$buttons.pause.removeAttribute('disabled');
    } catch ( e ) {
      console.warn("Failed toggle buttons", e);
    }

    this.$audio.src         = OSjs.API.getResourceURL(filename);
    this.$audio.volume      = 1.0;

    this.$audio.play();

    this._setTitle(this.title + ' - ' + OSjs.Utils.filename(filename));

    return true;
  };

  ApplicationMusicPlayerWindow.prototype.updateInfo = function(ev, info, slider) {
    if ( this.seeking ) return;
    if ( !this.$audio ) return;
    info = info || {};
    var msg = '-';
    if ( !info.Artist && !info.Album && !info.Track ) {
      msg = "Media information query failed";
    }
    this.$labels.Artist.innerHTML = info.Artist || msg;
    this.$labels.Album.innerHTML  = info.Album  || OSjs.Utils.dirname(this.currentFilename);
    this.$labels.Track.innerHTML  = info.Track  || OSjs.Utils.filename(this.currentFilename);
    this.updateTime(ev, slider);

    if ( slider ) {
      slider.min = 0;
      slider.max = 0;
      slider.setValue(0);
    }
  };

  ApplicationMusicPlayerWindow.prototype.updateTime = function(ev, slider, error) {
    if ( this.seeking ) return;
    if ( !this.$audio ) return;
    ev = ev || window.event;

    var total   = error ? 0 : this.$audio.duration;
    var current = error ? 0 : this.$audio.currentTime;
    var unknown = false;

    if ( isNaN(current) || !isFinite(current) ) current = 0.0;
    if ( isNaN(total) || !isFinite(total) ) {
      total = current;
      unknown = true;
    }

    var ftotal   = formatTime(total);
    var fcurrent = formatTime(current);
    if ( unknown ) {
      ftotal = '-' + ftotal + ' (seek unavailable in format)';
    }
    this.$labels.Time.innerHTML = fcurrent  + " / " + ftotal;

    if ( slider ) {
      slider.max = Math.round(total);
      slider.setValue(Math.round(current));
    }
  };

  ApplicationMusicPlayerWindow.prototype.seek = function(val) {
    this.seeking = true;
    try {
      this.$audio.currentTime = val;
    } catch ( e ) {
      console.warn("Failed to seek", e, val);
    }

    this.seeking = false;
  };

  /////////////////////////////////////////////////////////////////////////////
  // APPLICATION
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Application
   */
  var ApplicationMusicPlayer = function(args, metadata) {
    if ( !OSjs.Utils.getCompability().audio ) {
      throw "Your platform does not support Audio :(";
    }
    Application.apply(this, ['ApplicationMusicPlayer', args, metadata]);
    this.__dname = 'MusicPlayer';
  };

  ApplicationMusicPlayer.prototype = Object.create(Application.prototype);

  ApplicationMusicPlayer.prototype.destroy = function() {
    return Application.prototype.destroy.apply(this, []);
  };

  ApplicationMusicPlayer.prototype.init = function(core, session) {
    Application.prototype.init.apply(this, arguments);
    var self = this;

    this._addWindow(new ApplicationMusicPlayerWindow(this));

    var path = this._getArgument('file');
    var mime = this._getArgument('mime');
    if ( path ) {
      this.play(path, mime);
    }
  };

  ApplicationMusicPlayer.prototype._onMessage = function(obj, msg, args) {
    Application.prototype._onMessage.apply(this, arguments);

    if ( msg == 'destroyWindow' && obj._name === 'ApplicationMusicPlayerWindow' ) {
      this.destroy();
    } else if ( msg == 'attention' && args ) {
      this.play(args.file, args.mime);
    }
  };

  ApplicationMusicPlayer.prototype.play = function(filename, mime) {
    mime = mime || '';
    if ( !mime.match(/^audio/) ) {
      var msg = "The audio type is not supported: " + mime;
      var win = this._getWindow('ApplicationMusicPlayerWindow');
      win._error("Music Player error", "Failed to play file", msg);
      return;
    }

    var win = this._getWindow('ApplicationMusicPlayerWindow');
    if ( win ) {
      if ( win.play(filename, mime) ) {
        (function() {})();
      }
    }

    this._setArgument('file', filename);
    this._setArgument('mime', mime);
  };

  ApplicationMusicPlayer.prototype.info = function(filename) {
    var win = this._getWindow('ApplicationMusicPlayerWindow');
    if ( win ) {
      this._call('info', {filename: filename}, function(res) {
        var info = (res && res.result) ? res.result : null;
        win.updateInfo(null, info);
      });
    }
  };

  //
  // EXPORTS
  //
  OSjs.Applications = OSjs.Applications || {};
  OSjs.Applications.ApplicationMusicPlayer = ApplicationMusicPlayer;

})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Core.GUI, OSjs.Core.Dialogs);
<|endoftext|>


<commit_before>
(function(){
    "use strict";

    if(!global.cloudcmd)
        return console.log(
             '# appcache.js'                                    + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with Aplication Cache.'           + '\n'  +
             '# If you wont to see at work set appcache: true'  + '\n'  +
             '# in config.json and start cloudcmd.js'           + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,

    /* varible contain all watched file names
     * {name: true}
     */
        FileNames           = {},
        NamesList_s         = '',
        FallBack_s         = '',

    /* function thet use for crossplatform
     * access to fs.watch or fs.watchFile function
     */
        fs_watch            = null,
        on_fs_watch         = null,
        firstFileRead_b     = true,
        Manifest = '';

    setWatachFunctions();

    /* function add file or files to manifest
     * Examples:
     * exports.addFiles('jquery.js'),
     * exports.addFiles(['jquery.js', 'client.js']);
     * exports.addFiles([{'http://cdn.jquery/jq.js':'jquery.js'}, 'client.js']);
     */
    exports.addFiles = function(pFileNames) {
        var i, n, lName, lCurrentName,
            watch = exports.watch;

        /* if a couple files */
        if (Util.isArray(pFileNames)) {
            n = pFilesNames.length;

            for (i = 0; i < n; i++) {
                /* if fallback setted up */
                lCurrentName = pFileNames[i];

                if (Util.isObject(lCurrentName))
                    for(lName in lCurrentName) {
                        FallBack_s += lName + ' ' + lCurrentName[lName] + '\n';
                        watch(lCurrentName[lName]);
                    }
                else
                    watch(pFileNames[i]);
            }
        } else
            watch(pFileNames);

    };

    exports.createManifest = function(){
        var lAllNames = main.require('node_modules/minify/hashes');
        if(lAllNames)
            for(var lName in lAllNames){
                if(lName.indexOf('min') > 0)
                    lName = 'node_modules/minify/min/' + lName;
                exports.watch(lName);
            }
        processManifest();
    };

    exports.watch = function(pFileName){
        Util.log(pFileName + ' is watched');

        if(!FileNames[pFileName] &&
            pFileName !== './cloudcmd.appcache'){

            /* adding try...catch
             * if watched files would be more then system limit
             */
            var lWatch_f = function(){
                Util.tryCatch(function(){
                    fs_watch(pFileName, on_fs_watch(pFileName));
                });
            };

            /* if file.exists function exist and
             * file actually exists
             */
            if(fs.exists)
                fs.exists(pFileName, lWatch_f);
            else lWatch_f();

            NamesList_s += pFileName + '\n';
            FileNames[pFileName] = true;
        }
        else if(firstFileRead_b){
            processManifest();
            firstFileRead_b = false;
        }
    };

    function setWatachFunctions(){
        if(main.WIN32){
            /* good on windows  */
            fs_watch    = fs.watch;
            on_fs_watch = onWatch;
        }
        else{
            /* good on linux    */
            fs_watch    = fs.watchFile;
            on_fs_watch = onWatchFile;
        }

    }

    function onWatch (){
        return function(pEvent, pFileName){
            Util.log(pEvent);
            Util.log('file ' + pFileName + ' is changed');
            processManifest();
        };
    }

    function onWatchFile(pFileName){
        return function(pCurr, pPrev){
            if(pCurr.mtime !== pPrev.mtime){
                Util.log('file ' + pFileName + ' is changed');
                processManifest();
            }
        };
    }

    function processManifest(){
        Manifest = 'CACHE MANIFEST\n'   +
            '#' + new Date()   + '\n'   +
            'CACHE:\n'                  +
            NamesList_s                 +
            'NETWORK:\n'                +
            '*\n'                       +
            'FALLBACK:\n'               +
            FallBack_s;

        fs.writeFile('cloudcmd.appcache', Manifest, function(){
            Util.log('cloudcmd.appcache refreshed');
        });
    }
})();
<commit_msg>chore(appcache) add " "<commit_after>
(function(){
    "use strict";

    if (!global.cloudcmd)
        return console.log(
             '# appcache.js'                                    + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with Aplication Cache.'           + '\n'  +
             '# If you wont to see at work set appcache: true'  + '\n'  +
             '# in config.json and start cloudcmd.js'           + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,

    /* varible contain all watched file names
     * {name: true}
     */
        FileNames           = {},
        NamesList_s         = '',
        FallBack_s         = '',

    /* function thet use for crossplatform
     * access to fs.watch or fs.watchFile function
     */
        fs_watch            = null,
        on_fs_watch         = null,
        firstFileRead_b     = true,
        Manifest = '';

    setWatachFunctions();

    /* function add file or files to manifest
     * Examples:
     * exports.addFiles('jquery.js'),
     * exports.addFiles(['jquery.js', 'client.js']);
     * exports.addFiles([{'http://cdn.jquery/jq.js':'jquery.js'}, 'client.js']);
     */
    exports.addFiles = function(pFileNames) {
        var i, n, lName, lCurrentName,
            watch = exports.watch;

        /* if a couple files */
        if (Util.isArray(pFileNames)) {
            n = pFilesNames.length;

            for (i = 0; i < n; i++) {
                /* if fallback setted up */
                lCurrentName = pFileNames[i];

                if (Util.isObject(lCurrentName))
                    for (lName in lCurrentName) {
                        FallBack_s += lName + ' ' + lCurrentName[lName] + '\n';
                        watch(lCurrentName[lName]);
                    }
                else
                    watch(pFileNames[i]);
            }
        } else
            watch(pFileNames);

    };

    exports.createManifest = function(){
        var lAllNames = main.require('node_modules/minify/hashes');

        if (lAllNames)
            for (var lName in lAllNames){
                if (lName.indexOf('min') > 0)
                    lName = 'node_modules/minify/min/' + lName;
                exports.watch(lName);
            }
        processManifest();
    };

    exports.watch = function(pFileName) {
        Util.log(pFileName + ' is watched');

        if (!FileNames[pFileName] &&
            pFileName !== './cloudcmd.appcache') {

            /* adding try...catch
             * if watched files would be more then system limit
             */
            var lWatch_f = function() {
                Util.tryCatch(function() {
                    fs_watch(pFileName, on_fs_watch(pFileName));
                });
            };

            /* if file.exists function exist and
             * file actually exists
             */
            if (fs.exists)
                fs.exists(pFileName, lWatch_f);
            else
                lWatch_f();

            NamesList_s += pFileName + '\n';
            FileNames[pFileName] = true;
        } else if (firstFileRead_b) {
            processManifest();
            firstFileRead_b = false;
        }
    };

    function setWatachFunctions() {
        if (main.WIN32) {
            /* good on windows  */
            fs_watch    = fs.watch;
            on_fs_watch = onWatch;
        }
        else {
            /* good on linux    */
            fs_watch    = fs.watchFile;
            on_fs_watch = onWatchFile;
        }

    }

    function onWatch () {
        return function(pEvent, pFileName) {
            Util.log(pEvent);
            Util.log('file ' + pFileName + ' is changed');
            processManifest();
        };
    }

    function onWatchFile(pFileName) {
        return function(pCurr, pPrev) {
            if (pCurr.mtime !== pPrev.mtime) {
                Util.log('file ' + pFileName + ' is changed');
                processManifest();
            }
        };
    }

    function processManifest() {
        Manifest = 'CACHE MANIFEST\n'   +
            '#' + new Date()   + '\n'   +
            'CACHE:\n'                  +
            NamesList_s                 +
            'NETWORK:\n'                +
            '*\n'                       +
            'FALLBACK:\n'               +
            FallBack_s;

        fs.writeFile('cloudcmd.appcache', Manifest, function() {
            Util.log('cloudcmd.appcache refreshed');
        });
    }
})();
<|endoftext|>


<commit_before>/* eslint no-unused-vars: 0 */
'use strict';

const router = require('express').Router;

const app = router();
const ApiUser = require('../app/model').ApiUser;

const filters = require('./filters');

if (module.parent.exports.nunjucks) {
  Object.keys(filters).forEach(filter => {
    module.parent.exports.nunjucks.addFilter(filter, filters[filter]);
  });
}

app.use('/', (req, res, next) => {
  if (!req.session.auth.isAdmin) {
    return res.redirect('/');
  }

  return next();
});

app.get('/', (req, res) => res.redirect('/admin/users'));

app.get('/users', (req, res, next) => {
  ApiUser.find().limit(100).sort({ updated: -1 }).exec((err, apps) => {
    if (err) { return next(err); }
    return res.render('admin/users.html', { req, apps });
  });
});

module.exports = app;
<commit_msg>feat(admin): add 404 redirect to admin index<commit_after>/* eslint no-unused-vars: 0 */
'use strict';

const router = require('express').Router;

const app = router();
const ApiUser = require('../app/model').ApiUser;

const filters = require('./filters');

if (module.parent.exports.nunjucks) {
  Object.keys(filters).forEach(filter => {
    module.parent.exports.nunjucks.addFilter(filter, filters[filter]);
  });
}

app.use('/', (req, res, next) => {
  if (!req.session.auth.isAdmin) {
    return res.redirect('/');
  }

  return next();
});

app.get('/', (req, res) => res.redirect('/admin/users'));

app.get('/users', (req, res, next) => {
  ApiUser.find().limit(100).sort({ updated: -1 }).exec((err, apps) => {
    if (err) { return next(err); }
    return res.render('admin/users.html', { req, apps });
  });
});

app.get('*', (req, res) => res.redirect('/admin'));

module.exports = app;
<|endoftext|>