<commit_before>var _ = require('lodash');

var auth = require('../../lib/auth');
var db = require('../../db');
var user = require('../../lib/user');

module.exports = function(server) {

    // Sample usage:
    // % curl 'http://localhost:5000/user/search?_user=ssatoken'
    server.get({
        url: '/user/search',
        validation: {
            _user: {
                description: "A user's SSA token",
                isRequired: true
            },
            email: {
                description: 'Email to search for',
                isRequired: false
            },
            id: {
                description: 'User ID to search for',
                isRequired: false
            },
            q: {
                description: 'Email/user ID/username to search for',
                isRequired: false
            }
        }
    }, db.redisView(function(client, done, req, res) {
        var DATA = req.params;
        console.log(DATA);

        var lookup_email = DATA.email;
        var lookup_id = DATA.id;
        var lookup_q = DATA.q;
        var lookup = lookup_email || lookup_id || lookup_q;

        if (!lookup) {
            res.json(400, {error: 'Must provide either email or user ID'});
            done();
            return;
        }

        var _user = DATA._user;
        var email;
        if (!(email = auth.verifySSA(_user))) {
            res.json(403, {error: 'bad_user'});
            done();
            return;
        }

        // TODO: Allow searching by username.
        // (i.e., if no results for email, look by username, etc.)
        if (lookup_q) {
            if (_.isNumber(lookup_q)) {
                var lookup_id = lookup_q;
            } else {
                var lookup_email = lookup_q;
            }

            if (lookup_id) {
                // TODO: Exclude yourself from the object list.
                user.getPublicUserObjList(client, [lookup_id], function(objs) {
                    done();
                    res.json(objs);
                });
            }

            user.getUserIDFromEmail(client, lookup, function(err, obj) {
                if (err || !obj) {
                    res.json(400, {error: err || lookup_email ? 'bad_email' : 'bad_id'});
                    done();
                    return;
                }
                // TODO: Exclude yourself from the object list.
                user.getPublicUserObjList(client, [obj], function(objs) {
                    done();
                    res.json(objs);
                });
            });
        } else {
            // Return a single object.
            (lookup_email ? user.getUserFromEmail : user.getUserFromID)(client, lookup, function(err, obj) {
                if (err || !obj) {
                    res.json(400, {error: err || lookup_email ? 'bad_email' : 'bad_id'});
                    done();
                    return;
                }
                // TODO: Look up `id` from `getUserIDFromEmail` and compare.
                if (obj.email === email) {
                    res.json(400, {error: err || 'thats_you_silly'});
                    done();
                    return;
                }
                res.json(user.publicUserObj(obj));
                done();
            });
        }
    }));
};
<commit_msg>fix user/search nonsense<commit_after>var auth = require('../../lib/auth');
var db = require('../../db');
var user = require('../../lib/user');

module.exports = function(server) {

    // Sample usage:
    // % curl 'http://localhost:5000/user/search?_user=ssatoken'
    server.get({
        url: '/user/search',
        validation: {
            _user: {
                description: "A user's SSA token",
                isRequired: true
            },
            email: {
                description: 'Email to search for',
                isRequired: false
            },
            id: {
                description: 'User ID to search for',
                isRequired: false
            },
            q: {
                description: 'Email/user ID/username to search for',
                isRequired: false
            }
        }
    }, db.redisView(function(client, done, req, res) {
        var DATA = req.params;
        console.log(DATA);

        var lookup_email = DATA.email;
        var lookup_id = DATA.id;
        var lookup_q = DATA.q;
        var lookup = lookup_email || lookup_id || lookup_q;

        if (!lookup) {
            res.json(400, {error: 'Must provide either email or user ID'});
            done();
            return;
        }

        var _user = DATA._user;
        var email;
        if (!(email = auth.verifySSA(_user))) {
            res.json(403, {error: 'bad_user'});
            done();
            return;
        }

        // TODO: Allow searching by username.
        // (i.e., if no results for email, look by username, etc.)
        if (lookup_q) {
            user.getUserIDFromEmail(client, lookup, function(err, obj) {
                if (err || !obj) {
                    res.json(400, {error: err || lookup_email ? 'bad_email' : 'bad_id'});
                    done();
                    return;
                }
                // TODO: Exclude yourself from the object list.
                user.getPublicUserObjList(client, [obj], function(objs) {
                    done();
                    res.json(objs);
                });
            });
        } else {
            // Return a single object.
            (lookup_email ? user.getUserFromEmail : user.getUserFromID)(client, lookup, function(err, obj) {
                if (err || !obj) {
                    res.json(400, {error: err || lookup_email ? 'bad_email' : 'bad_id'});
                    done();
                    return;
                }
                // TODO: Look up `id` from `getUserIDFromEmail` and compare.
                if (obj.email === email) {
                    res.json(400, {error: err || 'thats_you_silly'});
                    done();
                    return;
                }
                res.json(user.publicUserObj(obj));
                done();
            });
        }
    }));
};
<|endoftext|>


<commit_before>const ndarray = require('ndarray')
const debug   = require('../debug').sub('voting', 'condorcets')
const EE      = require('events').EventEmitter

ndarray.zeros = require('zeros')
ndarray.show  = require('ndarray-show')
ndarray.ops   = require('ndarray-ops')

function baseMatrix(movies) {
	return ndarray.zeros([ movies.length, movies.length ])
}

module.exports = function(data) {
	const voting = new EE

	function update() {
		voting.matrix = voting.people.reduce(function(acc, val) {
			ndarray.ops.add(acc, acc, val)
			return acc
		}, baseMatrix(data.movies))

		debug('matrix:')
		if(debug.enabled) console.log(ndarray.show(voting.matrix))

		voting.results = []

		var maxVotes = 0
		for (var y = 0; y < voting.matrix.shape[1]; y++) {
			var votes = 0
			for(var x = 0; x < voting.matrix.shape[0]; x++) {
				votes += voting.matrix.get(x, y)
			}

			if(votes > maxVotes) {
				maxVotes = votes
				voting.results = []
			}
			if(votes >= maxVotes) {
				voting.results.push(y)
			}
		}

		if(maxVotes == 0)
			voting.results = []

		debug('results: %s', voting.results.map(function(id) {
			return data.movies[id].name
		}).join(', '))

		voting.emit('update')
	}

	voting.update = function(person) { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people[person.id] = generateMatrix(person, data.movies)
		update()

		process.nextTick(function() { cb(null) })
	} }

	voting.delete = function(person) { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people[person.id] = baseMatrix(data.movies)

		update()

		process.nextTick(function() { cb(null) })
	} }

	voting.reset = function() { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people = []
		voting.matrix = baseMatrix(data.movies)
		voting.results = []
		debug('reseting')

		process.nextTick(function() { cb(null) })
	} }

	return voting
}

function generateMatrix(person, movies) {
	const vote = person.vote

	const moviesOrder = {}
	movies.forEach(function(movie, id) {
		moviesOrder[id] = Infinity
	})
	vote.forEach(function(id, i) {
		moviesOrder[id] = i
	})
	debug(moviesOrder)

	const matrix = baseMatrix(movies)
	var val
	for(var x = 0; x < matrix.shape[0]; x++) {
		for(var y = 0; y < matrix.shape[1]; y++) {
			if(moviesOrder[y] < moviesOrder[x]) {
				val = 1
			} else {
				val = 0
			}
			matrix.set(x, y, val)
			debug.trace('setting %d (%d), %d (%d) to %d', x, moviesOrder[x], y, moviesOrder[y], val)
		}
	}
	debug('generated matrix for %s (%d):', person.name, person.id)
	if(debug.enabled) console.log(ndarray.show(matrix))
	return matrix
}<commit_msg>Fix condorcets method<commit_after>const ndarray = require('ndarray')
const debug   = require('../debug').sub('voting', 'condorcets')
const EE      = require('events').EventEmitter

ndarray.zeros = require('zeros')
ndarray.show  = require('ndarray-show')
ndarray.ops   = require('ndarray-ops')

function baseMatrix(movies) {
	return ndarray.zeros([ movies.length, movies.length ])
}

module.exports = function(data) {
	const voting = new EE

	function update() {
		voting.matrix = voting.people.reduce(function(acc, val) {
			ndarray.ops.add(acc, acc, val)
			return acc
		}, baseMatrix(data.movies))

		debug('matrix:')
		if(debug.enabled) console.log(ndarray.show(voting.matrix))

		voting.results = []

		const wins = {}
		data.movies.forEach(function(movie, id) {
			wins[id] = 0
		})

		for(var y = 0; y < voting.matrix.shape[1]; y++) {
			for(var x = 0; x < voting.matrix.shape[0]; x++) {
				if(x <= y) continue

				var runner   = voting.matrix.get(x, y)
				var opponent = voting.matrix.get(y, x)

				if(runner > opponent)
					wins[y] += 1
				else if(opponent > runner)
					wins[x] += 1

				debug.trace('%s (%d): %d | %s (%d): %d', data.movies[y].name, y, runner, data.movies[x].name, x, opponent)
			}
		}

		(function() {
			var maxWins = 0
			for(var id = 0; id < data.movies.length; id++) {
				if(wins[id] >= data.movies.length) {
					voting.results = [ id ]
					return
				} else if(wins[id] >= maxWins) {
					if(wins[id] > maxWins) {
						maxWins = wins[id]
						voting.results = []
					}

					voting.results.push(id)
				}
			}
		})()

		debug('wins:', wins)

		if(voting.results.length == data.movies.length)
			voting.results = []

		debug('results: %s', voting.results.map(function(id) {
			return data.movies[id].name
		}).join(', '))

		voting.emit('update')
	}

	voting.update = function(person) { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people[person.id] = generateMatrix(person, data.movies)
		update()

		process.nextTick(function() { cb(null) })
	} }

	voting.delete = function(person) { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people[person.id] = baseMatrix(data.movies)

		update()

		process.nextTick(function() { cb(null) })
	} }

	voting.reset = function() { return function(cb) {
		if(!cb) cb = function(err) { if(err) throw err }

		voting.people = []
		voting.matrix = baseMatrix(data.movies)
		voting.results = []
		debug('reseting')

		process.nextTick(function() { cb(null) })
	} }

	return voting
}

function generateMatrix(person, movies) {
	const vote = person.vote

	const moviesOrder = {}
	movies.forEach(function(movie, id) {
		moviesOrder[id] = Infinity
	})
	vote.forEach(function(id, i) {
		moviesOrder[id] = i
	})
	debug('movies order:', moviesOrder)

	const matrix = baseMatrix(movies)
	var val
	for(var x = 0; x < matrix.shape[0]; x++) {
		for(var y = 0; y < matrix.shape[1]; y++) {
			if(moviesOrder[y] < moviesOrder[x]) {
				val = 1
			} else {
				val = 0
			}
			matrix.set(x, y, val)
			debug.trace('setting %d (%d), %d (%d) to %d', x, moviesOrder[x], y, moviesOrder[y], val)
		}
	}
	debug('generated matrix for %s (%d):', person.name, person.id)
	if(debug.enabled) console.log(ndarray.show(matrix))
	return matrix
}<|endoftext|>


<commit_before>var pinguCtrl = app.controller('pinguCtrl', ['$scope', '$http', '$location', 'branches', 'reports', function ($scope, $http, $location, branches, reports) {
  $scope.branches = branches;
  $scope.reports = reports;

  $scope.newBranch = {
    branch_name:            '',
    branch_ip:              '',
    branch_service_number:  '',
    branch_service_type:    'Data',
    branch_access_type:     'ADSL',
    branch_bandwidth:       '512 Kbps'
  };
  $scope.report = {
    branch_id:  '',
    ticket:     '',
    alert:      false
  };
  $scope.editBranch = {};

  // socket connection is handled via big daddy i.e. appCtrl
  // everyone that is interested should be on the listen
  // this i think creates a neat interaction logic
  $scope.$on('NEW_BRANCH', function (event, newBranch) {
    $scope.branches.push(newBranch);
    $scope.$digest();
  });

  // we'll look through the list and update with the new info
  $scope.$on('UPDATED_BRANCH', function (event, updatedBranch) {
    for (index in $scope.branches) {
      if ($scope.branches[index].branch_id === updatedBranch.branch_id) {
        $scope.branches[index] = updatedBranch;
        $scope.$digest();
        break;
      }
    }
  });

  // branch deleted
  $scope.$on('DELETED_BRANCH', function (event, deletedBranchId) {
    for (index in $scope.branches) {
      if ($scope.branches[index].branch_id === deletedBranchId) {
        $scope.branches.splice(index, 1);
        $scope.$digest();
        break;
      }
    }
  });

  // ping result shows 100% loss
  $scope.$on('BLACK_HAWK_DOWN', function (event, data) {
    $('#black-hawk-down').modal();
    $scope.pingedBranch = data.branch;
    $scope.result = data.result;
    $scope.report = {
      branch_id:  data.branch.branch_id,
      ticket:     '',
      alert:      false
    };
    $scope.$digest();
  });

  // there's a logic collision
  // the app doesn't differentiate between a modal launched via ping
  // or manually, causing a report modal to close
  // on both situations --- this is an official TODO
  $scope.$on('AC-DC', function (event, data) {
    $('#black-hawk-down').modal('hide');
    $scope.report = {
      branch_id:  '',
      ticket:     '',
      alert:      false
    };
    $scope.reports.push(data);
    $scope.$digest();
  });

  // this is called when the form is added
  // on success, we'll send the ticket to ERYone via socket
  this.report = function () {
    $http.post('api/reports', $scope.report);
  };

  this.newBranchsubmit = function () {
    $http.post('api/branches', $scope.newBranch).success(function (data, status, headers, config) {
      $scope.branches.push(data.newBranch);
      $('#new-branch-modal').modal('hide');
      $scope.newBranch = {
        branch_name:            '',
        branch_ip:              '',
        branch_service_number:  '',
        branch_service_type:    'Data',
        branch_access_type:     'ADSL',
        branch_bandwidth:       '512 Kbps'
      };
    });
  };

  this.editBranch = function (branch) {
    $scope.editBranch = angular.copy(branch);
    $('#edit-branch-modal').modal();
  };

  this.deleteBranch = function () {
    // upon success, we'll go after the delete branch and well...
    // splice the shit out it
    // the rest will be informed to do the same via 'DELETED_BRANCH'
    $http.delete('api/branches/'+ $scope.editBranch.branch_id).success(function (data, status, headers, config) {
      for (index in $scope.branches) {
        if ($scope.branches[index].branch_id === data.deletedBranchId) {
          $scope.branches.splice(index, 1);
          break;
        }
      }

      $('#edit-branch-modal').modal('hide');
    });
  };

  // for re-usability purposes we're going to "tweak" the ip address
  // and yes the server WILL make sure it's an IP so we don't get shocked ;)
  this.ping = function (branch) {
    var ip = branch.branch_ip.split(/\./);

    for (index in ip) {
      ip[index] = Number(ip[index]);
    }

    ip[3]++; // well it's an IP ain't it
    ip = ip.join('.');

    // Pingu will get back to us (or ERYone) via socket
    $http.post('api/ping', {ip: ip, branch: branch});
  };

  this.editBranchsubmit = function () {
    $http.put('api/branches/'+ $scope.editBranch.branch_id, $scope.editBranch).success(function (data, status, headers, config) {
      for (index in $scope.branches) {
        if ($scope.branches[index].branch_id === data.updatedBranch.branch_id) {
          $scope.branches[index] = data.updatedBranch;
          break;
        }
      }

      $('#edit-branch-modal').modal('hide');
    });
  };

  $scope.pinguCtrl = this;

  // a couple of DOM bindings to make the page look pretty
  $('.branch-container, .report-container').css({
    'height': $(window).height() - 80 + 'px'
  });

  $('.branch-container, .report-container').niceScroll({
    zindex: 1,
    cursorcolor: 'rgba(51, 51, 51, 0.75)',
    cursorwidth: '4px',
    cursorborder: '0px solid rgba(0, 0, 0, 0)',
    cursorborderradius: '0px',
    hidecursordelay: 1000
  });

  $(window).resize(function () {
    $('.branch-container, .report-container').css({
      'height': $(window).height() - 80 + 'px'
    });
  });

}]);

pinguCtrl.socket = function ($q, $rootScope, $http, $location) {
  var defer = $q.defer();

  // making sure our session exits
  $http.get('api/login').success(function (data, status, headers, config) {
    // if all is good, we'll [re]attempt socket connection
    $rootScope.connect();
    defer.resolve();
  }).error(function (data, status, headers, config) {
    // ABANDON SHIP!
    $location.path('/login');
    // a bit of Star Wars shit right there
    // i just made a lot of Nerdemies (Nerd + enemies) - patent pending
    defer.reject({msg: 'session found not, Luke bad'});
  });

  return defer.promise;
};

pinguCtrl.branches = function ($q, $http) {
  var defer = $q.defer();

  $http.get('api/branches').success(function (data, status, headers, config) {
    defer.resolve(data);
  }).error(function (data, status, headers, config) {
    defer.reject(data);
  });

  return defer.promise;
};

pinguCtrl.reports = function ($q, $http) {
  var defer = $q.defer();

  $http.get('api/reports').success(function (data, status, headers, config) {
    defer.resolve(data);
  }).error(function (data, status, headers, config) {
    defer.reject(data);
  });

  return defer.promise;
};
<commit_msg>10-4<commit_after>var pinguCtrl = app.controller('pinguCtrl', ['$scope', '$http', '$location', 'branches', 'reports', function ($scope, $http, $location, branches, reports) {
  $scope.branches = branches;
  $scope.reports = reports;
  $scope.newBranch = {
    branch_name:            '',
    branch_ip:              '',
    branch_service_number:  '',
    branch_service_type:    'Data',
    branch_access_type:     'ADSL',
    branch_bandwidth:       '512 Kbps'
  };
  $scope.report = {
    branch_id:  '',
    ticket:     '',
    alert:      false
  };
  $scope.branch10_4 = {};

  // socket connection is handled via big daddy i.e. appCtrl
  // everyone that is interested should be on the listen
  // this i think creates a neat interaction logic
  $scope.$on('NEW_BRANCH', function (event, newBranch) {
    $scope.branches.push(newBranch);
    $scope.$digest();
  });

  // we'll look through the list and update with the new info
  $scope.$on('UPDATED_BRANCH', function (event, updatedBranch) {
    for (index in $scope.branches) {
      if ($scope.branches[index].branch_id === updatedBranch.branch_id) {
        $scope.branches[index] = updatedBranch;
        $scope.$digest();
        break;
      }
    }
  });

  // branch deleted
  $scope.$on('DELETED_BRANCH', function (event, deletedBranchId) {
    for (index in $scope.branches) {
      if ($scope.branches[index].branch_id === deletedBranchId) {
        $scope.branches.splice(index, 1);
        $scope.$digest();
        break;
      }
    }
  });

  // ping result shows 100% loss
  $scope.$on('BLACK_HAWK_DOWN', function (event, data) {
    $scope.branch10_4 = data.branch;
    // not in-use for the time being
    // but it's good to know it's there
    $scope.result = data.result;
    $scope.report = {
      branch_id:  data.branch.branch_id,
      ticket:     '',
      alert:      false
    };
    $scope.$digest();
    $('#black-hawk-down').modal();
  });

  // there's a logic collision
  // the app doesn't differentiate between a modal launched via ping
  // or manually, causing a report modal to close
  // on both situations --- this is an official TODO
  $scope.$on('AC-DC', function (event, data) {
    $('#black-hawk-down').modal('hide');
    $scope.report = {
      branch_id:  '',
      ticket:     '',
      alert:      false
    };
    $scope.reports.push(data);
    $scope.$digest();
  });

  this.newBranchsubmit = function () {
    $http.post('api/branches', $scope.newBranch).success(function (data, status, headers, config) {
      $scope.branches.push(data.newBranch);
      $('#new-branch-modal').modal('hide');
      $scope.newBranch = {
        branch_name:            '',
        branch_ip:              '',
        branch_service_number:  '',
        branch_service_type:    'Data',
        branch_access_type:     'ADSL',
        branch_bandwidth:       '512 Kbps'
      };
    });
  };

  this.editBranchsubmit = function () {
    $http.put('api/branches/'+ $scope.branch10_4.branch_id, $scope.branch10_4).success(function (data, status, headers, config) {
      for (index in $scope.branches) {
        if ($scope.branches[index].branch_id === data.updatedBranch.branch_id) {
          $scope.branches[index] = data.updatedBranch;
          break;
        }
      }

      $('#edit-branch-modal').modal('hide');
    });
  };

  this.deleteBranchSubmit = function () {
    // upon success, we'll go after the delete branch and well...
    // splice the shit out it
    // the rest will be informed to do the same via 'DELETED_BRANCH'
    $http.delete('api/branches/'+ $scope.branch10_4.branch_id).success(function (data, status, headers, config) {
      for (index in $scope.branches) {
        if ($scope.branches[index].branch_id === data.deletedBranchId) {
          $scope.branches.splice(index, 1);
          break;
        }
      }

      $('#edit-branch-modal').modal('hide');
    });
  };

  // this is called when the form is added
  // on success, we'll send the ticket to ERYone via socket
  this.report = function () {
    $http.post('api/reports', $scope.report);
  };

  // we're going to use California's five-o codes
  this.cali = function (branch, mode) {
    $scope.branch10_4 = angular.copy(branch);

    switch(mode) {
      // kidnapping attempt
      // user just wants her number --- riiiiiiiiiiiiiiight
      case '207A':
        $('#edit-branch-modal').modal();
      break;

      // drunk
      // user JUST wants to report a branch
      // PS
      // this is where the logic collision occurs, black hawk down will
      // be launched --- which can be closed with AC-DC event is emitted
      case '390':
        $scope.report = {
          branch_id:  $scope.branch10_4.branch_id,
          ticket:     '',
          alert:      false
        };
        $('#black-hawk-down').modal();
      break;
    }
  };

  // for re-usability purposes we're going to "tweak" the ip address
  // and yes the server WILL make sure it's an IP so we don't get shocked ;)
  this.ping = function (branch) {
    var ip = branch.branch_ip.split(/\./);

    for (index in ip) {
      ip[index] = Number(ip[index]);
    }

    ip[3]++; // well it's an IP ain't it
    ip = ip.join('.');

    // Pingu will get back to us (or ERYone) via socket
    $http.post('api/ping', {ip: ip, branch: branch});
  };

  $scope.pinguCtrl = this;

  // a couple of DOM bindings to make the page look pretty
  $('.branch-container, .report-container').css({
    'height': $(window).height() - 80 + 'px'
  });

  $('.branch-container, .report-container').niceScroll({
    zindex: 1,
    cursorcolor: 'rgba(51, 51, 51, 0.75)',
    cursorwidth: '4px',
    cursorborder: '0px solid rgba(0, 0, 0, 0)',
    cursorborderradius: '0px',
    hidecursordelay: 1000
  });

  $(window).resize(function () {
    $('.branch-container, .report-container').css({
      'height': $(window).height() - 80 + 'px'
    });
  });

}]);

pinguCtrl.socket = function ($q, $rootScope, $http, $location) {
  var defer = $q.defer();

  // making sure our session exits
  $http.get('api/login').success(function (data, status, headers, config) {
    // if all is good, we'll [re]attempt socket connection
    $rootScope.connect();
    defer.resolve();
  }).error(function (data, status, headers, config) {
    // ABANDON SHIP!
    $location.path('/login');
    // a bit of Star Wars shit right there
    // i just made a lot of Nerdemies (Nerd + enemies) - patent pending
    defer.reject({msg: 'session found not, Luke bad'});
  });

  return defer.promise;
};

pinguCtrl.branches = function ($q, $http) {
  var defer = $q.defer();

  $http.get('api/branches').success(function (data, status, headers, config) {
    defer.resolve(data);
  }).error(function (data, status, headers, config) {
    defer.reject(data);
  });

  return defer.promise;
};

pinguCtrl.reports = function ($q, $http) {
  var defer = $q.defer();

  $http.get('api/reports').success(function (data, status, headers, config) {
    defer.resolve(data);
  }).error(function (data, status, headers, config) {
    defer.reject(data);
  });

  return defer.promise;
};
<|endoftext|>


<commit_before>
app.controller( 'MapIndexController', function( $scope, PeliasGeoJsonLayerManager ) {

  // Helper Functions ( For Context Menu )
  function showCoordinates (e) { alert( e.latlng ); }
  function centerMap (e) { map.panTo(e.latlng); }
  function zoomIn (e) { map.zoomIn(); }
  function zoomOut (e) { map.zoomOut(); }

  // Init map
  var map = L.map( 'map', {
    zoomControl: false,
    contextmenu: true,
    contextmenuWidth: 140,
    contextmenuItems: [{
      text: 'Show coordinates',
      callback: showCoordinates
    }, {
      text: 'Center map here',
      callback: centerMap
    }, '-', {
      text: 'Zoom in',
      icon: 'images/zoom-in.png',
      callback: zoomIn
    }, {
      text: 'Zoom out',
      icon: 'images/zoom-out.png',
      callback: zoomOut
    }]
  });

  // Controls
  map.addControl(new L.Control.ZoomMin());
  L.control.locate().addTo(map);
  // L.control.fullscreen().addTo(map);
  L.Marker.include(L.Mixin.ContextMenu);

  // Configure map
  map.addLayer( L.tileLayer.provider( 'MapBox.missinglink.i3ook7ke' ) );
  var layerManager = PeliasGeoJsonLayerManager.bind( map );

  // Host String
  var hostMask = 'http://:domain::port:/:st:/:est:/{z}/{y}/{x}';

  // NOTE: this doesn't work as-of-yet due to cross-origin issues.
  // Can be fixed by implimenting JSONP
  // if( document.domain === 'pelias.wiz.co.nz' ){
  //   // Use subdomains if configured at the DNS level
  //   hostMask = 'http://{s}.:domain::port:/:st:/:est:/{z}/{y}/{x}';
  // }

  var hostString = hostMask.replace( ':domain:', document.domain )
                           .replace( ':port:', location.port ? ':' + location.port : '' );

  // Geonames
  layerManager.register( 'geonames.all',
    hostString.replace(':st:','points').replace(':est:','geoname'),
    { color: '#D00' }
  ).disable( 'geonames.all' );

  // Admin0
  layerManager.register( 'quattroshapes.admin0',
    hostString.replace(':st:','shapes').replace(':est:','admin0'),
    { color: '#FF00FF' }
  ).enable( 'quattroshapes.admin0' );

  // Admin1
  layerManager.register( 'quattroshapes.admin1',
    hostString.replace(':st:','shapes').replace(':est:','admin1'),
    { color: '#00FFFF' }
  ).enable( 'quattroshapes.admin1' );

  // Admin2
  layerManager.register( 'quattroshapes.admin2',
    hostString.replace(':st:','shapes').replace(':est:','admin2'),
    { color: '#FFFF00' }
  ).enable( 'quattroshapes.admin2' );

  // Local Admin
  layerManager.register( 'quattroshapes.localadmin',
    hostString.replace(':st:','shapes').replace(':est:','local_admin'),
    { color: '#0D0' }
  ).enable( 'quattroshapes.localadmin' );

  // Locality
  layerManager.register( 'quattroshapes.locality',
    hostString.replace(':st:','shapes').replace(':est:','locality'),
    { color: '#00D' }
  ).enable( 'quattroshapes.locality' );

  // Neighborhood
  layerManager.register( 'quattroshapes.neighborhood',
    hostString.replace(':st:','shapes').replace(':est:','neighborhood'),
    { color: '#D00' }
  ).enable( 'quattroshapes.neighborhood' );

  // Manually add layer
  // map.addLayer( PeliasGeoJsonLayer( '/shapes/locality/{z}/{y}/{x}' ) );

  // Center map
  // map.setView( [ 51.505, -0.124 ], 12 ); // London
  map.setView( [ 40.75558, -74.00391 ], 8 ); // New York

});
<commit_msg>re-enable subdomains<commit_after>
app.controller( 'MapIndexController', function( $scope, PeliasGeoJsonLayerManager ) {

  // Helper Functions ( For Context Menu )
  function showCoordinates (e) { alert( e.latlng ); }
  function centerMap (e) { map.panTo(e.latlng); }
  function zoomIn (e) { map.zoomIn(); }
  function zoomOut (e) { map.zoomOut(); }

  // Init map
  var map = L.map( 'map', {
    zoomControl: false,
    contextmenu: true,
    contextmenuWidth: 140,
    contextmenuItems: [{
      text: 'Show coordinates',
      callback: showCoordinates
    }, {
      text: 'Center map here',
      callback: centerMap
    }, '-', {
      text: 'Zoom in',
      icon: 'images/zoom-in.png',
      callback: zoomIn
    }, {
      text: 'Zoom out',
      icon: 'images/zoom-out.png',
      callback: zoomOut
    }]
  });

  // Controls
  map.addControl(new L.Control.ZoomMin());
  L.control.locate().addTo(map);
  // L.control.fullscreen().addTo(map);
  L.Marker.include(L.Mixin.ContextMenu);

  // Configure map
  map.addLayer( L.tileLayer.provider( 'MapBox.missinglink.i3ook7ke' ) );
  var layerManager = PeliasGeoJsonLayerManager.bind( map );

  // Host String
  var hostMask = 'http://:domain::port:/:st:/:est:/{z}/{y}/{x}';

  // Use subdomains if configured at the DNS level
  if( document.domain === 'pelias.wiz.co.nz' ){
    hostMask = 'http://{s}.:domain::port:/:st:/:est:/{z}/{y}/{x}';
  }

  var hostString = hostMask.replace( ':domain:', document.domain )
                           .replace( ':port:', location.port ? ':' + location.port : '' );

  // Geonames
  layerManager.register( 'geonames.all',
    hostString.replace(':st:','points').replace(':est:','geoname'),
    { color: '#D00' }
  ).disable( 'geonames.all' );

  // Admin0
  layerManager.register( 'quattroshapes.admin0',
    hostString.replace(':st:','shapes').replace(':est:','admin0'),
    { color: '#FF00FF' }
  ).enable( 'quattroshapes.admin0' );

  // Admin1
  layerManager.register( 'quattroshapes.admin1',
    hostString.replace(':st:','shapes').replace(':est:','admin1'),
    { color: '#00FFFF' }
  ).enable( 'quattroshapes.admin1' );

  // Admin2
  layerManager.register( 'quattroshapes.admin2',
    hostString.replace(':st:','shapes').replace(':est:','admin2'),
    { color: '#FFFF00' }
  ).enable( 'quattroshapes.admin2' );

  // Local Admin
  layerManager.register( 'quattroshapes.localadmin',
    hostString.replace(':st:','shapes').replace(':est:','local_admin'),
    { color: '#0D0' }
  ).enable( 'quattroshapes.localadmin' );

  // Locality
  layerManager.register( 'quattroshapes.locality',
    hostString.replace(':st:','shapes').replace(':est:','locality'),
    { color: '#00D' }
  ).enable( 'quattroshapes.locality' );

  // Neighborhood
  layerManager.register( 'quattroshapes.neighborhood',
    hostString.replace(':st:','shapes').replace(':est:','neighborhood'),
    { color: '#D00' }
  ).enable( 'quattroshapes.neighborhood' );

  // Manually add layer
  // map.addLayer( PeliasGeoJsonLayer( '/shapes/locality/{z}/{y}/{x}' ) );

  // Center map
  // map.setView( [ 51.505, -0.124 ], 12 ); // London
  map.setView( [ 40.75558, -74.00391 ], 8 ); // New York

});
<|endoftext|>


<commit_before>(function(window, document, undefined){

  /*
    Mixins
  */

  var observable = function(obj){
    obj.bind = function(cb){
      this._callbacks = this._callbacks || [];
      this._callbacks.push(cb);
    };

    obj.trigger = function(){
      if(!this._callbacks) return;
      for(var i = 0; callback = this._callbacks[i]; i++)
        callback.apply(this, arguments);
    };

    return obj;
  };

  var transformable = function(obj){
    obj.move = function(e){
      if(!e.type === "move" || !e.deltaX) return;
      if(_.isUndefined(this.currOffset)) this.currOffset = 0;
      this.currOffset += e.deltaX;
      this.el.css({"left" : this.currOffset});
    };

    obj.zoom = function(e){
      if(!e.type === "zoom") return;
      this.el.css({ "width": e.width });
    };
  };

  /*
    Plugins
  */
  var draggable = function(obj){
    var drag;
    function mousedown(e){
      e.preventDefault();
      drag = {x: e.pageX, y: e.pageY};
      e.type = "dragstart";
      obj.el.trigger(e);
    };

    function mousemove(e){
      e.preventDefault();
      if(!drag) return;
      e.type = "dragging";
      e = _.extend(e, {
        deltaX: e.pageX - drag.x,
        deltaY: e.pageY - drag.y
      });
      drag = {x: e.pageX, y: e.pageY};
      obj.el.trigger(e);
    };

    function mouseup(e){
      if(!drag) return;
      drag = null;
      e.type = "dragend";
      obj.el.trigger(e);
    };

    obj.el.bind("mousedown", mousedown);

    $(document).bind("mousemove", mousemove);
    $(document).bind("mouseup", mouseup);

    return obj;
  };

  // safari bug for too fast scrolling, h/t polymaps
  var safari = /WebKit\/533/.test(navigator.userAgent);
  var wheel = function(obj){
    function mousewheel(e){
      e.preventDefault();
      var delta = (e.wheelDelta || -e.detail);
      if(safari){
        var negative = delta < 0 ? -1 : 1;
        delta = Math.log(Math.abs(delta)) * negative * 2;
      };
      e.type = "scrolled";
      e.deltaX = delta;
      obj.el.trigger(e);
    };

    obj.el.bind("mousewheel DOMMouseScroll", mousewheel);
  };

  /*
    Utils
  */
  var Bounds = function(){
    this.min = +Infinity;
    this.max = -Infinity;
  };

  Bounds.prototype.extend = function(num){
    this.min = Math.min(num, this.min);
    this.max = Math.max(num, this.max);
  };

  Bounds.prototype.width = function(){
    return this.max - this.min;
  };

  Bounds.prototype.project = function(num, max){
    return (num - this.min) / this.width() * max;
  };

  // Handy dandy function to make sure that events are
  // triggered at the same time on two objects.'

  var sync = function(origin, listener){
    var events = Array.prototype.slice.call(arguments, 2);
    _.each(events, function(ev){
      origin.bind(function(e){
        if(e.type === ev && listener[ev])
          listener[ev](e);
      });
    });
  };

  var template = function(query) {
    return _.template($(query).text());
  };

  var getYearFromTimestamp = function(timestamp) {
    var d = new Date();
    d.setTime(timestamp * 1000);
    return d.getFullYear();
  };

  /*
    Models
  */
  // Stores state
  var Timeline = function(data) {
    data = data.sort(function(a, b){ return a.timestamp - b.timestamp; });
    this.bySid  = {};
    this.series = [];
    this.bounds = new Bounds();
    this.createSeries(data);
    this.bar      = new Bar(this);
    this.cardCont = new CardContainer(this);
    sync(this.bar, this.cardCont, "move", "zoom");
    var e = $.Event("render");
    this.trigger(e);
  };
  observable(Timeline.prototype);

  Timeline.prototype = _.extend(Timeline.prototype, {
    createSeries : function(series){
      for(var i = 0; i < series.length; i++){
        this.add(series[i]);
      }
    },

    add : function(card){
      if(!(card.event_series in this.bySid)){
        this.bySid[card.event_series] = new Series(card, this);
        this.series.push(this.bySid[card.event_series]);
      }
      var series = this.bySid[card.event_series];
      series.add(card);
      this.bounds.extend(series.max());
      this.bounds.extend(series.min());
    }
  });

  /*
   Views
  */
  var Bar = function(timeline) {
    this.el = $(".timeline_notchbar");
    this.el.css({ "left": 0 });
    this.timeline = timeline;
    draggable(this);
    wheel(this);
    _.bindAll(this, "moving", "doZoom");
    this.el.bind("dragging scrolled", this.moving);
    this.el.bind("doZoom", this.doZoom);
    this.template = template("#year_notch_tmpl");
    this.render();
  };
  observable(Bar.prototype);
  transformable(Bar.prototype);

  Bar.prototype = _.extend(Bar.prototype, {
    moving : function(e){
      var parent  = this.el.parent();
      var pOffset = parent.offset().left;
      var offset  = this.el.offset().left;

      // check to make sure we have a delta
      if(_.isUndefined(e.deltaX)) e.deltaX = 0;

      // check to make sure the bar isn't out of bounds
      if(offset + this.el.width() + e.deltaX < pOffset + parent.width())
        e.deltaX = (pOffset + parent.width()) - (offset + this.el.width());
      if(offset + e.deltaX > pOffset)
        e.deltaX = pOffset - offset;

      // and move both this and the card container.
      e.type = "move";
      this.trigger(e);
      this.move(e);
    },

    doZoom : function(e, width){
      var that = this;

      // needs fixin for offset and things, time fer thinkin'
      this.el.animate({"width": width + "%"}, {
        step: function(current) {
          var e   = $.Event();
          e.width = current + "%";
          e.type  = "zoom";
          that.el.trigger("dragging");
          that.trigger(e);
        }
      });
    },

    render : function(){
      var timestamp, year, html, date;
      var earliestYear = getYearFromTimestamp(this.timeline.bounds.min);
      var latestYear   = getYearFromTimestamp(this.timeline.bounds.max);
      // calculate divisions a bit better.
      for (i = earliestYear; i < latestYear; i++) {
        date      = new Date();
        date.setYear(i);
        date.setMonth(1);
        date.setDate(1);
        timestamp = date.getTime() / 1000 | 0;
        year      = i;
        html      = this.template({'timestamp' : timestamp, 'year' : year });
        this.el.append($(html).css("left", (this.timeline.bounds.project(timestamp, 100) | 0) + "%"));
      }
    }
  });

  var CardContainer = function(timeline){
    this.el = $("#timeline_card_scroller_inner");
  };
  observable(CardContainer.prototype);
  transformable(CardContainer.prototype);

  var color = function(){
    return "#" + _.reduce([256, 182, 230], function(memo, it){
      var unpadded = (Math.random(it) * 256 | 0).toString(16);
      return memo + (unpadded.length < 2 ? "0" + unpadded : unpadded);
    }, "");
  };

  var Series = function(series, timeline) {
    this.color    = color();
    this.timeline = timeline;
    this.name     = series.event_series;
    this.cards    = [];
    _.bindAll(this, "render", "showNotches", "hideNotches");
    this.template = template("#series_legend_tmpl");
    this.timeline.bind(this.render);
  };
  observable(Series.prototype);

  Series.prototype = _.extend(Series.prototype, {
    add : function(card){
      var crd = new Card(card, this);
      this.cards.splice(this.sortedIndex(crd), 0, crd);
    },

    sortedIndex : function(card){
      return _.sortedIndex(this.cards, card, this._comparator);
    },

    _comparator : function(crd){
      return crd.timestamp;
    },

    hideNotches : function(){
      this.el.addClass("series_legend_item_inactive");
      _.each(this.cards, function(card){
        card.hideNotch();
      });
    },

    showNotches : function(){
      this.el.removeClass("series_legend_item_inactive");
      _.each(this.cards, function(card){
        card.showNotch();
      });
    },

    render : function(e){
      if(!e.type === "render") return;
      this.el = $(this.template(this));
      $(".series_nav_container").append(this.el);
      this.el.toggle(this.hideNotches,this.showNotches);
    }
  });

  _(["min", "max"]).each(function(key){
    Series.prototype[key] = function() {
      return _[key].call(_, this.cards, this._comparator).timestamp;
    };
  });

  var Card = function(card, series) {
    this.series = series;
    var card = _.clone(card);
    this.timestamp = card.timestamp;
    this.attributes = card;
    this.attributes.topcolor = series.color;
    this.template = template("#card_tmpl");
    this.ntemplate = template("#notch_tmpl");
    _.bindAll(this, "render", "activate");
    this.series.timeline.bind(this.render);
    this.series.bind(this.deactivate);
  };

  Card.prototype = _.extend(Card.prototype, {
    get : function(key){
      return this.attributes[key];
    },

    render : function(e){
      if(!e.type === "render") return;
      this.offset = this.series.timeline.bounds.project(this.timestamp, 100);
      var html = this.ntemplate(this.attributes);
      this.notch = $(html).css({"left": this.offset + "%"});
      $(".timeline_notchbar").append(this.notch);
      this.notch.click(this.activate);
    },

    activate : function(e){
      this.hideActiveCard();

      // draw the actual card
      if (!this.el) {
        this.el = $(this.template(this.attributes));
        this.el.css({"left": this.offset + "%"});
        $("#timeline_card_scroller_inner").append(this.el);
      }
      this.el.show().addClass("card_active");
      this.notch.addClass("timeline_notch_active");
    },

    hideActiveCard : function() {
      $(".card_active").removeClass("card_active").hide();
      $(".timeline_notch_active").removeClass("timeline_notch_active");
    },

    hideNotch : function(){
      this.notch.hide();
      if(this.el) this.el.hide();
    },

    showNotch : function(){
      this.notch.show();
    }

  });

  var ctor = function(){};
  var inherits = function(child, parent){
    ctor.prototype  = parent.prototype;
    child.prototype = new ctor();
    child.prototype.constructor = child;
  };

  // Controls
  var Control = function(direction){
    this.direction = direction;
    this.el = $(this.prefix + direction);
     _.bindAll(this, 'click');
    this.el.bind('click', this.click);
  };

  var curZoom = 100;

  var Zoom = function(direction) {
    Control.apply(this, arguments);
  };
  inherits(Zoom, Control);

  Zoom.prototype = _.extend(Zoom.prototype, {
    prefix : ".timeline_zoom_",
    click : function() {
      curZoom += (this.direction === "in" ? +100 : -100);
      if (curZoom >= 100) {
        $(".timeline_notchbar").trigger('doZoom', [curZoom]);
      } else {
        curZoom = 100;
      }
    }
  });

  var Chooser = function(direction) {
    Control.apply(this, arguments);
    this.notches = $(".timeline_notch");
  };
  inherits(Chooser, Control);

  Chooser.prototype = _.extend(Control.prototype, {
    prefix: ".timeline_choose_",
    click: function(e){
      var el;
      var curCardIdx = this.notches.index($(".timeline_notch_active"));
      var numOfCards = this.notches.length;
      if (this.direction === "next") {
        el = (curCardIdx < numOfCards ? this.notches.eq(curCardIdx + 1) : false);
      } else {
        el = (curCardIdx > 0 ? this.notches.eq(curCardIdx - 1) : false);
      }

      if(!el) return;
      el.trigger("click");
    }
  });

  $(function(){
    window.timeline = new Timeline(timelineData);
    new Zoom("in");
    new Zoom("out");
    var chooser = new Chooser("next");
    chooser.click();
    new Chooser("prev");
  });

})(window, document);
<commit_msg>don't show square's on empty names<commit_after>(function(window, document, undefined){

  /*
    Mixins
  */

  var observable = function(obj){
    obj.bind = function(cb){
      this._callbacks = this._callbacks || [];
      this._callbacks.push(cb);
    };

    obj.trigger = function(){
      if(!this._callbacks) return;
      for(var i = 0; callback = this._callbacks[i]; i++)
        callback.apply(this, arguments);
    };

    return obj;
  };

  var transformable = function(obj){
    obj.move = function(e){
      if(!e.type === "move" || !e.deltaX) return;
      if(_.isUndefined(this.currOffset)) this.currOffset = 0;
      this.currOffset += e.deltaX;
      this.el.css({"left" : this.currOffset});
    };

    obj.zoom = function(e){
      if(!e.type === "zoom") return;
      this.el.css({ "width": e.width });
    };
  };

  /*
    Plugins
  */
  var draggable = function(obj){
    var drag;
    function mousedown(e){
      e.preventDefault();
      drag = {x: e.pageX, y: e.pageY};
      e.type = "dragstart";
      obj.el.trigger(e);
    };

    function mousemove(e){
      e.preventDefault();
      if(!drag) return;
      e.type = "dragging";
      e = _.extend(e, {
        deltaX: e.pageX - drag.x,
        deltaY: e.pageY - drag.y
      });
      drag = {x: e.pageX, y: e.pageY};
      obj.el.trigger(e);
    };

    function mouseup(e){
      if(!drag) return;
      drag = null;
      e.type = "dragend";
      obj.el.trigger(e);
    };

    obj.el.bind("mousedown", mousedown);

    $(document).bind("mousemove", mousemove);
    $(document).bind("mouseup", mouseup);

    return obj;
  };

  // safari bug for too fast scrolling, h/t polymaps
  var safari = /WebKit\/533/.test(navigator.userAgent);
  var wheel = function(obj){
    function mousewheel(e){
      e.preventDefault();
      var delta = (e.wheelDelta || -e.detail);
      if(safari){
        var negative = delta < 0 ? -1 : 1;
        delta = Math.log(Math.abs(delta)) * negative * 2;
      };
      e.type = "scrolled";
      e.deltaX = delta;
      obj.el.trigger(e);
    };

    obj.el.bind("mousewheel DOMMouseScroll", mousewheel);
  };

  /*
    Utils
  */
  var Bounds = function(){
    this.min = +Infinity;
    this.max = -Infinity;
  };

  Bounds.prototype.extend = function(num){
    this.min = Math.min(num, this.min);
    this.max = Math.max(num, this.max);
  };

  Bounds.prototype.width = function(){
    return this.max - this.min;
  };

  Bounds.prototype.project = function(num, max){
    return (num - this.min) / this.width() * max;
  };

  // Handy dandy function to make sure that events are
  // triggered at the same time on two objects.'

  var sync = function(origin, listener){
    var events = Array.prototype.slice.call(arguments, 2);
    _.each(events, function(ev){
      origin.bind(function(e){
        if(e.type === ev && listener[ev])
          listener[ev](e);
      });
    });
  };

  var template = function(query) {
    return _.template($(query).text());
  };

  var getYearFromTimestamp = function(timestamp) {
    var d = new Date();
    d.setTime(timestamp * 1000);
    return d.getFullYear();
  };

  /*
    Models
  */
  // Stores state
  var Timeline = function(data) {
    data = data.sort(function(a, b){ return a.timestamp - b.timestamp; });
    this.bySid  = {};
    this.series = [];
    this.bounds = new Bounds();
    this.createSeries(data);
    this.bar      = new Bar(this);
    this.cardCont = new CardContainer(this);
    sync(this.bar, this.cardCont, "move", "zoom");
    var e = $.Event("render");
    this.trigger(e);
  };
  observable(Timeline.prototype);

  Timeline.prototype = _.extend(Timeline.prototype, {
    createSeries : function(series){
      for(var i = 0; i < series.length; i++){
        this.add(series[i]);
      }
    },

    add : function(card){
      if(!(card.event_series in this.bySid)){
        this.bySid[card.event_series] = new Series(card, this);
        this.series.push(this.bySid[card.event_series]);
      }
      var series = this.bySid[card.event_series];
      series.add(card);
      this.bounds.extend(series.max());
      this.bounds.extend(series.min());
    }
  });

  /*
   Views
  */
  var Bar = function(timeline) {
    this.el = $(".timeline_notchbar");
    this.el.css({ "left": 0 });
    this.timeline = timeline;
    draggable(this);
    wheel(this);
    _.bindAll(this, "moving", "doZoom");
    this.el.bind("dragging scrolled", this.moving);
    this.el.bind("doZoom", this.doZoom);
    this.template = template("#year_notch_tmpl");
    this.render();
  };
  observable(Bar.prototype);
  transformable(Bar.prototype);

  Bar.prototype = _.extend(Bar.prototype, {
    moving : function(e){
      var parent  = this.el.parent();
      var pOffset = parent.offset().left;
      var offset  = this.el.offset().left;

      // check to make sure we have a delta
      if(_.isUndefined(e.deltaX)) e.deltaX = 0;

      // check to make sure the bar isn't out of bounds
      if(offset + this.el.width() + e.deltaX < pOffset + parent.width())
        e.deltaX = (pOffset + parent.width()) - (offset + this.el.width());
      if(offset + e.deltaX > pOffset)
        e.deltaX = pOffset - offset;

      // and move both this and the card container.
      e.type = "move";
      this.trigger(e);
      this.move(e);
    },

    doZoom : function(e, width){
      var that = this;

      // needs fixin for offset and things, time fer thinkin'
      this.el.animate({"width": width + "%"}, {
        step: function(current) {
          var e   = $.Event();
          e.width = current + "%";
          e.type  = "zoom";
          that.el.trigger("dragging");
          that.trigger(e);
        }
      });
    },

    render : function(){
      var timestamp, year, html, date;
      var earliestYear = getYearFromTimestamp(this.timeline.bounds.min);
      var latestYear   = getYearFromTimestamp(this.timeline.bounds.max);
      // calculate divisions a bit better.
      for (i = earliestYear; i < latestYear; i++) {
        date      = new Date();
        date.setYear(i);
        date.setMonth(1);
        date.setDate(1);
        timestamp = date.getTime() / 1000 | 0;
        year      = i;
        html      = this.template({'timestamp' : timestamp, 'year' : year });
        this.el.append($(html).css("left", (this.timeline.bounds.project(timestamp, 100) | 0) + "%"));
      }
    }
  });

  var CardContainer = function(timeline){
    this.el = $("#timeline_card_scroller_inner");
  };
  observable(CardContainer.prototype);
  transformable(CardContainer.prototype);

  var color = function(){
    return "#" + _.reduce([256, 182, 230], function(memo, it){
      var unpadded = (Math.random(it) * 256 | 0).toString(16);
      return memo + (unpadded.length < 2 ? "0" + unpadded : unpadded);
    }, "");
  };

  var Series = function(series, timeline) {
    this.timeline = timeline;
    this.name     = series.event_series;
    this.color    = this.name.length > 0 ? color() : "#444";
    this.cards    = [];
    _.bindAll(this, "render", "showNotches", "hideNotches");
    this.template = template("#series_legend_tmpl");
    this.timeline.bind(this.render);
  };
  observable(Series.prototype);

  Series.prototype = _.extend(Series.prototype, {
    add : function(card){
      var crd = new Card(card, this);
      this.cards.splice(this.sortedIndex(crd), 0, crd);
    },

    sortedIndex : function(card){
      return _.sortedIndex(this.cards, card, this._comparator);
    },

    _comparator : function(crd){
      return crd.timestamp;
    },

    hideNotches : function(){
      this.el.addClass("series_legend_item_inactive");
      _.each(this.cards, function(card){
        card.hideNotch();
      });
    },

    showNotches : function(){
      this.el.removeClass("series_legend_item_inactive");
      _.each(this.cards, function(card){
        card.showNotch();
      });
    },

    render : function(e){
      if(!e.type === "render") return;
      if(this.name.length === 0) return;
      this.el = $(this.template(this));
      $(".series_nav_container").append(this.el);
      this.el.toggle(this.hideNotches,this.showNotches);
    }
  });

  _(["min", "max"]).each(function(key){
    Series.prototype[key] = function() {
      return _[key].call(_, this.cards, this._comparator).timestamp;
    };
  });

  var Card = function(card, series) {
    this.series = series;
    var card = _.clone(card);
    this.timestamp = card.timestamp;
    this.attributes = card;
    this.attributes.topcolor = series.color;
    this.template = template("#card_tmpl");
    this.ntemplate = template("#notch_tmpl");
    _.bindAll(this, "render", "activate");
    this.series.timeline.bind(this.render);
    this.series.bind(this.deactivate);
  };

  Card.prototype = _.extend(Card.prototype, {
    get : function(key){
      return this.attributes[key];
    },

    render : function(e){
      if(!e.type === "render") return;
      this.offset = this.series.timeline.bounds.project(this.timestamp, 100);
      var html = this.ntemplate(this.attributes);
      this.notch = $(html).css({"left": this.offset + "%"});
      $(".timeline_notchbar").append(this.notch);
      this.notch.click(this.activate);
    },

    activate : function(e){
      this.hideActiveCard();

      // draw the actual card
      if (!this.el) {
        this.el = $(this.template(this.attributes));
        this.el.css({"left": this.offset + "%"});
        $("#timeline_card_scroller_inner").append(this.el);
      }
      this.el.show().addClass("card_active");
      this.notch.addClass("timeline_notch_active");
    },

    hideActiveCard : function() {
      $(".card_active").removeClass("card_active").hide();
      $(".timeline_notch_active").removeClass("timeline_notch_active");
    },

    hideNotch : function(){
      this.notch.hide();
      if(this.el) this.el.hide();
    },

    showNotch : function(){
      this.notch.show();
    }

  });

  var ctor = function(){};
  var inherits = function(child, parent){
    ctor.prototype  = parent.prototype;
    child.prototype = new ctor();
    child.prototype.constructor = child;
  };

  // Controls
  var Control = function(direction){
    this.direction = direction;
    this.el = $(this.prefix + direction);
     _.bindAll(this, 'click');
    this.el.bind('click', this.click);
  };

  var curZoom = 100;

  var Zoom = function(direction) {
    Control.apply(this, arguments);
  };
  inherits(Zoom, Control);

  Zoom.prototype = _.extend(Zoom.prototype, {
    prefix : ".timeline_zoom_",
    click : function() {
      curZoom += (this.direction === "in" ? +100 : -100);
      if (curZoom >= 100) {
        $(".timeline_notchbar").trigger('doZoom', [curZoom]);
      } else {
        curZoom = 100;
      }
    }
  });

  var Chooser = function(direction) {
    Control.apply(this, arguments);
    this.notches = $(".timeline_notch");
  };
  inherits(Chooser, Control);

  Chooser.prototype = _.extend(Control.prototype, {
    prefix: ".timeline_choose_",
    click: function(e){
      var el;
      var curCardIdx = this.notches.index($(".timeline_notch_active"));
      var numOfCards = this.notches.length;
      if (this.direction === "next") {
        el = (curCardIdx < numOfCards ? this.notches.eq(curCardIdx + 1) : false);
      } else {
        el = (curCardIdx > 0 ? this.notches.eq(curCardIdx - 1) : false);
      }
      if(!el) return;
      el.trigger("click");
    }
  });

  $(function(){
    window.timeline = new Timeline(timelineData);
    new Zoom("in");
    new Zoom("out");
    var chooser = new Chooser("next");
    chooser.click();
    new Chooser("prev");
  });

})(window, document);
<|endoftext|>


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

$(function () {
    "use strict";
    drawChart();

    loadAjaxPartial('inOutAccounts', spentUri);
    loadAjaxPartial('inOutCategory', categoryUri);
    loadAjaxPartial('inOutBudget', budgetUri);
    loadAjaxPartial('topXexpense', expenseUri);
    loadAjaxPartial('topXincome', incomeUri);

});

function drawChart() {
    "use strict";

    // month view:
    // draw account chart
    // month view:
    doubleYChart(mainUri, 'in-out-chart');
}<commit_msg>Remove some comments [skip ci]<commit_after>
/*
 * month.js
 * Copyright (c) 2017 thegrumpydictator@gmail.com
 *
 * This file is part of Firefly III.
 *
 * Firefly III is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Firefly III is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Firefly III.  If not, see <http://www.gnu.org/licenses/>.
 */

$(function () {
    "use strict";
    drawChart();

    loadAjaxPartial('inOutAccounts', spentUri);
    loadAjaxPartial('inOutCategory', categoryUri);
    loadAjaxPartial('inOutBudget', budgetUri);
    loadAjaxPartial('topXexpense', expenseUri);
    loadAjaxPartial('topXincome', incomeUri);

});

function drawChart() {
    "use strict";

    // month view:
    doubleYChart(mainUri, 'in-out-chart');
}<|endoftext|>


<commit_before>define([
	"dojo/_base/declare", "dojo/_base/lang", "dojo/on", "dojo/request", "dojo/topic",
	"dojo/dom-class", "dojo/query", "dojo/dom-style", "dojo/text!./templates/GenomeOverview.html", "dojo/dom-construct",
	"dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin", "dijit/Dialog",
	"../util/PathJoin", "./SelectionToGroup", "./GenomeFeatureSummary", "./DataItemFormatter",
	"./ExternalItemFormatter", "./AdvancedDownload"

], function(declare, lang, on, xhr, Topic,
			domClass, domQuery, domStyle, Template, domConstruct,
			WidgetBase, Templated, _WidgetsInTemplateMixin, Dialog,
			PathJoin, SelectionToGroup, GenomeFeatureSummary, DataItemFormatter,
			ExternalItemFormatter, AdvancedDownload){

	return declare([WidgetBase, Templated, _WidgetsInTemplateMixin], {
		baseClass: "GenomeOverview",
		disabled: false,
		templateString: Template,
		apiServiceUrl: window.App.dataAPI,
		genome: null,
		state: null,

		_setStateAttr: function(state){
			this._set("state", state);
			if(state.genome){
				this.set("genome", state.genome);
			}
		},

		"_setGenomeAttr": function(genome){
			if(this.genome && (this.genome.genome_id == genome.genome_id)){
				// console.log("Genome ID Already Set")
				return;
			}
			this.genome = genome;

			this.createSummary(genome);

			var sumWidgets = ["apSummaryWidget", "gfSummaryWidget", "pfSummaryWidget", "spgSummaryWidget"];

			sumWidgets.forEach(function(w){
				if(this[w]){
					this[w].set('query', "eq(genome_id," + this.genome.genome_id + ")")
				}
			}, this);

			// display/hide download button per public status
			if(genome.public){
				domStyle.set(domQuery("div.ActionButtonWrapper.btnDownloadGenome")[0], "display", "inline-block");
			}else{
				// private, hide button
				domStyle.set(domQuery("div.ActionButtonWrapper.btnDownloadGenome")[0], "display", "none");
			}
		},

		"createSummary": function(genome){
			domConstruct.empty(this.genomeSummaryNode);
			domConstruct.place(DataItemFormatter(genome, "genome_data", {}), this.genomeSummaryNode, "first");
			domConstruct.empty(this.pubmedSummaryNode);
			domConstruct.place(ExternalItemFormatter(genome, "pubmed_data", {}), this.pubmedSummaryNode, "first");
		},

		onAddGenome: function(){

			if(!window.App.user || !window.App.user.id){
				Topic.publish("/login");
				return;
			}

			var dlg = new Dialog({title: "Add This Genome To Group"});
			var stg = new SelectionToGroup({
				selection: [this.genome],
				type: 'genome_group'
			});
			on(dlg.domNode, "dialogAction", function(){
				dlg.hide();
				setTimeout(function(){
					dlg.destroy();
				}, 2000);
			});
			domConstruct.place(stg.domNode, dlg.containerNode, "first");
			stg.startup();
			dlg.startup();
			dlg.show();
		},

		onDownload: function(){

			var dialog = new Dialog({title: "Download"});
			var advDn = new AdvancedDownload({selection: [this.genome], containerType: "genome_data"});
			domConstruct.place(advDn.domNode, dialog.containerNode);
			dialog.show();
		},

		startup: function(){
			if(this._started){
				return;
			}
			this.inherited(arguments);

			if(this.genome){
				this.set("genome", this.genome);
			}
		}
	});
});
<commit_msg>bypass reserved word<commit_after>define([
	"dojo/_base/declare", "dojo/_base/lang", "dojo/on", "dojo/request", "dojo/topic",
	"dojo/dom-class", "dojo/query", "dojo/dom-style", "dojo/text!./templates/GenomeOverview.html", "dojo/dom-construct",
	"dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin", "dijit/Dialog",
	"../util/PathJoin", "./SelectionToGroup", "./GenomeFeatureSummary", "./DataItemFormatter",
	"./ExternalItemFormatter", "./AdvancedDownload"

], function(declare, lang, on, xhr, Topic,
			domClass, domQuery, domStyle, Template, domConstruct,
			WidgetBase, Templated, _WidgetsInTemplateMixin, Dialog,
			PathJoin, SelectionToGroup, GenomeFeatureSummary, DataItemFormatter,
			ExternalItemFormatter, AdvancedDownload){

	return declare([WidgetBase, Templated, _WidgetsInTemplateMixin], {
		baseClass: "GenomeOverview",
		disabled: false,
		templateString: Template,
		apiServiceUrl: window.App.dataAPI,
		genome: null,
		state: null,

		_setStateAttr: function(state){
			this._set("state", state);
			if(state.genome){
				this.set("genome", state.genome);
			}
		},

		"_setGenomeAttr": function(genome){
			if(this.genome && (this.genome.genome_id == genome.genome_id)){
				// console.log("Genome ID Already Set")
				return;
			}
			this.genome = genome;

			this.createSummary(genome);

			var sumWidgets = ["apSummaryWidget", "gfSummaryWidget", "pfSummaryWidget", "spgSummaryWidget"];

			sumWidgets.forEach(function(w){
				if(this[w]){
					this[w].set('query', "eq(genome_id," + this.genome.genome_id + ")")
				}
			}, this);

			// display/hide download button per public status
			if(genome['public']){
				domStyle.set(domQuery("div.ActionButtonWrapper.btnDownloadGenome")[0], "display", "inline-block");
			}else{
				// private, hide button
				domStyle.set(domQuery("div.ActionButtonWrapper.btnDownloadGenome")[0], "display", "none");
			}
		},

		"createSummary": function(genome){
			domConstruct.empty(this.genomeSummaryNode);
			domConstruct.place(DataItemFormatter(genome, "genome_data", {}), this.genomeSummaryNode, "first");
			domConstruct.empty(this.pubmedSummaryNode);
			domConstruct.place(ExternalItemFormatter(genome, "pubmed_data", {}), this.pubmedSummaryNode, "first");
		},

		onAddGenome: function(){

			if(!window.App.user || !window.App.user.id){
				Topic.publish("/login");
				return;
			}

			var dlg = new Dialog({title: "Add This Genome To Group"});
			var stg = new SelectionToGroup({
				selection: [this.genome],
				type: 'genome_group'
			});
			on(dlg.domNode, "dialogAction", function(){
				dlg.hide();
				setTimeout(function(){
					dlg.destroy();
				}, 2000);
			});
			domConstruct.place(stg.domNode, dlg.containerNode, "first");
			stg.startup();
			dlg.startup();
			dlg.show();
		},

		onDownload: function(){

			var dialog = new Dialog({title: "Download"});
			var advDn = new AdvancedDownload({selection: [this.genome], containerType: "genome_data"});
			domConstruct.place(advDn.domNode, dialog.containerNode);
			dialog.show();
		},

		startup: function(){
			if(this._started){
				return;
			}
			this.inherited(arguments);

			if(this.genome){
				this.set("genome", this.genome);
			}
		}
	});
});
<|endoftext|>


<commit_before>/**
 * @title Rocket Reveal
 * @description Adds reveal class when element scrolls past threshold.
 * @version 0.0.3
 * @author Richard Nelson
 * @email sc2071@gmail.com
 */

(function( $ ) {

	"use strict";

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketRevealSingleton = (function() {
		console.log( "new RocketRevealSingleton" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var instance;

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC FUNCTIONS ----- //
		function getInstance() {
			console.log( "RocketRevealSingleton: getInstance" );

			if ( !instance ) {

				instance = new RocketRevealManager();

			}

			return instance;

		}

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
		 	getInstance: getInstance
		}

	}());

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketRevealManager = function( elem ) {
		console.log( "new RocketRevealManager" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var $window;
		var containers;
		var enabled;
		var resizeTimer;
		var scrollTimer;
		var windowHeight;
		var windowTop;

		// ----- PRIVATE CONSTANTS ----- //
		var RESIZE_DELAY = 250;
		var SCROLL_DELAY = 250;

		// ----- PRIVATE FUNCTIONS ----- //
		function init( elem ) {
			console.log( "RocketRevealManager: init" );

			containers = [];

			$window = $( window );
			windowHeight = $window.height();
			windowTop = $window.scrollTop();

		}

		function clearResizeTimer() {
			console.log( "RocketRevealManager: clearResizeTimer" );

			if ( resizeTimer ) {

				clearTimeout( resizeTimer );
				resizeTimer = undefined;

			}

		}

		function clearScrollTimer() {
			console.log( "RocketRevealManager: clearScrollTimer" );

			if ( scrollTimer ) {

				clearTimeout( scrollTimer );
				scrollTimer = undefined;

			}

		}

		// ----- PRIVATE EVENT LISTENERS ----- //
		function onResize( e ) {
			console.log( "RocketRevealManager: onResize" );

			clearResizeTimer();
			resizeTimer = setTimeout( onResizeTimeout, RESIZE_DELAY );

		}

		function onResizeTimeout() {
			console.log( "RocketRevealManager: onResizeTimeout" );

			clearResizeTimer();
			windowHeight = $window.height();
			update();

		}

		function onScroll( e ) {
			console.log( "RocketRevealManager: onScroll" );

			if ( !scrollTimer )
				scrollTimer = setTimeout( onScrollTimeout, SCROLL_DELAY );

		}

		function onScrollTimeout() {
			console.log( "RocketRevealManager: onScrollTimeout" );

			clearScrollTimer();
			windowTop = $window.scrollTop();
			update();

		}

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC VARS ----- //

		// ----- PUBLIC CONSTANTS ----- //

		// ----- PUBLIC FUNCTIONS ----- //
		function add( elem ) {
			console.log( "RocketRevealManager: add" );

			var revealer = new RocketReveal( elem );
			containers.push( revealer );

		}

		function destroy() {
			console.log( "RocketRevealManager: destroy" );

			disable();

			$.each( containers, function( i ) {

				containers[ i ].destroy();

			} );

		}

		function disable() {
			console.log( "RocketRevealManager: disable" );

			enabled = false;

			clearResizeTimer();
			clearScrollTimer();

			$window.off( "resize", onResize );
			$window.off( "scroll", onScroll );

		}

		function enable() {
			console.log( "RocketRevealManager: enable" );

			enabled = true;

			$window.on( "resize", onResize );
			$window.on( "scroll", onScroll );

		}

		function execute( func, options ) {
			console.log( "RocketRevealManager: execute -> " + func );

			this[ func ].call( this, options );

		}

		function refresh() {
			console.log( "RocketRevealManager: refresh" );

			$.each( containers, function( i ) {

				containers[ i ].refreshItems();
				containers[ i ].updateItems( windowTop, windowHeight );

			} );

		}

		function update() {
			console.log( "RocketRevealManager: update" );

			$.each( containers, function( i ) {

				containers[ i ].updateItems( windowTop, windowHeight );

			} );

		}

		// ----- PUBLIC EVENT LISTENERS ----- //

		/*************************************************
		 * CALL
		 *************************************************/
		init( elem );

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
			add: add,
		 	destroy: destroy,
		 	disable: disable,
		 	enable: enable,
		 	execute: execute,
		 	refresh: refresh,
		 	update: update
		}

	}

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketReveal = function( elem ) {
		console.log( "new RocketReveal" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var $container;
		var items;
		var staggerTime;
		var thresholdRatio;

		// ----- PRIVATE CONSTANTS ----- //
		var EVENT_ANIMATION_TRANSITION_END = "animationend webkitAnimationEnd oanimationend MSAnimationEnd transitionend webkitTransitionEnd otransitionend MSTransitionEnd";
		var STYLE_REVEAL = "rkt-reveal";
		var STYLE_REVEAL_IN = "rkt-reveal-in";

		// ----- PRIVATE FUNCTIONS ----- //
		function init( elem ) {
			console.log( "RocketReveal: init" );

			$container = $( elem );
			staggerTime = parseFloat( $container.data( "stagger" ) ) || 0.1;
			thresholdRatio = parseFloat( $container.data( "threshold" ) ) || 0.9;

			addItems();
			updateItems();

		}

		function addItems() {
			console.log( "RocketReveal: addItems" );

			var $item;

			items = [];
			$container.find( "." + STYLE_REVEAL ).not( "." + STYLE_REVEAL_IN ).each( function( i ) {

				$item = $( this );
				items.push( $item );

			} );

			console.info( "Added " + items.length + " items..." );

		}

		function getElementOffsetTop( elem ) {
			//console.log( "RocketReveal: getElementOffsetTop" );

			var itemTransform = elem.css( "transform" ).replace( /[a-zA-Z\(\)\s]/g, "" ).split( "," );
			var itemTop = elem.offset().top - itemTransform[5];

			return itemTop;

		}

		// ----- PRIVATE EVENT LISTENERS ----- //

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC VARS ----- //

		// ----- PUBLIC CONSTANTS ----- //

		// ----- PUBLIC FUNCTIONS ----- //
		function destroy() {
			console.log( "RocketReveal: destroy" );

			$container.find( "." + STYLE_REVEAL ).not( "." + STYLE_REVEAL_IN ).each( function( i ) {

				$( this ).off( EVENT_ANIMATION_TRANSITION_END );

			} );

			items = undefined;

		}

		function refreshItems() {
			console.log( "RocketReveal: refreshItems" );

			addItems();
			updateItems();

		}

		function updateItems( windowTop, windowHeight ) {
			console.log( "RocketReveal: updateItems", windowTop, windowHeight );

			var $item;
			var delay = 0;
			var i = 0;
			var lastIndex;
			var length = items.length;
			var thresholdTop = windowTop + windowHeight * thresholdRatio;

			//console.info( "NUM ITEMS: " + items.length );
			//console.info( "------> THRESHOLD TOP: " + thresholdTop );

			for ( i; i < length; i++ ) {

				$item = items[i];

				//console.info( $item );
				//console.info( "---> ITEM TOP: " + getElementOffsetTop( $item ) );

				if ( getElementOffsetTop( $item ) <= thresholdTop ) {

					//console.info( "---> ITEM DELAY: ", delay );
					$item.css( "animation-delay", delay.toString() + "s" );
					$item.css( "transition-delay", delay.toString() + "s" );
					delay += staggerTime;
					lastIndex = i;

					var onEnd = function( e ) {
						console.log( "RocketReveal: onEnd" );

						var $target = $( e.currentTarget );

						$target.off( EVENT_ANIMATION_TRANSITION_END, onEnd );
						$target.css( "animation-delay", "" );
						$target.css( "transition-delay", "" );
						$target.removeClass( STYLE_REVEAL )
						$target.removeClass( STYLE_REVEAL_IN );

					}

					$item.on( EVENT_ANIMATION_TRANSITION_END, onEnd );
					$item.addClass( STYLE_REVEAL_IN );

				}

			}

			// Clean Up Array
			if ( lastIndex )
				items.splice( 0, lastIndex + 1 );

		}

		// ----- PUBLIC EVENT LISTENERS ----- //

		/*************************************************
		 * CALL
		 *************************************************/
		init( elem );

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
		 	destroy: destroy,
		 	refreshItems: refreshItems,
		 	updateItems: updateItems
		}

	}

	/*************************************************
	 * jQUERY PLUGIN
	 *************************************************/
	$.fn.rktReveal = function( command ) {

		var mgr = RocketRevealSingleton.getInstance();

		this.each( function() {

			if ( !command )
				mgr.add( this );
			else
				mgr.execute( command );

		} );

		return this;

	};

}( jQuery ));

<commit_msg>Minor optimizations to Reveal plugin.<commit_after>/**
 * @title Rocket Reveal
 * @description Adds reveal class when element scrolls past threshold.
 * @version 0.0.3
 * @author Richard Nelson
 * @email sc2071@gmail.com
 */

(function( $ ) {

	"use strict";

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketRevealSingleton = (function() {
		console.log( "new RocketRevealSingleton" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var instance;

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC FUNCTIONS ----- //
		function getInstance() {
			console.log( "RocketRevealSingleton: getInstance" );

			if ( !instance ) {

				instance = new RocketRevealManager();

			}

			return instance;

		}

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
		 	getInstance: getInstance
		}

	}());

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketRevealManager = function( elem ) {
		console.log( "new RocketRevealManager" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var $window;
		var containers;
		var enabled;
		var resizeTimer;
		var scrollTimer;
		var windowHeight;
		var windowTop;

		// ----- PRIVATE CONSTANTS ----- //
		var RESIZE_DELAY = 250;
		var SCROLL_DELAY = 250;

		// ----- PRIVATE FUNCTIONS ----- //
		function init( elem ) {
			console.log( "RocketRevealManager: init" );

			containers = [];

			$window = $( window );
			windowHeight = $window.height();
			windowTop = $window.scrollTop();

		}

		function clearResizeTimer() {
			console.log( "RocketRevealManager: clearResizeTimer" );

			if ( resizeTimer ) {

				clearTimeout( resizeTimer );
				resizeTimer = undefined;

			}

		}

		function clearScrollTimer() {
			console.log( "RocketRevealManager: clearScrollTimer" );

			if ( scrollTimer ) {

				clearTimeout( scrollTimer );
				scrollTimer = undefined;

			}

		}

		// ----- PRIVATE EVENT LISTENERS ----- //
		function onResize( e ) {
			console.log( "RocketRevealManager: onResize" );

			clearResizeTimer();
			resizeTimer = setTimeout( onResizeTimeout, RESIZE_DELAY );

		}

		function onResizeTimeout() {
			console.log( "RocketRevealManager: onResizeTimeout" );

			clearResizeTimer();
			update();

		}

		function onScroll( e ) {
			console.log( "RocketRevealManager: onScroll" );

			if ( !scrollTimer )
				scrollTimer = setTimeout( onScrollTimeout, SCROLL_DELAY );

		}

		function onScrollTimeout() {
			console.log( "RocketRevealManager: onScrollTimeout" );

			clearScrollTimer();
			update();

		}

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC VARS ----- //

		// ----- PUBLIC CONSTANTS ----- //

		// ----- PUBLIC FUNCTIONS ----- //
		function add( elem ) {
			console.log( "RocketRevealManager: add" );

			var revealer = new RocketReveal( elem );
			containers.push( revealer );

		}

		function destroy() {
			console.log( "RocketRevealManager: destroy" );

			disable();

			$.each( containers, function( i ) {

				containers[ i ].destroy();

			} );

		}

		function disable() {
			console.log( "RocketRevealManager: disable" );

			enabled = false;

			clearResizeTimer();
			clearScrollTimer();

			$window.off( "resize", onResize );
			$window.off( "scroll", onScroll );

		}

		function enable() {
			console.log( "RocketRevealManager: enable" );

			enabled = true;

			$window.on( "resize", onResize );
			$window.on( "scroll", onScroll );

		}

		function execute( func, options ) {
			console.log( "RocketRevealManager: execute -> " + func );

			this[ func ].call( this, options );

		}

		function refresh() {
			console.log( "RocketRevealManager: refresh" );

			$.each( containers, function( i ) {

				containers[ i ].refreshItems();
				containers[ i ].updateItems( windowTop, windowHeight );

			} );

		}

		function update() {
			console.log( "RocketRevealManager: update" );

			windowTop = $window.scrollTop();

			$.each( containers, function( i ) {

				containers[ i ].updateItems( windowTop, windowHeight );

			} );

		}

		// ----- PUBLIC EVENT LISTENERS ----- //

		/*************************************************
		 * CALL
		 *************************************************/
		init( elem );

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
			add: add,
		 	destroy: destroy,
		 	disable: disable,
		 	enable: enable,
		 	execute: execute,
		 	refresh: refresh,
		 	update: update
		}

	}

	/*************************************************
	 * PROTOTYPE
	 *************************************************/
	var RocketReveal = function( elem ) {
		console.log( "new RocketReveal" );

		/*************************************************
		 * PRIVATE
		 *************************************************/

		// ----- PRIVATE VARS ----- //
		var $container;
		var items;
		var staggerTime;
		var thresholdRatio;

		// ----- PRIVATE CONSTANTS ----- //
		var EVENT_ANIMATION_TRANSITION_END = "animationend webkitAnimationEnd oanimationend MSAnimationEnd transitionend webkitTransitionEnd otransitionend MSTransitionEnd";
		var STYLE_REVEAL = "rkt-reveal";
		var STYLE_REVEAL_IN = "rkt-reveal-in";

		// ----- PRIVATE FUNCTIONS ----- //
		function init( elem ) {
			console.log( "RocketReveal: init" );

			$container = $( elem );
			staggerTime = parseFloat( $container.data( "stagger" ) ) || 0.1;
			thresholdRatio = parseFloat( $container.data( "threshold" ) ) || 0.9;

			addItems();
			updateItems();

		}

		function addItems() {
			console.log( "RocketReveal: addItems" );

			var $item;

			items = [];
			$container.find( "." + STYLE_REVEAL ).not( "." + STYLE_REVEAL_IN ).each( function( i ) {

				$item = $( this );
				items.push( $item );

			} );

			console.info( "Added " + items.length + " items..." );

		}

		function getElementOffsetTop( elem ) {
			//console.log( "RocketReveal: getElementOffsetTop" );

			var itemTransform = elem.css( "transform" ).replace( /[a-zA-Z\(\)\s]/g, "" ).split( "," );
			var itemTop = elem.offset().top - itemTransform[5];

			return itemTop;

		}

		// ----- PRIVATE EVENT LISTENERS ----- //

		/*************************************************
		 * PUBLIC
		 *************************************************/

		// ----- PUBLIC VARS ----- //

		// ----- PUBLIC CONSTANTS ----- //

		// ----- PUBLIC FUNCTIONS ----- //
		function destroy() {
			console.log( "RocketReveal: destroy" );

			$container.find( "." + STYLE_REVEAL ).not( "." + STYLE_REVEAL_IN ).each( function( i ) {

				$( this ).off( EVENT_ANIMATION_TRANSITION_END );

			} );

			items = undefined;

		}

		function refreshItems() {
			console.log( "RocketReveal: refreshItems" );

			addItems();
			updateItems();

		}

		function updateItems( windowTop, windowHeight ) {
			console.log( "RocketReveal: updateItems", windowTop, windowHeight );

			var $item;
			var delay = 0;
			var i = 0;
			var lastIndex;
			var length = items.length;
			var thresholdTop = windowTop + windowHeight * thresholdRatio;

			//console.info( "NUM ITEMS: " + items.length );
			//console.info( "------> THRESHOLD TOP: " + thresholdTop );

			for ( i; i < length; i++ ) {

				$item = items[i];

				//console.info( $item );
				//console.info( "---> ITEM TOP: " + getElementOffsetTop( $item ) );

				if ( getElementOffsetTop( $item ) <= thresholdTop ) {

					//console.info( "---> ITEM DELAY: ", delay );
					$item.css( "animation-delay", delay.toString() + "s" );
					$item.css( "transition-delay", delay.toString() + "s" );
					delay += staggerTime;
					lastIndex = i;

					var onEnd = function( e ) {
						console.log( "RocketReveal: onEnd" );

						var $target = $( e.currentTarget );

						$target.off( EVENT_ANIMATION_TRANSITION_END, onEnd );
						$target.css( "animation-delay", "" );
						$target.css( "transition-delay", "" );
						$target.removeClass( STYLE_REVEAL )
						$target.removeClass( STYLE_REVEAL_IN );

					}

					$item.on( EVENT_ANIMATION_TRANSITION_END, onEnd );
					$item.addClass( STYLE_REVEAL_IN );

				}

			}

			// Clean Up Array
			if ( lastIndex )
				items.splice( 0, lastIndex + 1 );

		}

		// ----- PUBLIC EVENT LISTENERS ----- //

		/*************************************************
		 * CALL
		 *************************************************/
		init( elem );

		/*************************************************
		 * RETURN
		 *************************************************/
		return {
		 	destroy: destroy,
		 	refreshItems: refreshItems,
		 	updateItems: updateItems
		}

	}

	/*************************************************
	 * jQUERY PLUGIN
	 *************************************************/
	$.fn.rktReveal = function() {

		var mgr = RocketRevealSingleton.getInstance();

		var param0 = arguments[0];
		var param1 = arguments[1];

		this.each( function() {

			if ( typeof( param0 ) !== "string" )
				mgr.add( this );
			else
				mgr.execute( param0, param1 );

		} );

		return this;

	};

}( jQuery ));

<|endoftext|>


<commit_before>// [Working example](/serviceworker-cookbook/push-subscription-management/).

var subscriptionButton = document.getElementById('subscriptionButton');

// As subscription object is needed in few places let's create a method which
// returns a promise.
function getSubscription() {
  return navigator.serviceWorker.ready
    .then(function(registration) {
      return registration.pushManager.getSubscription();
    });
}

// Register service worker and check the initial subscription state.
// Set the UI (button) according to the status.
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js')
    .then(function() {
      console.log('service worker registered');
      subscriptionButton.removeAttribute('disabled');
    });
  getSubscription()
    .then(function(subscription) {
      if (subscription) {
        console.log('Already subscribed', subscription.endpoint);
        setUnsubscribeButton();
      } else {
        setSubscribeButton();
      }
    });
}

// Get the `registration` from service worker and create a new
// subscription using `registration.pushManager.subscribe`. Then
// register received new subscription by sending a POST request with its
// endpoint to the server.
function subscribe() {
  navigator.serviceWorker.ready.then(function(registration) {
    return registration.pushManager.subscribe({ userVisibleOnly: true });
  }).then(function(subscription) {
    console.log('Subscribed', subscription.endpoint);
    return fetch('register', {
      method: 'post',
      headers: {
        'Content-type': 'application/json'
      },
      body: JSON.stringify({
        endpoint: subscription.endpoint
      })
    });
  }).then(setUnsubscribeButton);
}

// Get existing subscription from service worker, unsubscribe
// (`subscription.unsubscribe()`) and unregister it in the server with
// a POST request to stop sending push messages to
// unexisting endpoint.
function unsubscribe() {
  getSubscription().then(function(subscription) {
    return subscription.unsubscribe()
      .then(function() {
        console.log('Unsubscribed', subscription.endpoint);
        return fetch('unregister', {
          method: 'post',
          headers: {
            'Content-type': 'application/json'
          },
          body: JSON.stringify({
            endpoint: subscription.endpoint
          })
        });
      });
  }).then(setSubscribeButton);
}

// Change the subscription button's text and action.
function setSubscribeButton() {
  subscriptionButton.onclick = subscribe;
  subscriptionButton.textContent = 'Subscribe!';
}

function setUnsubscribeButton() {
  subscriptionButton.onclick = unsubscribe;
  subscriptionButton.textContent = 'Unsubscribe!';
}
<commit_msg>Fix broken link in the Push Subscription recipe. Fixes #205<commit_after>// [Working example](/push-subscription-management_demo.html).

var subscriptionButton = document.getElementById('subscriptionButton');

// As subscription object is needed in few places let's create a method which
// returns a promise.
function getSubscription() {
  return navigator.serviceWorker.ready
    .then(function(registration) {
      return registration.pushManager.getSubscription();
    });
}

// Register service worker and check the initial subscription state.
// Set the UI (button) according to the status.
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js')
    .then(function() {
      console.log('service worker registered');
      subscriptionButton.removeAttribute('disabled');
    });
  getSubscription()
    .then(function(subscription) {
      if (subscription) {
        console.log('Already subscribed', subscription.endpoint);
        setUnsubscribeButton();
      } else {
        setSubscribeButton();
      }
    });
}

// Get the `registration` from service worker and create a new
// subscription using `registration.pushManager.subscribe`. Then
// register received new subscription by sending a POST request with its
// endpoint to the server.
function subscribe() {
  navigator.serviceWorker.ready.then(function(registration) {
    return registration.pushManager.subscribe({ userVisibleOnly: true });
  }).then(function(subscription) {
    console.log('Subscribed', subscription.endpoint);
    return fetch('register', {
      method: 'post',
      headers: {
        'Content-type': 'application/json'
      },
      body: JSON.stringify({
        endpoint: subscription.endpoint
      })
    });
  }).then(setUnsubscribeButton);
}

// Get existing subscription from service worker, unsubscribe
// (`subscription.unsubscribe()`) and unregister it in the server with
// a POST request to stop sending push messages to
// unexisting endpoint.
function unsubscribe() {
  getSubscription().then(function(subscription) {
    return subscription.unsubscribe()
      .then(function() {
        console.log('Unsubscribed', subscription.endpoint);
        return fetch('unregister', {
          method: 'post',
          headers: {
            'Content-type': 'application/json'
          },
          body: JSON.stringify({
            endpoint: subscription.endpoint
          })
        });
      });
  }).then(setSubscribeButton);
}

// Change the subscription button's text and action.
function setSubscribeButton() {
  subscriptionButton.onclick = subscribe;
  subscriptionButton.textContent = 'Subscribe!';
}

function setUnsubscribeButton() {
  subscriptionButton.onclick = unsubscribe;
  subscriptionButton.textContent = 'Unsubscribe!';
}
<|endoftext|>


<commit_before>/* Karger's algorithm */
/* Find the minimum cut on a undirected graph */

'use strict';

const fs = require('fs');
const readline = require('readline');

const adjacencyList = [];
const rl = readline.createInterface({
	input: fs.createReadStream('graph.txt'),
});

rl.on('line', (line) => {
	var list = line.split('\t');
	list.shift();
	adjacencyList.push(list);
});

rl.on('close', () => {
	console.log(adjacencyList);
})
<commit_msg>updated karger's min cut<commit_after>/* Karger's algorithm */
/* Find the minimum cut on a undirected graph */

'use strict';

const fs = require('fs');
const readline = require('readline');

const adjacencyList = [];
const edges = [];
const rl = readline.createInterface({
	input: fs.createReadStream('graph.txt'),
});

rl.on('line', (line) => {
	const list = line.split('\t');
	// The last entry is an empty string, remove it.
	list.pop();
	const v = list.shift();
	adjacencyList.push(list);

	for(let u of list) {
		const edge = [v, u];
		edges.push(edge);
	}

});

rl.on('close', () => {
	const minCut = getMinCut(adjacencyList, edges);
	// console.log(minCut);
});

function getMinCut(adjacencyList, edges) {
	if(adjacencyList.length === 2) return;

	const edge = getRandomEdge(edges);
	console.log(edge);
	removeEdge(edges, edge);
}

function getRandomEdge(edges) {
	const index = Math.floor(Math.random() * edges.length);
	return edges[index];
}

function removeEdge(edges, edge) {

}<|endoftext|>


<commit_before>'use strict';

const {homedir} = require('os');
const {readFile} = require('fs/promises');

const {join} = require('path');

const tryToCatch = require('try-to-catch');
const currify = require('currify');
const findUp = require('find-up');
const threadIt = require('thread-it');
const {codeframe} = require('putout');
const putout = threadIt(require.resolve('putout'));

threadIt.init();

// warm up worker cache
transpile('');

const URL = '/api/v1/user-menu';
const DEFAULT_MENU_PATH = join(__dirname, '../static/user-menu.js');

module.exports = currify(async ({menuName}, req, res, next) => {
    if (req.url.indexOf(URL))
        return next();

    const {method} = req;

    if (method === 'GET')
        return await onGET({
            req,
            res,
            menuName,
        });

    next();
});

async function onGET({req, res, menuName}) {
    const {dir} = req.query;
    const url = req.url.replace(URL, '');

    if (url === '/default')
        return sendDefaultMenu(res);

    const [errorFind, currentMenuPath] = await tryToCatch(findUp, [
        menuName,
    ], {cwd: dir});

    if (errorFind && errorFind.code !== 'ENOENT')
        return res
            .status(404)
            .send(e.message);

    const homeMenuPath = join(homedir(), menuName);
    const menuPath = currentMenuPath || homeMenuPath;
    const [e, source] = await tryToCatch(readFile, menuPath, 'utf8');

    if (e && e.code !== 'ENOENT')
        return res
            .status(404)
            .send(e.message);

    if (e)
        return sendDefaultMenu(res);

    const [parseError, result] = await transpile(source);

    if (parseError)
        return res
            .type('js')
            .send(getError(parseError, source));

    res
        .type('js')
        .send(result.code);
}

function getError(error, source) {
    return `
        const e = Error(\`
${codeframe({
        error,
        source,
        highlightCode: false,
    })}
\`);

        e.code = 'frame';

        throw e;
    `;
}

function sendDefaultMenu(res) {
    res.sendFile(DEFAULT_MENU_PATH, {
        cacheControl: false,
    });
}

function transpile(source) {
    return tryToCatch(putout, source, {
        plugins: [
            'convert-esm-to-commonjs',
            'strict-mode',
            'cloudcmd',
        ],
    });
}
<commit_msg>chore(user-menu) lint<commit_after>'use strict';

const {homedir} = require('os');
const {readFile} = require('fs/promises');

const {join} = require('path');

const montag = require('montag');
const tryToCatch = require('try-to-catch');
const currify = require('currify');
const findUp = require('find-up');
const threadIt = require('thread-it');
const {codeframe} = require('putout');
const putout = threadIt(require.resolve('putout'));

threadIt.init();

// warm up worker cache
transpile('');

const URL = '/api/v1/user-menu';
const DEFAULT_MENU_PATH = join(__dirname, '../static/user-menu.js');

module.exports = currify(async ({menuName}, req, res, next) => {
    if (req.url.indexOf(URL))
        return next();

    const {method} = req;

    if (method === 'GET')
        return await onGET({
            req,
            res,
            menuName,
        });

    next();
});

async function onGET({req, res, menuName}) {
    const {dir} = req.query;
    const url = req.url.replace(URL, '');

    if (url === '/default')
        return sendDefaultMenu(res);

    const [errorFind, currentMenuPath] = await tryToCatch(findUp, [
        menuName,
    ], {cwd: dir});

    if (errorFind && errorFind.code !== 'ENOENT')
        return res
            .status(404)
            .send(e.message);

    const homeMenuPath = join(homedir(), menuName);
    const menuPath = currentMenuPath || homeMenuPath;
    const [e, source] = await tryToCatch(readFile, menuPath, 'utf8');

    if (e && e.code !== 'ENOENT')
        return res
            .status(404)
            .send(e.message);

    if (e)
        return sendDefaultMenu(res);

    const [parseError, result] = await transpile(source);

    if (parseError)
        return res
            .type('js')
            .send(getError(parseError, source));

    res
        .type('js')
        .send(result.code);
}

function getError(error, source) {
    return montag`
            const e = Error(\`
${codeframe({
        error,
        source,
        highlightCode: false,
    })}
\`);

        e.code = 'frame';

        throw e;
    `;
}

function sendDefaultMenu(res) {
    res.sendFile(DEFAULT_MENU_PATH, {
        cacheControl: false,
    });
}

async function transpile(source) {
    return await tryToCatch(putout, source, {
        plugins: [
            'convert-esm-to-commonjs',
            'strict-mode',
            'cloudcmd',
        ],
    });
}

<|endoftext|>


<commit_before>const common = require('./../common');
const fs = require("fs");
const path = require("path");

const isObject = function (obj) {
    return obj instanceof Object;
};

const isArray = function (obj) {
    return typeof obj == "object" && obj.constructor == Array;
};

const isNull = function (obj) {
    console.log('isNull: ' + obj);
    return isNotNull(obj) ? false : true;
};

const isNotNull = function (obj) {
    if (null != obj && undefined != obj && '' != obj && 'undefined' != obj && obj.length > 0) {
        return true
    } else {
        return false;
    }

};

const isNvl = function (source, target) {
    if (isNull(source)) {
        return target;
    }
    return source;
};

/**
 * 判断日志目录是否存在，不存在时创建日志目录
 * fs.mkdirSync('creatdir2', 0777); 目录权限（读写权限），默认0777
 * @param dirpath 将创建的目录路径
 * @returns {boolean}
 */
const checkAndCreateDir = function (dirname, authNum) {
    if (isNull(authNum)) {
        authNum = common.AUTH_NUM;
    }
    if (fs.existsSync(dirname)) {
        return true;
    } else {
        if (checkAndCreateDir(path.dirname(dirname), authNum)) {
            fs.mkdirSync(dirname, authNum);
            return true;
        }
    }
};

const Models = {
    isNvl: isNvl,
    isNull: isNull,
    isNotNull: isNotNull,
    isObject: isObject,
    isArray: isArray,
    checkAndCreateDir: checkAndCreateDir
};

module.exports = Models;<commit_msg>删除无用注释<commit_after>const common = require('./../common');
const fs = require("fs");
const path = require("path");

const isObject = function (obj) {
    return obj instanceof Object;
};

const isArray = function (obj) {
    return typeof obj == "object" && obj.constructor == Array;
};

const isNull = function (obj) {
    return isNotNull(obj) ? false : true;
};

const isNotNull = function (obj) {
    if (null != obj && undefined != obj && '' != obj && 'undefined' != obj && obj.length > 0) {
        return true
    } else {
        return false;
    }

};

const nvl = function (source, target) {
    if (isNull(source)) {
        return target;
    }
    return source;
};

/**
 * 判断日志目录是否存在，不存在时创建日志目录
 * fs.mkdirSync('creatdir2', 0777); 目录权限（读写权限），默认0777
 * @param dirpath 将创建的目录路径
 * @returns {boolean}
 */
const checkAndCreateDir = function (dirname, authNum) {
    if (isNull(authNum)) {
        authNum = common.AUTH_NUM;
    }
    if (fs.existsSync(dirname)) {
        return true;
    } else {
        if (checkAndCreateDir(path.dirname(dirname), authNum)) {
            fs.mkdirSync(dirname, authNum);
            return true;
        }
    }
};

const Models = {
    nvl: nvl,
    isNull: isNull,
    isNotNull: isNotNull,
    isObject: isObject,
    isArray: isArray,
    checkAndCreateDir: checkAndCreateDir
};

module.exports = Models;<|endoftext|>


<commit_before><commit_msg>Fix copying questions with rows and columns<commit_after><|endoftext|>