<commit_before>define('tasks_view', ['app'], function (app) {

	var TaskModel = Backbone.Model.extend({
			defaults: {
				'selected': false
			},
			url: function () {
				var id = this.has('id') ? this.get('id') : '';
				return '/task/' + id;
			},
			initialize: function () {
				this.bind('remove', function () {
					this.destroy();
				}, this);
			}
		}),

		TasksCollection = Backbone.Collection.extend({
			model: TaskModel,
			url: function () {
				return 'tasks/';
			}
		}),

		TaskView = Backbone.View.extend({
			tagName: 'li',
			template: '' +
				'
<input type="checkbox" ' +
				'<% if (selected) { %> checked <% } %>' +
				' name="task" value="<%= id %>" />
' +
				'
<%= title %>
',
			formTemplate: '' +
				'
<input type="checkbox" checked name="task" value="<%= id %>" />
' +
				'
<input type="text" name="task_title_<%= id %>" value="<%= title %>" />
',

			events: { 'click :checkbox': 'selectTask' },

			initialize: function () {
				_.bindAll(this, 'selectTask');
			},

			render: function (action) {
				if (action === 'form') {
					this.$el.html(_.template(this.formTemplate, this.model.toJSON()));

				} else if (action === 'class') {
					this.className = this.model.get('new_status') || this.model.get('status');
					this.$el.attr('class', this.className);
				}

				if (action !== 'form') {
					this.$el.html(_.template(this.template, this.model.toJSON()));
				}

				this.$el.attr('task_id', this.model.get('id'));
				return this;
			},

			selectTask: function (e) {
				e.preventDefault();

				// Update selected attribute of a model. That will trigger 'change:selected' event
				// which was binded with 'selectItems' function on the main view.
				this.model.set('selected', !this.model.get('selected'));
			}
		});

	return Backbone.View.extend({
		noTaskTemplate: '
There is not task to do! YaY!
',

		initialize: function (options) {
			var self = this;
			this.parent = options.parent;
			this.broker = options.broker;

			_.bindAll(this, 'selectItems', '_tasksFetched');

			// Define a collection where will be stored a view for each task.
			this._viewsCollection = new Backbone.Collection();

			// Define a collection where will be stored the list of tasks.
			this.tasksCollection = new TasksCollection();

			// Getting the list! Make an initial request to the backend
			// to store all task in the collection as models.
			this.tasksCollection.fetch({
				success: function () {
					self._tasksFetched();
				}
			});

			// Binding events trigger by the user.
			this.tasksCollection.bind('change:selected', this.selectItems);

			// Binding public events to our general Backbone.Event object.
			// Those will be triggered by nav_view.
			this.broker.on('task:create', this.addTask, this);
			this.broker.on('tasks:edit:view', this.editTasks, this);
			this.broker.on('tasks:edit:save', this.saveTasks, this);
			this.broker.on('tasks:status:change', this.changeStatusTasks, this);
			this.broker.on('tasks:remove', this.removeTasks, this);
		},

		_tasksFetched: function () {

			// If there's no tasks in the database we need to display any message
			// telling it. If it gets some tasks we need to create and store a view for each one.

			if (this.$el.children().length !== this.tasksCollection.length &&
				!this.$el.find('.no-task').length) {
				this.render();

			} else {
				this.tasksCollection.each(function (model) {
					// Binding events. Need to create the views.
					this._viewsCollection.add({
						'id': model.get('id'),
						'view': this._getTaskView(model)
					});
				}, this);
			}
		},

		render: function () {
			var self = this;

			// Rendering the entire list of tasks
			// Or a message if there's no tasks.

			this.$el.children().remove();
			this._viewsCollection.reset([]);

			this.tasksCollection.each(function (model) {

				var view = new TaskView({
					model: model,
					className: 'backbone tag ' + model.get('status')
				});

				self._viewsCollection.add({
					'id': model.get('id'),
					'view': view
				});

				this.$el.append(view.render().el);
			}, this);

			if (!this.tasksCollection.length) {
				this.$el.append(this.noTaskTemplate);
			}

			return this;
		},

		selectItems: function (model) {
			var self = this, view = this._viewsCollection.findWhere({'id': model.get('id')}).get('view');

			// If an item has been checked and it's the first one: trigger an event to enable editRemove bar mode.
			// Else, if an item has been unchecked and it was the last element checked: trigger an event to disable
			// editRemove mode and enable addTask instead.

			if (model.get('selected') && this.tasksCollection.where({selected: true}).length === 1) {
				this.broker.trigger('task:select', 'checked');
			} else if (!model.get('selected') && !this.tasksCollection.where({selected: true}).length) {
				this.broker.trigger('task:select', 'unchecked');

				this.editingFormEnable = false;
				this.changingStatusEnable = false;
			}

			// Anytime the user check or uncheck an item and the 'editingForm' view or 'changeStatus' is enable
			// we need to: check/uncheck the item and re-render the view to form/read-only mode and/or restore
			// the original status of the task.

			if (this.editingFormEnable && model.get('selected')) {
				view.render('form');
			} else if (this.changingStatusEnable && model.get('selected')) {
				view.model.set('new_status', this.parent.$el.find('.select select').val());
				view.render('class');
			} else if (this.changingStatusEnable && !model.get('selected')) {
				view.model.set('new_status', undefined);
				view.render('class');
			} else {
				view.render();
			}
		},

		addTask: function (object) {
			var self = this, view;

			// To create a task it needs all the datas (get them in object)
			// and syncronized _viewsCollection with the new view created.
			// Also, append the task to the list generated rendering the view.

			this.tasksCollection.create(object, {
				wait: true,
				success: function (model) {
					view = new TaskView({
						model: model,
						className: model.get('status')
					});

					self._viewsCollection.add({
						'id': model.get('id'),
						'view': view
					});

					if (self.$el.find('.no-task').length) {
						self.$el.children().remove();
					}

					self.$el.prepend(view.render().el);
				}
			});
		},

		editTasks: function () {
			var self = this, view;

			// Event triggered by nav_view. For each task selected in the list it needs to
			// re-render in 'edit' mode. Also need to know that 'EditMode' is enable.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');
				view.render('form');
			});

			this.editingFormEnable = true;
		},

		saveTasks: function (action) {
			var self = this, view, title;

			// Event triggered by nav_view. For each task selected in the list it needs to
			// collect the new datas, they could be 'title' or 'status' and save them in the
			// model of this task. After that, need to render the view to update HTML.
			// Otherwise, if the event is to CANCEL the action, we need to set up 'title'
			// and 'status' to the default value of the task and render it.
			// Also, saving any action means that any 'editMode' has been disabled.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');

				if (action === 'saving') {
					title = view.$el.find('[name=task_title_' + model.get('id') + ']').val();
					if (title) view.model.set('title', title);

					if (view.model.get('new_status')) {
						view.model.set('status', view.model.get('new_status'));
						view.render('class');
						view.model.set('new_status', undefined);
					}
					view.model.save();

				} else {
					// When cancel, need to set the original status on the view.
					view.model.set('new_status', undefined);
					view.render('class');
				}

				view.render();
			});

			this.editingFormEnable = false;
			this.changingFormEnable = false;
		},

		removeTasks: function (action) {
			var self = this, view;

			// Event triggered by nav_view. For each task selected it needs to remove the DOM
			// from the list of tasks and also, need to remove the view/model from all collections.
			// If the main collection (tasksCollection) is empty it needs to render a message telling
			// that there's no tasks on the list.
			// Also, after removing tasks or canceling the current action it needs to disable any
			// 'editMode' in the main view.

			if (action === 'saving') {
				_.each(this.tasksCollection.where({selected:true}), function (model) {
					view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');
					view.remove();
					self._viewsCollection.remove(self._viewsCollection.findWhere({'id': model.get('id')}));
				});

				this.tasksCollection.remove(this.tasksCollection.where({selected:true}));

				if (!this.tasksCollection.length) {
					this.render();
				}
			}

			this.editingFormEnable = false;
			this.changingFormEnable = false;
		},

		changeStatusTasks: function (newStatus) {
			var self = this, view;

			// Event triggered by nav_view. For each task selected it needs to re-render
			// the view appling the new status selected. That doesn't means to save the new
			// status for each tasks (that will be done on saveTasks function)
			// If there's no status in the task it will set up the current one.
			// Also, there's a 'editMode' enable because it's enable the form to change status
			// of some tasks.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');

				if (!newStatus) {
					view.model.set('new_status', undefined);
				} else {
					view.model.set('new_status', newStatus);
				}

				view.render('class');
			});

			this.changingStatusEnable = true;
		},

		_getTaskView: function (model) {

			// Create and return a new task with the model provided.
			return new TaskView({
				el: this.$el.find('[task_id=' + model.get('id') + ']'),
				model: model,
				className: (model.get('new_status') || model.get('status'))
			});
		}
	});

});<commit_msg>Fixed a bug on changing status and unselecting tasks<commit_after>define('tasks_view', ['app'], function (app) {

	var TaskModel = Backbone.Model.extend({
			defaults: {
				'selected': false
			},
			url: function () {
				var id = this.has('id') ? this.get('id') : '';
				return '/task/' + id;
			},
			initialize: function () {
				this.bind('remove', function () {
					this.destroy();
				}, this);
			}
		}),

		TasksCollection = Backbone.Collection.extend({
			model: TaskModel,
			url: function () {
				return 'tasks/';
			}
		}),

		TaskView = Backbone.View.extend({
			tagName: 'li',
			template: '' +
				'
<input type="checkbox" ' +
				'<% if (selected) { %> checked <% } %>' +
				' name="task" value="<%= id %>" />
' +
				'
<%= title %>
',
			formTemplate: '' +
				'
<input type="checkbox" checked name="task" value="<%= id %>" />
' +
				'
<input type="text" name="task_title_<%= id %>" value="<%= title %>" />
',

			events: { 'click :checkbox': 'selectTask' },

			initialize: function () {
				_.bindAll(this, 'selectTask');
			},

			render: function (action) {
				if (action === 'form') {
					this.$el.html(_.template(this.formTemplate, this.model.toJSON()));

				} else if (action === 'class') {
					this.className = this.model.get('new_status') || this.model.get('status');
					this.$el.attr('class', this.className);
				}

				if (action !== 'form') {
					this.$el.html(_.template(this.template, this.model.toJSON()));
				}

				this.$el.attr('task_id', this.model.get('id'));
				return this;
			},

			selectTask: function (e) {
				e.preventDefault();

				// Update selected attribute of a model. That will trigger 'change:selected' event
				// which was binded with 'selectItems' function on the main view.
				this.model.set('selected', !this.model.get('selected'));
			}
		});

	return Backbone.View.extend({
		noTaskTemplate: '
There is not task to do! YaY!
',

		initialize: function (options) {
			var self = this;
			this.parent = options.parent;
			this.broker = options.broker;

			_.bindAll(this, 'selectItems', '_tasksFetched');

			// Define a collection where will be stored a view for each task.
			this._viewsCollection = new Backbone.Collection();

			// Define a collection where will be stored the list of tasks.
			this.tasksCollection = new TasksCollection();

			// Getting the list! Make an initial request to the backend
			// to store all task in the collection as models.
			this.tasksCollection.fetch({
				success: function () {
					self._tasksFetched();
				}
			});

			// Binding events trigger by the user.
			this.tasksCollection.bind('change:selected', this.selectItems);

			// Binding public events to our general Backbone.Event object.
			// Those will be triggered by nav_view.
			this.broker.on('task:create', this.addTask, this);
			this.broker.on('tasks:edit:view', this.editTasks, this);
			this.broker.on('tasks:edit:save', this.saveTasks, this);
			this.broker.on('tasks:status:change', this.changeStatusTasks, this);
			this.broker.on('tasks:remove', this.removeTasks, this);
		},

		_tasksFetched: function () {

			// If there's no tasks in the database we need to display any message
			// telling it. If it gets some tasks we need to create and store a view for each one.

			if (this.$el.children().length !== this.tasksCollection.length &&
				!this.$el.find('.no-task').length) {
				this.render();

			} else {
				this.tasksCollection.each(function (model) {
					// Binding events. Need to create the views.
					this._viewsCollection.add({
						'id': model.get('id'),
						'view': this._getTaskView(model)
					});
				}, this);
			}
		},

		render: function () {
			var self = this;

			// Rendering the entire list of tasks
			// Or a message if there's no tasks.

			this.$el.children().remove();
			this._viewsCollection.reset([]);

			this.tasksCollection.each(function (model) {

				var view = new TaskView({
					model: model,
					className: 'backbone tag ' + model.get('status')
				});

				self._viewsCollection.add({
					'id': model.get('id'),
					'view': view
				});

				this.$el.append(view.render().el);
			}, this);

			if (!this.tasksCollection.length) {
				this.$el.append(this.noTaskTemplate);
			}

			return this;
		},

		selectItems: function (model) {
			var self = this, view = this._viewsCollection.findWhere({'id': model.get('id')}).get('view');

			// If an item has been checked and it's the first one: trigger an event to enable editRemove bar mode.
			// Else, if an item has been unchecked and it was the last element checked: trigger an event to disable
			// editRemove mode and enable addTask instead.

			if (model.get('selected') && this.tasksCollection.where({selected: true}).length === 1) {
				this.broker.trigger('task:select', 'checked');
			} else if (!model.get('selected') && !this.tasksCollection.where({selected: true}).length) {
				this.broker.trigger('task:select', 'unchecked');

				this.editingFormEnable = false;
			}

			// Anytime the user check or uncheck an item and the 'editingForm' view or 'changeStatus' is enable
			// we need to: check/uncheck the item and re-render the view to form/read-only mode and/or restore
			// the original status of the task.

			if (this.editingFormEnable && model.get('selected')) {
				view.render('form');
			} else if (this.changingStatusEnable && model.get('selected')) {
				view.model.set('new_status', this.parent.$el.find('.select select').val());
			} else if (this.changingStatusEnable && !model.get('selected')) {
				view.model.set('new_status', undefined);
				if (!this.tasksCollection.where({selected:true}).length)  this.changingStatusEnable = false;
				view.render('class');
			} else {
				view.render();
			}
		},

		addTask: function (object) {
			var self = this, view;

			// To create a task it needs all the datas (get them in object)
			// and syncronized _viewsCollection with the new view created.
			// Also, append the task to the list generated rendering the view.

			this.tasksCollection.create(object, {
				wait: true,
				success: function (model) {
					view = new TaskView({
						model: model,
						className: model.get('status')
					});

					self._viewsCollection.add({
						'id': model.get('id'),
						'view': view
					});

					if (self.$el.find('.no-task').length) {
						self.$el.children().remove();
					}

					self.$el.prepend(view.render().el);
				}
			});
		},

		editTasks: function () {
			var self = this, view;

			// Event triggered by nav_view. For each task selected in the list it needs to
			// re-render in 'edit' mode. Also need to know that 'EditMode' is enable.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');
				view.render('form');
			});

			this.editingFormEnable = true;
		},

		saveTasks: function (action) {
			var self = this, view, title;

			// Event triggered by nav_view. For each task selected in the list it needs to
			// collect the new datas, they could be 'title' or 'status' and save them in the
			// model of this task. After that, need to render the view to update HTML.
			// Otherwise, if the event is to CANCEL the action, we need to set up 'title'
			// and 'status' to the default value of the task and render it.
			// Also, saving any action means that any 'editMode' has been disabled.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');

				if (action === 'saving') {
					title = view.$el.find('[name=task_title_' + model.get('id') + ']').val();
					if (title) view.model.set('title', title);

					if (view.model.get('new_status')) {
						view.model.set('status', view.model.get('new_status'));
						view.render('class');
						view.model.set('new_status', undefined);
					}
					view.model.save();

				} else {
					// When cancel, need to set the original status on the view.
					view.model.set('new_status', undefined);
					view.render('class');
				}

				view.render();
			});

			this.editingFormEnable = false;
			this.changingFormEnable = false;
		},

		removeTasks: function (action) {
			var self = this, view;

			// Event triggered by nav_view. For each task selected it needs to remove the DOM
			// from the list of tasks and also, need to remove the view/model from all collections.
			// If the main collection (tasksCollection) is empty it needs to render a message telling
			// that there's no tasks on the list.
			// Also, after removing tasks or canceling the current action it needs to disable any
			// 'editMode' in the main view.

			if (action === 'saving') {
				_.each(this.tasksCollection.where({selected:true}), function (model) {
					view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');
					view.remove();
					self._viewsCollection.remove(self._viewsCollection.findWhere({'id': model.get('id')}));
				});

				this.tasksCollection.remove(this.tasksCollection.where({selected:true}));

				if (!this.tasksCollection.length) {
					this.render();
				}
			}

			this.editingFormEnable = false;
			this.changingFormEnable = false;
		},

		changeStatusTasks: function (newStatus) {
			var self = this, view;

			// Event triggered by nav_view. For each task selected it needs to re-render
			// the view appling the new status selected. That doesn't means to save the new
			// status for each tasks (that will be done on saveTasks function)
			// If there's no status in the task it will set up the current one.
			// Also, there's a 'editMode' enable because it's enable the form to change status
			// of some tasks.

			_.each(this.tasksCollection.where({selected:true}), function (model) {
				view = self._viewsCollection.findWhere({'id': model.get('id')}).get('view');

				if (!newStatus) {
					view.model.set('new_status', undefined);
				} else {
					view.model.set('new_status', newStatus);
				}

				view.render('class');
			});

			this.changingStatusEnable = true;
		},

		_getTaskView: function (model) {

			// Create and return a new task with the model provided.
			return new TaskView({
				el: this.$el.find('[task_id=' + model.get('id') + ']'),
				model: model,
				className: (model.get('new_status') || model.get('status'))
			});
		}
	});

});<|endoftext|>


<commit_before>
exports.up = function (knex, Promise) {
    return knex.schema.createTable('users_last_seen', function (t) {
        t.string('id').notNull();
        t.integer('timestamp').notNull().defaultTo(0);
    });
};

exports.down = function (knex, Promise) {
    return knex.schema.dropTable('users_last_seen');
};
<commit_msg>fix timestamps<commit_after>
exports.up = function (knex, Promise) {
    return knex.schema.createTable('users_last_seen', function (t) {
        t.string('id').notNull();
        t.timestamp('timestamp').notNull().defaultTo(0);
    });
};

exports.down = function (knex, Promise) {
    return knex.schema.dropTable('users_last_seen');
};
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    sortPerformersBy(performerSortProperties) {
      this.set('performerSortProperties', [performerSortProperties]);
    },
    penalizeEligibility(performer) {
      performer.penalizeEligibility();
    },
  },
  performerSortProperties: [
    'performer.totPoints:desc',
    'group.chap_name:asc',
  ],
  sortedPerformers: Ember.computed.sort(
    'model.performers',
    'performerSortProperties'
  ),
});
<commit_msg>change default rank<commit_after>import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    sortPerformersBy(performerSortProperties) {
      this.set('performerSortProperties', [performerSortProperties]);
    },
    penalizeEligibility(performer) {
      performer.penalizeEligibility();
    },
  },
  performerSortProperties: [
    'performer.totRank:asc',
    'group.chap_name:asc',
  ],
  sortedPerformers: Ember.computed.sort(
    'model.performers',
    'performerSortProperties'
  ),
});
<|endoftext|>


<commit_before>import config from '../config';
import db from './database';
import Joi from 'joi';

const Users = db.define(
	'Users',
	{
		hashKey: 'userId',
		timestamps: true,
		schema: {
			userId: db.types.uuid(),
			userName: Joi.string(),
			email: Joi.string().email(),
			displayName: Joi.string(),
			passwordHash: Joi.string(),
			role: Joi.string(),
			imageUrl: Joi.string()
		},
		tableName: `divelog-${config.env}-users`,
		indexes: [
			{
				hashKey: 'userName',
				name: 'UserNameIndex',
				type: 'global'
			},
			{
				hashKey: 'email',
				name: 'EmailIndex',
				type: 'global'
			}
		]
	});

export default Users;
<commit_msg>Added fields to users table necessary for password reset.<commit_after>import config from '../config';
import db from './database';
import Joi from 'joi';

const Users = db.define(
	'Users',
	{
		hashKey: 'userId',
		timestamps: true,
		schema: {
			userId: db.types.uuid(),
			userName: Joi.string(),
			email: Joi.string().email(),
			displayName: Joi.string(),
			passwordHash: Joi.string(),
			role: Joi.string(),
			imageUrl: Joi.string(),
			passwordResetToken: Joi.string().alphanum().length(16),
			passwordResetExpiration: Joi.string().isoDate()
		},
		tableName: `divelog-${config.env}-users`,
		indexes: [
			{
				hashKey: 'userName',
				name: 'UserNameIndex',
				type: 'global'
			},
			{
				hashKey: 'email',
				name: 'EmailIndex',
				type: 'global'
			}
		]
	});

export default Users;
<|endoftext|>


<commit_before>angular.module('myApp').service('hiService', [
    function () {
        let MOODS = {
            CRYING: 'crying',
            SAD: 'sad',
            ALRIGHT: 'alright',
            HAPPY: 'happy'
        };

        function getMood (happinessIndex) {
            if ((happinessIndex >= 0) && (happinessIndex < 0.25)) {
                return MOODS.CRYING;
            }

            if ((happinessIndex >= 0.25) && (happinessIndex < 0.5)) {
                return MOODS.SAD;
            }

            if ((happinessIndex >= 0.5) && (happinessIndex < 0.75)) {
                return MOODS.ALRIGHT;
            }

            if ((happinessIndex >= 0.75) && (happinessIndex <= 1)) {
                return MOODS.HAPPY;
            }

            return MOODS.ALRIGHT;
        }

        return {
            MOODS: MOODS,
            getMood: getMood
        };
    }
]);
<commit_msg>new index borders<commit_after>angular.module('myApp').service('hiService', [
    function () {
        let MOODS = {
            CRYING: 'crying',
            SAD: 'sad',
            ALRIGHT: 'alright',
            HAPPY: 'happy'
        };

        function getMood (happinessIndex) {
            if ((happinessIndex >= 0) && (happinessIndex < 0.5)) {
                return MOODS.CRYING;
            }

            if ((happinessIndex >= 0.5) && (happinessIndex < 0.55)) {
                return MOODS.SAD;
            }

            if ((happinessIndex >= 0.55) && (happinessIndex < 0.6)) {
                return MOODS.ALRIGHT;
            }

            if ((happinessIndex >= 0.6) && (happinessIndex <= 1)) {
                return MOODS.HAPPY;
            }

            return MOODS.ALRIGHT;
        }

        return {
            MOODS: MOODS,
            getMood: getMood
        };
    }
]);
<|endoftext|>


<commit_before>(function () {
    const EventEmitter = require("events");

    var services = [];
    var serviceMap = {};

    var activeService = null;
    var currentContent = null;
    var resolvedURL = null;
    var playbackMessage = null;
    var playbackOK = true;
    var player = null;

    var Manager = {
        registerService: function (service) {
            services.push(service);
            serviceMap[service.type] = service;
        },
        getService: function (type) {
            return serviceMap[type];
        },
        hub: new EventEmitter()
    };

    Manager.registerService(require("./sopcast/module.js"));
    Manager.registerService(require("./youtube/module.js"));
    Manager.registerService(require("./torrent/module.js"));

    Manager.getServices = function () {
        return services;
    };
    Manager.play = function (type, url) {
        return new Promise(function (resolve, reject) {
            playbackMessage = "Stopping player...";
            sayStatusChanged();

            player.stop().then(function() {
                for (var s of services) {
                    if (s.type != type) s.terminate();
                }
                var service = Manager.getService(type);
                console.log("Playing: ", url, service.type);

                var content = service.findCachedContent(url);
                currentContent = content;
                activeService = service;

                console.log("Content to play: ", content);

                if (!content) {
                    reject(new Error("Content not found"));
                    return;
                } else {
                    resolve();
                }

                player.showNotification(content.title, "Theater is prearing channel. Sit back and relax please!");

                playbackOK = true;
                playbackMessage = "Resolving media..";
                sayStatusChanged();

                service.start(content).then(function (resolvedContent) {
                    resolvedURL = resolvedContent.url;
                    playbackOK = true;
                    playbackMessage = "Sending media to player...";
                    sayStatusChanged();
                    player.play(resolvedContent.url, {live: resolvedContent.live}).then(function () {
                        playbackMessage = "Media sent to player";
                        sayStatusChanged();
                    }).catch(function (e) {
                        playbackOK = false;
                        playbackMessage = "Failed to play on player: " + e;
                        console.error(e);
                        sayStatusChanged();
                    });
                }).catch(function (e) {
                    playbackOK = false;
                    playbackMessage = "Unable to resolve media to playable stream using backend: " + e;
                    console.error(e);
                    sayStatusChanged();
                });
            }).catch(function (e) {
                playbackOK = false;
                playbackMessage = "Failed to stop current playback: " + e;
                console.error(e);
                sayStatusChanged();
            });
        });
    };

    Manager.resendPlayback = function () {
        return new Promise(function (resolve, reject) {
            if (!resolvedURL) {
                reject(new Error("No URL"));
                return;
            }
            resolve();

            playbackMessage = "Sending media to player...";
            sayStatusChanged();
            player.play(resolvedURL).then(function () {
                playbackMessage = "Media sent to player";
                sayStatusChanged();
            }).catch(function (e) {
                playbackOK = false;
                playbackMessage = "Failed to play on player: " + e;
                console.error(e);
                sayStatusChanged();
            });
        });
    };
    Manager.stop = function () {
        return new Promise(function (resolve, reject) {
            resolve();
            player.stop();
            if (activeService) activeService.terminate();
            currentContent = null;
            resolvedURL = null;

            sayStatusChanged();
        });
    };

    function sayStatusChanged() {
        try {
            setTimeout(function () {
                Manager.hub.emit("status", Manager.getCurrentStatus());
            }, 10);
        } catch (e) {
            console.error(e);
        }
    };

    Manager.getCurrentStatus = function () {
        var status = {};
        if (currentContent) status.content = currentContent;
        if (activeService) {
            status.service = {
                type: activeService.type,
                name: activeService.name,
                status: activeService.getCurrentStatus(),
                backend: activeService.getBackendStatus()
            };
        }

        status.playbackStatus = playbackOK ? "OK" : "Error";
        status.playbackMessage = playbackMessage;

        return status;
    };
    Manager.setPlayer = function (providedPlayer) {
        player = providedPlayer;
    };
    Manager.notifyStatusChange = function () {
        sayStatusChanged();
    };

    module.exports = Manager;
})();
<commit_msg>Fix live content<commit_after>(function () {
    const EventEmitter = require("events");

    var services = [];
    var serviceMap = {};

    var activeService = null;
    var currentContent = null;
    var resolvedURL = null;
    var playbackMessage = null;
    var playbackOK = true;
    var player = null;

    var Manager = {
        registerService: function (service) {
            services.push(service);
            serviceMap[service.type] = service;
        },
        getService: function (type) {
            return serviceMap[type];
        },
        hub: new EventEmitter()
    };

    Manager.registerService(require("./sopcast/module.js"));
    Manager.registerService(require("./youtube/module.js"));
    Manager.registerService(require("./torrent/module.js"));

    Manager.getServices = function () {
        return services;
    };
    Manager.play = function (type, url) {
        return new Promise(function (resolve, reject) {
            playbackMessage = "Stopping player...";
            sayStatusChanged();

            player.stop().then(function() {
                for (var s of services) {
                    if (s.type != type) s.terminate();
                }
                var service = Manager.getService(type);
                console.log("Playing: ", url, service.type);

                var content = service.findCachedContent(url);
                currentContent = content;
                activeService = service;

                console.log("Content to play: ", content);

                if (!content) {
                    reject(new Error("Content not found"));
                    return;
                } else {
                    resolve();
                }

                player.showNotification(content.title, "Theater is prearing channel. Sit back and relax please!");

                playbackOK = true;
                playbackMessage = "Resolving media..";
                sayStatusChanged();

                service.start(content).then(function (resolvedContent) {
                    resolvedURL = resolvedContent.url;
                    playbackOK = true;
                    playbackMessage = "Sending media to player...";
                    sayStatusChanged();
                    player.play(resolvedContent.url, {live: resolvedContent.live}).then(function () {
                        playbackMessage = "Media sent to player";
                        sayStatusChanged();
                    }).catch(function (e) {
                        playbackOK = false;
                        playbackMessage = "Failed to play on player: " + e;
                        console.error(e);
                        sayStatusChanged();
                    });
                }).catch(function (e) {
                    playbackOK = false;
                    playbackMessage = "Unable to resolve media to playable stream using backend: " + e;
                    console.error(e);
                    sayStatusChanged();
                });
            }).catch(function (e) {
                playbackOK = false;
                playbackMessage = "Failed to stop current playback: " + e;
                console.error(e);
                sayStatusChanged();
            });
        });
    };

    Manager.resendPlayback = function () {
        return new Promise(function (resolve, reject) {
            if (!resolvedURL) {
                reject(new Error("No URL"));
                return;
            }
            resolve();

            playbackMessage = "Sending media to player...";
            sayStatusChanged();
            player.play(resolvedURL, {live: resolvedContent && resolvedContent.live}).then(function () {
                playbackMessage = "Media sent to player";
                sayStatusChanged();
            }).catch(function (e) {
                playbackOK = false;
                playbackMessage = "Failed to play on player: " + e;
                console.error(e);
                sayStatusChanged();
            });
        });
    };
    Manager.stop = function () {
        return new Promise(function (resolve, reject) {
            resolve();
            player.stop();
            if (activeService) activeService.terminate();
            currentContent = null;
            resolvedURL = null;

            sayStatusChanged();
        });
    };

    function sayStatusChanged() {
        try {
            setTimeout(function () {
                Manager.hub.emit("status", Manager.getCurrentStatus());
            }, 10);
        } catch (e) {
            console.error(e);
        }
    };

    Manager.getCurrentStatus = function () {
        var status = {};
        if (currentContent) status.content = currentContent;
        if (activeService) {
            status.service = {
                type: activeService.type,
                name: activeService.name,
                status: activeService.getCurrentStatus(),
                backend: activeService.getBackendStatus()
            };
        }

        status.playbackStatus = playbackOK ? "OK" : "Error";
        status.playbackMessage = playbackMessage;

        return status;
    };
    Manager.setPlayer = function (providedPlayer) {
        player = providedPlayer;
    };
    Manager.notifyStatusChange = function () {
        sayStatusChanged();
    };

    module.exports = Manager;
})();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014, Raghu Nayyar <beingminimal@gmail.com>
 * Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
 * This file is licensed under the Affero General Public License version 3 or later.
 * See the COPYING-README file.
 */

var $userGroupList,
	$sortGroupBy;

var GroupList;
GroupList = {
	activeGID: '',
	everyoneGID: '_everyone',
	filter: '',
	filterGroups: false,

	addGroup: function (gid, usercount) {
		var $li = $userGroupList.find('.isgroup:last-child').clone();
		$li
			.data('gid', gid)
			.find('.groupname').text(gid);
		GroupList.setUserCount($li, usercount);

		$li.appendTo($userGroupList);

		GroupList.sortGroups();

		return $li;
	},

	setUserCount: function (groupLiElement, usercount) {
		if ($sortGroupBy !== 1) {
			// If we don't sort by group count we don't display them either
			return;
		}

		var $groupLiElement = $(groupLiElement);
		if (usercount === undefined || usercount === 0 || usercount < 0) {
			usercount = '';
			$groupLiElement.data('usercount', 0);
		} else {
			$groupLiElement.data('usercount', usercount);
		}
		$groupLiElement.find('.usercount').text(usercount);
	},

	getUserCount: function ($groupLiElement) {
		return parseInt($groupLiElement.data('usercount'), 10);
	},

	modGroupCount: function(gid, diff) {
		var $li = GroupList.getGroupLI(gid);
		var count = GroupList.getUserCount($li) + diff;
		GroupList.setUserCount($li, count);
	},

	incEveryoneCount: function() {
		GroupList.modGroupCount(GroupList.everyoneGID, 1);
	},

	decEveryoneCount: function() {
		GroupList.modGroupCount(GroupList.everyoneGID, -1);
	},

	incGroupCount: function(gid) {
		GroupList.modGroupCount(gid, 1);
	},

	decGroupCount: function(gid) {
		GroupList.modGroupCount(gid, -1);
	},

	getCurrentGID: function () {
		return GroupList.activeGID;
	},

	sortGroups: function () {
		var lis = $userGroupList.find('.isgroup').get();

		lis.sort(function (a, b) {
			// "Everyone" always at the top
			if ($(a).data('gid') === '_everyone') {
				return -1;
			} else if ($(b).data('gid') === '_everyone') {
				return 1;
			}

			// "admin" always as second
			if ($(a).data('gid') === 'admin') {
				return -1;
			} else if ($(b).data('gid') === 'admin') {
				return 1;
			}

			if ($sortGroupBy === 1) {
				// Sort by user count first
				var $usersGroupA = $(a).data('usercount'),
					$usersGroupB = $(b).data('usercount');
				if ($usersGroupA > 0 && $usersGroupA > $usersGroupB) {
					return -1;
				}
				if ($usersGroupB > 0 && $usersGroupB > $usersGroupA) {
					return 1;
				}
			}

			// Fallback or sort by group name
			return UserList.alphanum(
				$(a).find('a span').text(),
				$(b).find('a span').text()
			);
		});

		var items = [];
		$.each(lis, function (index, li) {
			items.push(li);
			if (items.length === 100) {
				$userGroupList.append(items);
				items = [];
			}
		});
		if (items.length > 0) {
			$userGroupList.append(items);
		}
	},

	createGroup: function (groupname) {
		$.post(
			OC.generateUrl('/settings/users/groups'),
			{
				id: groupname
			},
			function (result) {
				if (result.groupname) {
					var addedGroup = result.groupname;
					UserList.availableGroups = $.unique($.merge(UserList.availableGroups, [addedGroup]));
					GroupList.addGroup(result.groupname);
				}
				GroupList.toggleAddGroup();
			}).fail(function(result) {
				OC.Notification.showTemporary(t('settings', 'Error creating group: {message}', {message: result.responseJSON.message}));
			});
	},

	update: function () {
		if (GroupList.updating) {
			return;
		}
		GroupList.updating = true;
		$.get(
			OC.generateUrl('/settings/users/groups'),
			{
				pattern: this.filter,
				filterGroups: this.filterGroups ? 1 : 0,
				sortGroups: $sortGroupBy
			},
			function (result) {

				var lis = [];
				if (result.status === 'success') {
					$.each(result.data, function (i, subset) {
						$.each(subset, function (index, group) {
							if (GroupList.getGroupLI(group.name).length > 0) {
								GroupList.setUserCount(GroupList.getGroupLI(group.name).first(), group.usercount);
							}
							else {
								var $li = GroupList.addGroup(group.name, group.usercount);

								$li.addClass('appear transparent');
								lis.push($li);
							}
						});
					});
					if (result.data.length > 0) {
						GroupList.doSort();
					}
					else {
						GroupList.noMoreEntries = true;
					}
					_.defer(function () {
						$(lis).each(function () {
							this.removeClass('transparent');
						});
					});
				}
				GroupList.updating = false;

			}
		);
	},

	elementBelongsToAddGroup: function (el) {
		return !(el !== $('#newgroup-form').get(0) &&
		$('#newgroup-form').find($(el)).length === 0);
	},

	hasAddGroupNameText: function () {
		var name = $('#newgroupname').val();
		return $.trim(name) !== '';

	},

	showGroup: function (gid) {
		GroupList.activeGID = gid;
		UserList.empty();
		UserList.update(gid);
		$userGroupList.find('li').removeClass('active');
		if (gid !== undefined) {
			//TODO: treat Everyone properly
			GroupList.getGroupLI(gid).addClass('active');
		}
	},

	isAddGroupButtonVisible: function () {
		return $('#newgroup-init').is(":visible");
	},

	toggleAddGroup: function (event) {
		if (GroupList.isAddGroupButtonVisible()) {
			event.stopPropagation();
			$('#newgroup-form').show();
			$('#newgroup-init').hide();
			$('#newgroupname').focus();
			GroupList.handleAddGroupInput('');
		}
		else {
			$('#newgroup-form').hide();
			$('#newgroup-init').show();
			$('#newgroupname').val('');
		}
	},

	handleAddGroupInput: function (input) {
		if(input.length) {
			$('#newgroup-form input[type="submit"]').attr('disabled', null);
		} else {
			$('#newgroup-form input[type="submit"]').attr('disabled', 'disabled');
		}
	},

	isGroupNameValid: function (groupname) {
		if ($.trim(groupname) === '') {
			OC.Notification.showTemporary(t('settings', 'Error creating group: {message}', {
				message: t('settings', 'A valid group name must be provided')
			}));
			return false;
		}
		return true;
	},

	hide: function (gid) {
		GroupList.getGroupLI(gid).hide();
	},
	show: function (gid) {
		GroupList.getGroupLI(gid).show();
	},
	remove: function (gid) {
		GroupList.getGroupLI(gid).remove();
	},
	empty: function () {
		$userGroupList.find('.isgroup').filter(function(index, item){
			return $(item).data('gid') !== '';
		}).remove();
	},
	initDeleteHandling: function () {
		//set up handler
		GroupDeleteHandler = new DeleteHandler('/settings/users/groups', 'groupname',
			GroupList.hide, GroupList.remove);

		//configure undo
		OC.Notification.hide();
		var msg = escapeHTML(t('settings', 'deleted {groupName}', {groupName: '%oid'})) + '' +
			escapeHTML(t('settings', 'undo')) + '';
		GroupDeleteHandler.setNotification(OC.Notification, 'deletegroup', msg,
			GroupList.show);

		//when to mark user for delete
		$userGroupList.on('click', '.delete', function () {
			// Call function for handling delete/undo
			GroupDeleteHandler.mark(GroupList.getElementGID(this));
		});

		//delete a marked user when leaving the page
		$(window).on('beforeunload', function () {
			GroupDeleteHandler.deleteEntry();
		});
	},

	getGroupLI: function (gid) {
		return $userGroupList.find('li.isgroup').filter(function () {
			return GroupList.getElementGID(this) === gid;
		});
	},

	getElementGID: function (element) {
		return ($(element).closest('li').data('gid') || '').toString();
	},
	getEveryoneCount: function () {
		$.ajax({
			type: "GET",
			dataType: "json",
			url: OC.generateUrl('/settings/users/stats')
		}).success(function (data) {
			$('#everyonegroup').data('usercount', data.totalUsers);
			$('#everyonecount').text(data.totalUsers);
		});
	}
};

$(document).ready( function () {
	$userGroupList = $('#usergrouplist');
	GroupList.initDeleteHandling();
	$sortGroupBy = $userGroupList.data('sort-groups');
	if ($sortGroupBy === 1) {
		// Disabled due to performance issues, when we don't need it for sorting
		GroupList.getEveryoneCount();
	}

	// Display or hide of Create Group List Element
	$('#newgroup-form').hide();
	$('#newgroup-init').on('click', function (e) {
		GroupList.toggleAddGroup(e);
	});

	$(document).on('click keydown keyup', function(event) {
		if(!GroupList.isAddGroupButtonVisible() &&
			!GroupList.elementBelongsToAddGroup(event.target) &&
			!GroupList.hasAddGroupNameText()) {
			GroupList.toggleAddGroup();
		}
		// Escape
		if(!GroupList.isAddGroupButtonVisible() && event.keyCode && event.keyCode === 27) {
			GroupList.toggleAddGroup();
		}
	});

	// Responsible for Creating Groups.
	$('#newgroup-form form').submit(function (event) {
		event.preventDefault();
		if(GroupList.isGroupNameValid($('#newgroupname').val())) {
			GroupList.createGroup($('#newgroupname').val());
		}
	});

	// click on group name
	$userGroupList.on('click', '.isgroup', function () {
		GroupList.showGroup(GroupList.getElementGID(this));
	});

	$('#newgroupname').on('input', function(){
		GroupList.handleAddGroupInput(this.value);
	});
});
<commit_msg>allow group named "0" to be deleted<commit_after>/**
 * Copyright (c) 2014, Raghu Nayyar <beingminimal@gmail.com>
 * Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com>
 * This file is licensed under the Affero General Public License version 3 or later.
 * See the COPYING-README file.
 */

var $userGroupList,
	$sortGroupBy;

var GroupList;
GroupList = {
	activeGID: '',
	everyoneGID: '_everyone',
	filter: '',
	filterGroups: false,

	addGroup: function (gid, usercount) {
		var $li = $userGroupList.find('.isgroup:last-child').clone();
		$li
			.data('gid', gid)
			.attr('data-gid', gid)
			.find('.groupname').text(gid);
		GroupList.setUserCount($li, usercount);

		$li.appendTo($userGroupList);

		GroupList.sortGroups();

		return $li;
	},

	setUserCount: function (groupLiElement, usercount) {
		if ($sortGroupBy !== 1) {
			// If we don't sort by group count we don't display them either
			return;
		}

		var $groupLiElement = $(groupLiElement);
		if (usercount === undefined || usercount === 0 || usercount < 0) {
			usercount = '';
			$groupLiElement.data('usercount', 0);
		} else {
			$groupLiElement.data('usercount', usercount);
		}
		$groupLiElement.find('.usercount').text(usercount);
	},

	getUserCount: function ($groupLiElement) {
		return parseInt($groupLiElement.data('usercount'), 10);
	},

	modGroupCount: function(gid, diff) {
		var $li = GroupList.getGroupLI(gid);
		var count = GroupList.getUserCount($li) + diff;
		GroupList.setUserCount($li, count);
	},

	incEveryoneCount: function() {
		GroupList.modGroupCount(GroupList.everyoneGID, 1);
	},

	decEveryoneCount: function() {
		GroupList.modGroupCount(GroupList.everyoneGID, -1);
	},

	incGroupCount: function(gid) {
		GroupList.modGroupCount(gid, 1);
	},

	decGroupCount: function(gid) {
		GroupList.modGroupCount(gid, -1);
	},

	getCurrentGID: function () {
		return GroupList.activeGID;
	},

	sortGroups: function () {
		var lis = $userGroupList.find('.isgroup').get();

		lis.sort(function (a, b) {
			// "Everyone" always at the top
			if ($(a).data('gid') === '_everyone') {
				return -1;
			} else if ($(b).data('gid') === '_everyone') {
				return 1;
			}

			// "admin" always as second
			if ($(a).data('gid') === 'admin') {
				return -1;
			} else if ($(b).data('gid') === 'admin') {
				return 1;
			}

			if ($sortGroupBy === 1) {
				// Sort by user count first
				var $usersGroupA = $(a).data('usercount'),
					$usersGroupB = $(b).data('usercount');
				if ($usersGroupA > 0 && $usersGroupA > $usersGroupB) {
					return -1;
				}
				if ($usersGroupB > 0 && $usersGroupB > $usersGroupA) {
					return 1;
				}
			}

			// Fallback or sort by group name
			return UserList.alphanum(
				$(a).find('a span').text(),
				$(b).find('a span').text()
			);
		});

		var items = [];
		$.each(lis, function (index, li) {
			items.push(li);
			if (items.length === 100) {
				$userGroupList.append(items);
				items = [];
			}
		});
		if (items.length > 0) {
			$userGroupList.append(items);
		}
	},

	createGroup: function (groupname) {
		$.post(
			OC.generateUrl('/settings/users/groups'),
			{
				id: groupname
			},
			function (result) {
				if (result.groupname) {
					var addedGroup = result.groupname;
					UserList.availableGroups = $.unique($.merge(UserList.availableGroups, [addedGroup]));
					GroupList.addGroup(result.groupname);
				}
				GroupList.toggleAddGroup();
			}).fail(function(result) {
				OC.Notification.showTemporary(t('settings', 'Error creating group: {message}', {message: result.responseJSON.message}));
			});
	},

	update: function () {
		if (GroupList.updating) {
			return;
		}
		GroupList.updating = true;
		$.get(
			OC.generateUrl('/settings/users/groups'),
			{
				pattern: this.filter,
				filterGroups: this.filterGroups ? 1 : 0,
				sortGroups: $sortGroupBy
			},
			function (result) {

				var lis = [];
				if (result.status === 'success') {
					$.each(result.data, function (i, subset) {
						$.each(subset, function (index, group) {
							if (GroupList.getGroupLI(group.name).length > 0) {
								GroupList.setUserCount(GroupList.getGroupLI(group.name).first(), group.usercount);
							}
							else {
								var $li = GroupList.addGroup(group.name, group.usercount);

								$li.addClass('appear transparent');
								lis.push($li);
							}
						});
					});
					if (result.data.length > 0) {
						GroupList.doSort();
					}
					else {
						GroupList.noMoreEntries = true;
					}
					_.defer(function () {
						$(lis).each(function () {
							this.removeClass('transparent');
						});
					});
				}
				GroupList.updating = false;

			}
		);
	},

	elementBelongsToAddGroup: function (el) {
		return !(el !== $('#newgroup-form').get(0) &&
		$('#newgroup-form').find($(el)).length === 0);
	},

	hasAddGroupNameText: function () {
		var name = $('#newgroupname').val();
		return $.trim(name) !== '';

	},

	showGroup: function (gid) {
		GroupList.activeGID = gid;
		UserList.empty();
		UserList.update(gid);
		$userGroupList.find('li').removeClass('active');
		if (gid !== undefined) {
			//TODO: treat Everyone properly
			GroupList.getGroupLI(gid).addClass('active');
		}
	},

	isAddGroupButtonVisible: function () {
		return $('#newgroup-init').is(":visible");
	},

	toggleAddGroup: function (event) {
		if (GroupList.isAddGroupButtonVisible()) {
			event.stopPropagation();
			$('#newgroup-form').show();
			$('#newgroup-init').hide();
			$('#newgroupname').focus();
			GroupList.handleAddGroupInput('');
		}
		else {
			$('#newgroup-form').hide();
			$('#newgroup-init').show();
			$('#newgroupname').val('');
		}
	},

	handleAddGroupInput: function (input) {
		if(input.length) {
			$('#newgroup-form input[type="submit"]').attr('disabled', null);
		} else {
			$('#newgroup-form input[type="submit"]').attr('disabled', 'disabled');
		}
	},

	isGroupNameValid: function (groupname) {
		if ($.trim(groupname) === '') {
			OC.Notification.showTemporary(t('settings', 'Error creating group: {message}', {
				message: t('settings', 'A valid group name must be provided')
			}));
			return false;
		}
		return true;
	},

	hide: function (gid) {
		GroupList.getGroupLI(gid).hide();
	},
	show: function (gid) {
		GroupList.getGroupLI(gid).show();
	},
	remove: function (gid) {
		GroupList.getGroupLI(gid).remove();
	},
	empty: function () {
		$userGroupList.find('.isgroup').filter(function(index, item){
			return $(item).data('gid') !== '';
		}).remove();
	},
	initDeleteHandling: function () {
		//set up handler
		GroupDeleteHandler = new DeleteHandler('/settings/users/groups', 'groupname',
			GroupList.hide, GroupList.remove);

		//configure undo
		OC.Notification.hide();
		var msg = escapeHTML(t('settings', 'deleted {groupName}', {groupName: '%oid'})) + '' +
			escapeHTML(t('settings', 'undo')) + '';
		GroupDeleteHandler.setNotification(OC.Notification, 'deletegroup', msg,
			GroupList.show);

		//when to mark user for delete
		$userGroupList.on('click', '.delete', function () {
			// Call function for handling delete/undo
			GroupDeleteHandler.mark(GroupList.getElementGID(this));
		});

		//delete a marked user when leaving the page
		$(window).on('beforeunload', function () {
			GroupDeleteHandler.deleteEntry();
		});
	},

	getGroupLI: function (gid) {
		return $userGroupList.find('li.isgroup').filter(function () {
			return GroupList.getElementGID(this) === gid;
		});
	},

	getElementGID: function (element) {
		return ($(element).closest('li').attr('data-gid') || '').toString();
	},
	getEveryoneCount: function () {
		$.ajax({
			type: "GET",
			dataType: "json",
			url: OC.generateUrl('/settings/users/stats')
		}).success(function (data) {
			$('#everyonegroup').data('usercount', data.totalUsers);
			$('#everyonecount').text(data.totalUsers);
		});
	}
};

$(document).ready( function () {
	$userGroupList = $('#usergrouplist');
	GroupList.initDeleteHandling();
	$sortGroupBy = $userGroupList.data('sort-groups');
	if ($sortGroupBy === 1) {
		// Disabled due to performance issues, when we don't need it for sorting
		GroupList.getEveryoneCount();
	}

	// Display or hide of Create Group List Element
	$('#newgroup-form').hide();
	$('#newgroup-init').on('click', function (e) {
		GroupList.toggleAddGroup(e);
	});

	$(document).on('click keydown keyup', function(event) {
		if(!GroupList.isAddGroupButtonVisible() &&
			!GroupList.elementBelongsToAddGroup(event.target) &&
			!GroupList.hasAddGroupNameText()) {
			GroupList.toggleAddGroup();
		}
		// Escape
		if(!GroupList.isAddGroupButtonVisible() && event.keyCode && event.keyCode === 27) {
			GroupList.toggleAddGroup();
		}
	});

	// Responsible for Creating Groups.
	$('#newgroup-form form').submit(function (event) {
		event.preventDefault();
		if(GroupList.isGroupNameValid($('#newgroupname').val())) {
			GroupList.createGroup($('#newgroupname').val());
		}
	});

	// click on group name
	$userGroupList.on('click', '.isgroup', function () {
		GroupList.showGroup(GroupList.getElementGID(this));
	});

	$('#newgroupname').on('input', function(){
		GroupList.handleAddGroupInput(this.value);
	});
});
<|endoftext|>


<commit_before>/**
 * Ember Tiny Auth
 *
 * TODO: eventually move this out into it's own code base
 */
(function() {

'use strict';

var Storage = {};
var Authenticator = {};
var Authorizer = {};

/**
 * Storage base class.
 *
 * @class
 * @abstract
 */
Storage.Base = Ember.Object.extend(Ember.Evented, {
  /**
   * Persist data. You should implement this function to persist the data
   * somehow between requests.
   *
   * @function
   * @abstract
   * @param {object} data Data to persist.
   */
  persist: function(/*data*/) { throw new Error('implement persist'); },

  /**
   * Restore data. You should implement this function to return data that was
   * previously persisted.
   *
   * @function
   * @abstract
   * @return {object} The previously persisted data.
   */
  restore: function() { throw new Error('implement restore'); },

  /**
   * Clear data. You should implement this function to clear data that was
   * previously persisted.
   *
   * @function
   * @abstract
   */
  clear: function() { throw new Error('implement clear'); }
});

Storage.Local = Storage.Base.extend({
  init: function() {
    this._super();
    this._watchStorage();
  },

  persist: function(data) {
    localStorage.setItem('auth-data', JSON.stringify(data));
  },

  restore: function() {
    return JSON.parse(localStorage.getItem('auth-data'));
  },

  clear: function() { localStorage.removeItem('auth-data'); },

  _watchStorage: function() {
    Ember.$(window).on('storage', function() {
      this.trigger('change');
    }.bind(this));
  }
});

/**
 * Authenticator base class.
 *
 * @class
 * @abstract
 */
Authenticator.Base = Ember.Object.extend({
  /**
   * Authenticate a user. This method must be implemented by a concrete
   * subclass of the base authenticator.
   *
   * @function
   * @abstract
   * @param {object} credentials Provided by the application and could vary.
   * Your authenticator should use these values to make a request to the server
   * and authenticate the user.
   * @return {Ember.RSVP.Promise} A promise that, when resolved, indicates that
   * the user has been authenticated and the application can begin to make
   * requests as that user. The data that this promise resolves with will be
   * stored in the session as `sessionData` which can later be used by the
   * authorizer to authorize requests.
   */
  authenticate: function(/*credentials*/) {
    return Ember.RSVP.reject('implement authenticate');
  },

  /**
   * Invalidate a session. This method may be implemented by a concrete
   * subclass of the base authenticator. An implementation, for instance, would
   * allow communicating with the server to invalidate the session or track
   * when a user logs out. Regardless of the server's response, the session
   * data will be cleared on the client side.
   *
   * @function
   * @return {Ember.RSVP.Promise} A promise that, when resolved, indicates that
   * the session has been invalidated. The promise need not be resolved with
   * any value.
   */
  invalidate: function(/*content*/) {
    return Ember.RSVP.resolve();
  }
});

/**
 * Authorizer base class. Base authorizer can be used, but does nothing.
 *
 * @class
 */
Authorizer.Base = Ember.Object.extend({
  /**
   * The session that should be used to store authorization data. This will be
   * set automatically, but you can use it from your implementation of
   * `authorize` in order to access or update the session's `authorizedData`.
   *
   * @type {Session}
   */
  session: function() {
    return this.container.lookup('auth-session:main');
  }.property(),

  /**
   * Setup AJAX requests to authorize users. During the authorization process
   * you can get or set `content` on the session to allow authorization to work
   * across multiple browser sessions.
   *
   * @function
   * @param {jqXHR} jqXHR jQuery XMLHTTPRequest object.
   * @param {object} requestOptions Request options.
   */
  authorize: function(/*jqXHR, requestOptions*/) {
  },

  /**
   * Authorizers can set this value to support session login without requiring
   * invoking the authorize method. This can typically be supported by pulling
   * authorization information out of HTTP response headers when the server's
   * authentication method provides it in the response. The authorizer will not
   * have knowledge of which requests are related to login, though.
   *
   * @type {object}
   */
  capturedAuthorization: undefined,
});

/**
 * Authentication Session. The session acts as a proxy to the underlying
 * content that's stored in the storage. You can therefore access data that's
 * been set on the session (which usually comes from resolution value of
 * Authenticator.prototype.authenticate). The underlying data should be
 * considered read-only. If you need to alter it, consider using
 * Session.prototype.integrateContent.
 *
 * @class
 */
var Session = Ember.ObjectProxy.extend({
  attemptedTransition: null,

  /**
   * @private
   * @type {Object}
   */
  content: {},

  init: function() {
    this._super();
    this._installPrefilter();
  },

  storage: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.storage);
  }.property(),

  authenticator: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.authenticator);
  }.property(),

  authorizer: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.authorizer);
  }.property(),

  /**
   * Whether the user is authenticated.
   *
   * @return {boolean}
   */
  isAuthenticated: function() {
    return Ember.keys(this.get('content')).length > 0;
  }.property('content'),

  /**
   * Authenticate a user. This will result in the authenticator authenticating
   * the user using the given credentials. Successful resolution by the
   * authenticator will result in the resolve value being stored to the
   * configured storage.
   *
   * Once authenticated, you can access the `attemptedTransition` on the
   * session to see if you should redirect the user back to a route they were
   * trying to reach.
   *
   * @param {object} credentials Credentials that will be passed to the
   * authenticator.
   * @return {Ember.RSVP.Promise} A promise indicating wither or not the
   * underlying authenticator succeeded. The resolved value for the promise
   * will match that of what was given by the authenticator.
   */
  authenticate: function(credentials) {
    return this.get('authenticator').authenticate(credentials)
    .then(function(data) {
      this.set('content', data);
      return data;
    }.bind(this));
  },

  /**
   * Login without explicitly invoking the authenticator's `authenticate`
   * method. In order for this to work, the authorizer needs to support
   * capturing authorization data as requests are passed back and forth with
   * the server. This method will throw an exception if the authorizer does not
   * support capturing authorization data.
   *
   * @param {object} data Data to append to the authorization data that will
   * be stored in the session.
   */
  login: function(data) {
    var authorizer = this.get('authorizer');
    var captured = authorizer.get('capturedAuthorization');
    if (!captured) {
      throw new Error('Authorization information not captured by authorizer.');
    }
    this.set('content', Ember.$.extend({}, data, captured));
  },

  /**
   * Invalidate a session. This will result in the authenticator having an
   * opportunity to process invalidation. Session data will be cleared
   * regardless of whether the resulting promise resolves successfully or
   * rejects.
   *
   * @function
   * @return {Ember.RSVP.Promise} A promise indicating whether or not the
   * underlying authenticator succeeded.
   */
  invalidate: function() {
    var clear = function() {
      this.set('content', {});
      this.get('authenticator').set('capturedAuthorization', undefined);
      this.get('storage').clear();
    }.bind(this);
    return this.get('authenticator').invalidate(this.get('content'))
    .then(clear, function(e) { clear(); throw e; });
  },

  /**
   * Integrate new content. This method integrates the provided content into
   * the session's current content. It will add new values from the provided
   * content and overwrite any values in the current content with those from
   * the provided content. It does so shallowly. You should prefer this method
   * over other ways of merging content.
   *
   * Integration of content will only occur if the session is already
   * authenticated. Otherwise the content will simply be ignored.
   *
   * @function
   * @param {object} content New content values to integrate.
   */
  integrateContent: function(content) {
    if (this.get('isAuthenticated')) {
      this.set('content', Ember.$.extend({}, content, this.get('content')));
    }
  },

  /**
   * Restores the session's content to what's stored in the storage.
   *
   * @function
   */
  restore: function() {
    var storage = this.get('storage');
    var content = storage.restore() || {};
    this.set('content', content);
  },

  /**
   * Restores the session's content and observes changes to the storage as
   * well. Changes to the storage will cause an automatic restore.
   *
   * @function
   * @private
   */
  observeStorage: function() {
    var storage = this.get('storage');
    storage.off('change', this, this.restore);
    storage.on('change', this, this.restore);
  },

  _contentChanged: function() {
    this.get('storage').persist(this.get('content'));
  }.observes('content'),

  _installPrefilter: function() {
    Ember.$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
      if (this.isDestroyed || options.crossDomain) { return; }
      this.get('authorizer').authorize(jqXHR, options);
    }.bind(this));
  }
});

/**
 * Authenticated Route Mixin. This should be used to protect routes that
 * require authentication. This will set the property `attemptedTransition`
 * on the session which you can use from your route that actual performs
 * authentication to transition back to where the user came from.
 *
 * @type Mixin
 */
var AuthenticatedRouteMixin = Ember.Mixin.create({
  beforeModel: function(transition) {
    this._super();
    if (!this.get('session').get('isAuthenticated')) {
      this.get('session').set('attemptedTransition', transition);
      this.transitionTo('login');
    }
  }
});

/**
 * Setup function. Sets up all required functionality for authentication
 * support and makes `session` available on controllers and routes.
 *
 * @function
 * @param {Ember.Container} container
 * @param {Ember.Application} application
 * @param {string} [options.authenticator] Authenticator factory
 * @param {string} [options.authorizer] Authorizer factory
 * @param {string} [options.storage] Storage factory
 */
var setup = function(container, application, options) {
  var opts = Ember.$.extend({}, {
    authenticator: 'auth-session-authenticator:base',
    authorizer: 'auth-session-authorizer:base',
    storage: 'auth-session-storage:local'
  }, options);
  application.register('auth-session-settings:main', opts, { instantiate: false });
  application.register('auth-session:main', Session);
  application.register('auth-session-authenticator:base', Authenticator);
  application.register('auth-session-authorizer:base', Authorizer);
  application.register('auth-session-storage:local', Storage.Local);
  application.inject('controller', 'session', 'auth-session:main');
  application.inject('route', 'session', 'auth-session:main');

  var session = container.lookup('auth-session:main');
  session.restore();
  session.observeStorage();
};

Ember.TinyAuth = {
  setup: setup,
  Storage: Storage,
  Authenticator: Authenticator,
  Authorizer: Authorizer,
  AuthenticatedRouteMixin: AuthenticatedRouteMixin
};

}());

/**
 * Admit One
 *
 * TODO: make API endpoints customizable
 */
(function() {
'use strict';

var Auth = Ember.TinyAuth;
var AdmitOne = Ember.AdmitOne = Ember.AdmitOne || {};

// expose everything in tiny-auth to admit-one users. we'll end up overwriting
// some of the pieces in here, but they'll serve the same purposes, and
// advanced uses should directly access tiny-auth.
Ember.$.extend(AdmitOne, Auth);

var extractAuthorizationHeader = function(xhr) {
  var authorization = xhr.getResponseHeader('Authorization');
  var tokenMatch = authorization && authorization.match(/\s*token\s+(.*)\s*/i);
  var token = tokenMatch && tokenMatch[1];
  var invalidated = authorization && !!authorization.match(/\s*invalidated\s*/i);
  return [token, invalidated];
};

AdmitOne.Authenticator = Auth.Authenticator.Base.extend({
  authenticate: function(credentials) {
    return new Ember.RSVP.Promise(function(resolve, reject) {
      Ember.$.ajax('/api/v1/sessions', {
        method: 'post',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify({ session: credentials })
      })
      .then(
        function(data, status, xhr) {
          var extracted = extractAuthorizationHeader(xhr);
          var token = extracted[0];
          resolve({
            email: data.session.email,
            token: token
          });
        },
        function(xhr, status, error) { reject(error); });
    });
  },

  invalidate: function(/*data*/) {
    return new Ember.RSVP.Promise(function(resolve, reject) {
      Ember.$.ajax('/api/v1/sessions/current', {
        method: 'delete',
        contentType: 'application/json; charset=utf-8'
      })
      .then(
        function() { resolve(); },
        function(xhr, status, error) { reject(error); });
    });
  }
});

AdmitOne.Authorizer = Auth.Authorizer.Base.extend(Ember.Evented, {

  /**
   * Handle authentication token for all incoming and outgoing ajax requests.
   * Store the token when we receive it, and send it in all future requests.
   * Clear the token when it's invalidated.
   */
  authorize: function(jqXHR, options) {
    var session = this.get('session');
    var token = session.get('token');
    if (token) {
      options.beforeSend = (function(beforeSend) {
        return function(xhr) {
          xhr.setRequestHeader('Authorization', 'Token ' + token);
          return beforeSend.apply(this, arguments);
        };
      })(options.beforeSend || function() {});
    }

    options.success = options.success || [];
    options.success = Ember.$.isArray(options.success) ? options.success : [options.success];
    options.success.unshift(function(data, status, xhr) {
      var extracted = extractAuthorizationHeader(xhr);
      var token = extracted[0];
      var invalidated = extracted[1];
      if (invalidated) { session.invalidate(); }
      else if (token) {
        this.trigger('authorization-token', token);
        this.set('capturedAuthorization', { token: token });
        session.integrateContent({ token: token });
      }
    }.bind(this));
  }

});

}());

/**
 * Admit One Initialization
 */
(function() {

Ember.AdmitOne.setup = function(configuraiton) {
  Ember.$.extend(configuraiton, {
    authenticator: 'auth-session-authenticator:admit-one',
    authorizer: 'auth-session-authorizer:admit-one',
    storage: 'auth-session-storage:local'
  });
  Ember.Application.initializer({
    name: 'admit-one',
    initialize: function(container, application) {
      var admit = Ember.AdmitOne;
      var Authenticator = admit.Authenticator;
      var Authorizer = admit.Authorizer;
      application.register('auth-session-authenticator:admit-one', Authenticator);
      application.register('auth-session-authorizer:admit-one', Authorizer);
      Ember.TinyAuth.setup(container, application, configuraiton);
    }
  });
};

}());
<commit_msg>Added options to setup.<commit_after>/**
 * Ember Tiny Auth
 *
 * TODO: eventually move this out into it's own code base
 */
(function() {

'use strict';

var Storage = {};
var Authenticator = {};
var Authorizer = {};

/**
 * Storage base class.
 *
 * @class
 * @abstract
 */
Storage.Base = Ember.Object.extend(Ember.Evented, {
  /**
   * Persist data. You should implement this function to persist the data
   * somehow between requests.
   *
   * @function
   * @abstract
   * @param {object} data Data to persist.
   */
  persist: function(/*data*/) { throw new Error('implement persist'); },

  /**
   * Restore data. You should implement this function to return data that was
   * previously persisted.
   *
   * @function
   * @abstract
   * @return {object} The previously persisted data.
   */
  restore: function() { throw new Error('implement restore'); },

  /**
   * Clear data. You should implement this function to clear data that was
   * previously persisted.
   *
   * @function
   * @abstract
   */
  clear: function() { throw new Error('implement clear'); }
});

Storage.Local = Storage.Base.extend({
  init: function() {
    this._super();
    this._watchStorage();
  },

  persist: function(data) {
    localStorage.setItem('auth-data', JSON.stringify(data));
  },

  restore: function() {
    return JSON.parse(localStorage.getItem('auth-data'));
  },

  clear: function() { localStorage.removeItem('auth-data'); },

  _watchStorage: function() {
    Ember.$(window).on('storage', function() {
      this.trigger('change');
    }.bind(this));
  }
});

/**
 * Authenticator base class.
 *
 * @class
 * @abstract
 */
Authenticator.Base = Ember.Object.extend({
  /**
   * Authenticate a user. This method must be implemented by a concrete
   * subclass of the base authenticator.
   *
   * @function
   * @abstract
   * @param {object} credentials Provided by the application and could vary.
   * Your authenticator should use these values to make a request to the server
   * and authenticate the user.
   * @return {Ember.RSVP.Promise} A promise that, when resolved, indicates that
   * the user has been authenticated and the application can begin to make
   * requests as that user. The data that this promise resolves with will be
   * stored in the session as `sessionData` which can later be used by the
   * authorizer to authorize requests.
   */
  authenticate: function(/*credentials*/) {
    return Ember.RSVP.reject('implement authenticate');
  },

  /**
   * Invalidate a session. This method may be implemented by a concrete
   * subclass of the base authenticator. An implementation, for instance, would
   * allow communicating with the server to invalidate the session or track
   * when a user logs out. Regardless of the server's response, the session
   * data will be cleared on the client side.
   *
   * @function
   * @return {Ember.RSVP.Promise} A promise that, when resolved, indicates that
   * the session has been invalidated. The promise need not be resolved with
   * any value.
   */
  invalidate: function(/*content*/) {
    return Ember.RSVP.resolve();
  }
});

/**
 * Authorizer base class. Base authorizer can be used, but does nothing.
 *
 * @class
 */
Authorizer.Base = Ember.Object.extend({
  /**
   * The session that should be used to store authorization data. This will be
   * set automatically, but you can use it from your implementation of
   * `authorize` in order to access or update the session's `authorizedData`.
   *
   * @type {Session}
   */
  session: function() {
    return this.container.lookup('auth-session:main');
  }.property(),

  /**
   * Setup AJAX requests to authorize users. During the authorization process
   * you can get or set `content` on the session to allow authorization to work
   * across multiple browser sessions.
   *
   * @function
   * @param {jqXHR} jqXHR jQuery XMLHTTPRequest object.
   * @param {object} requestOptions Request options.
   */
  authorize: function(/*jqXHR, requestOptions*/) {
  },

  /**
   * Authorizers can set this value to support session login without requiring
   * invoking the authorize method. This can typically be supported by pulling
   * authorization information out of HTTP response headers when the server's
   * authentication method provides it in the response. The authorizer will not
   * have knowledge of which requests are related to login, though.
   *
   * @type {object}
   */
  capturedAuthorization: undefined,
});

/**
 * Authentication Session. The session acts as a proxy to the underlying
 * content that's stored in the storage. You can therefore access data that's
 * been set on the session (which usually comes from resolution value of
 * Authenticator.prototype.authenticate). The underlying data should be
 * considered read-only. If you need to alter it, consider using
 * Session.prototype.integrateContent.
 *
 * @class
 */
var Session = Ember.ObjectProxy.extend({
  attemptedTransition: null,

  /**
   * @private
   * @type {Object}
   */
  content: {},

  init: function() {
    this._super();
    this._installPrefilter();
  },

  storage: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.storage);
  }.property(),

  authenticator: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.authenticator);
  }.property(),

  authorizer: function() {
    var options = this.container.lookup('auth-session-settings:main');
    return this.container.lookup(options.authorizer);
  }.property(),

  /**
   * Whether the user is authenticated.
   *
   * @return {boolean}
   */
  isAuthenticated: function() {
    return Ember.keys(this.get('content')).length > 0;
  }.property('content'),

  /**
   * Authenticate a user. This will result in the authenticator authenticating
   * the user using the given credentials. Successful resolution by the
   * authenticator will result in the resolve value being stored to the
   * configured storage.
   *
   * Once authenticated, you can access the `attemptedTransition` on the
   * session to see if you should redirect the user back to a route they were
   * trying to reach.
   *
   * @param {object} credentials Credentials that will be passed to the
   * authenticator.
   * @return {Ember.RSVP.Promise} A promise indicating wither or not the
   * underlying authenticator succeeded. The resolved value for the promise
   * will match that of what was given by the authenticator.
   */
  authenticate: function(credentials) {
    return this.get('authenticator').authenticate(credentials)
    .then(function(data) {
      this.set('content', data);
      return data;
    }.bind(this));
  },

  /**
   * Login without explicitly invoking the authenticator's `authenticate`
   * method. In order for this to work, the authorizer needs to support
   * capturing authorization data as requests are passed back and forth with
   * the server. This method will throw an exception if the authorizer does not
   * support capturing authorization data.
   *
   * @param {object} data Data to append to the authorization data that will
   * be stored in the session.
   */
  login: function(data) {
    var authorizer = this.get('authorizer');
    var captured = authorizer.get('capturedAuthorization');
    if (!captured) {
      throw new Error('Authorization information not captured by authorizer.');
    }
    this.set('content', Ember.$.extend({}, data, captured));
  },

  /**
   * Invalidate a session. This will result in the authenticator having an
   * opportunity to process invalidation. Session data will be cleared
   * regardless of whether the resulting promise resolves successfully or
   * rejects.
   *
   * @function
   * @return {Ember.RSVP.Promise} A promise indicating whether or not the
   * underlying authenticator succeeded.
   */
  invalidate: function() {
    var clear = function() {
      this.set('content', {});
      this.get('authenticator').set('capturedAuthorization', undefined);
      this.get('storage').clear();
    }.bind(this);
    return this.get('authenticator').invalidate(this.get('content'))
    .then(clear, function(e) { clear(); throw e; });
  },

  /**
   * Integrate new content. This method integrates the provided content into
   * the session's current content. It will add new values from the provided
   * content and overwrite any values in the current content with those from
   * the provided content. It does so shallowly. You should prefer this method
   * over other ways of merging content.
   *
   * Integration of content will only occur if the session is already
   * authenticated. Otherwise the content will simply be ignored.
   *
   * @function
   * @param {object} content New content values to integrate.
   */
  integrateContent: function(content) {
    if (this.get('isAuthenticated')) {
      this.set('content', Ember.$.extend({}, content, this.get('content')));
    }
  },

  /**
   * Restores the session's content to what's stored in the storage.
   *
   * @function
   */
  restore: function() {
    var storage = this.get('storage');
    var content = storage.restore() || {};
    this.set('content', content);
  },

  /**
   * Restores the session's content and observes changes to the storage as
   * well. Changes to the storage will cause an automatic restore.
   *
   * @function
   * @private
   */
  observeStorage: function() {
    var storage = this.get('storage');
    storage.off('change', this, this.restore);
    storage.on('change', this, this.restore);
  },

  _contentChanged: function() {
    this.get('storage').persist(this.get('content'));
  }.observes('content'),

  _installPrefilter: function() {
    Ember.$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
      if (this.isDestroyed || options.crossDomain) { return; }
      this.get('authorizer').authorize(jqXHR, options);
    }.bind(this));
  }
});

/**
 * Authenticated Route Mixin. This should be used to protect routes that
 * require authentication. This will set the property `attemptedTransition`
 * on the session which you can use from your route that actual performs
 * authentication to transition back to where the user came from.
 *
 * @type Mixin
 */
var AuthenticatedRouteMixin = Ember.Mixin.create({
  beforeModel: function(transition) {
    this._super();
    if (!this.get('session').get('isAuthenticated')) {
      this.get('session').set('attemptedTransition', transition);
      this.transitionTo('login');
    }
  }
});

/**
 * Setup function. Sets up all required functionality for authentication
 * support and makes `session` available on controllers and routes.
 *
 * @function
 * @param {Ember.Container} container
 * @param {Ember.Application} application
 * @param {string} [options.authenticator] Authenticator factory
 * @param {string} [options.authorizer] Authorizer factory
 * @param {string} [options.storage] Storage factory
 */
var setup = function(container, application, options) {
  var opts = Ember.$.extend({}, {
    authenticator: 'auth-session-authenticator:base',
    authorizer: 'auth-session-authorizer:base',
    storage: 'auth-session-storage:local'
  }, options);
  application.register('auth-session-settings:main', opts, { instantiate: false });
  application.register('auth-session:main', Session);
  application.register('auth-session-authenticator:base', Authenticator);
  application.register('auth-session-authorizer:base', Authorizer);
  application.register('auth-session-storage:local', Storage.Local);
  application.inject('controller', 'session', 'auth-session:main');
  application.inject('route', 'session', 'auth-session:main');

  var session = container.lookup('auth-session:main');
  session.restore();
  session.observeStorage();
};

Ember.TinyAuth = {
  setup: setup,
  Storage: Storage,
  Authenticator: Authenticator,
  Authorizer: Authorizer,
  AuthenticatedRouteMixin: AuthenticatedRouteMixin
};

}());

/**
 * Admit One
 *
 * TODO: make API endpoints customizable
 */
(function() {
'use strict';

var Auth = Ember.TinyAuth;
var AdmitOne = Ember.AdmitOne = Ember.AdmitOne || {};

// expose everything in tiny-auth to admit-one users. we'll end up overwriting
// some of the pieces in here, but they'll serve the same purposes, and
// advanced uses should directly access tiny-auth.
Ember.$.extend(AdmitOne, Auth);

var extractAuthorizationHeader = function(xhr) {
  var authorization = xhr.getResponseHeader('Authorization');
  var tokenMatch = authorization && authorization.match(/\s*token\s+(.*)\s*/i);
  var token = tokenMatch && tokenMatch[1];
  var invalidated = authorization && !!authorization.match(/\s*invalidated\s*/i);
  return [token, invalidated];
};

AdmitOne.Authenticator = Auth.Authenticator.Base.extend({
  authenticate: function(credentials) {
    var settings = this.container.lookup('admit-one-settings:main');
    var authenticateURL = settings.api.authenticate;
    return new Ember.RSVP.Promise(function(resolve, reject) {
      Ember.$.ajax(authenticateURL, {
        method: 'post',
        contentType: 'application/json; charset=utf-8',
        data: JSON.stringify({ session: credentials })
      })
      .then(
        function(data, status, xhr) {
          var extracted = extractAuthorizationHeader(xhr);
          var token = extracted[0];
          resolve(Ember.$.extend({}, data.session, {
            token: token
          }));
        },
        function(xhr, status, error) { reject(error); });
    });
  },

  invalidate: function(/*data*/) {
    var settings = this.container.lookup('admit-one-settings:main');
    var invalidateURL = settings.api.invalidate;
    return new Ember.RSVP.Promise(function(resolve, reject) {
      Ember.$.ajax(invalidateURL, {
        method: 'delete',
        contentType: 'application/json; charset=utf-8'
      })
      .then(
        function() { resolve(); },
        function(xhr, status, error) { reject(error); });
    });
  }
});

AdmitOne.Authorizer = Auth.Authorizer.Base.extend(Ember.Evented, {

  /**
   * Handle authentication token for all incoming and outgoing ajax requests.
   * Store the token when we receive it, and send it in all future requests.
   * Clear the token when it's invalidated.
   */
  authorize: function(jqXHR, options) {
    var session = this.get('session');
    var token = session.get('token');
    if (token) {
      options.beforeSend = (function(beforeSend) {
        return function(xhr) {
          xhr.setRequestHeader('Authorization', 'Token ' + token);
          return beforeSend.apply(this, arguments);
        };
      })(options.beforeSend || function() {});
    }

    options.success = options.success || [];
    options.success = Ember.$.isArray(options.success) ? options.success : [options.success];
    options.success.unshift(function(data, status, xhr) {
      var extracted = extractAuthorizationHeader(xhr);
      var token = extracted[0];
      var invalidated = extracted[1];
      if (invalidated) { session.invalidate(); }
      else if (token) {
        this.trigger('authorization-token', token);
        this.set('capturedAuthorization', { token: token });
        session.integrateContent({ token: token });
      }
    }.bind(this));
  }

});

}());

/**
 * Admit One Initialization
 */
(function() {

Ember.AdmitOne.setup = function(options) {
  var opts = options || {};

  opts.containers = Ember.$.extend(opts.containers || {}, {
    authenticator: 'auth-session-authenticator:admit-one',
    authorizer: 'auth-session-authorizer:admit-one',
    storage: 'auth-session-storage:local'
  });

  if (Ember.typeOf(opts.api) === 'string') {
    opts.api = { endpoint: opts.api };
  }
  opts.api = opts.api || {};
  opts.api.endpoint = opts.api.endpoint || '/api';
  opts.api.authenticate = opts.api.authenticate ||
    opts.api.endpoint + '/sessions';
  opts.api.invalidate = opts.api.invalidate ||
    opts.api.endpoint + '/sessions/current';

  Ember.Application.initializer({
    name: 'admit-one',
    initialize: function(container, application) {
      var admit = Ember.AdmitOne;
      var Authenticator = admit.Authenticator;
      var Authorizer = admit.Authorizer;
      application.register('auth-session-authenticator:admit-one', Authenticator);
      application.register('auth-session-authorizer:admit-one', Authorizer);
      application.register('admit-one-settings:main', opts, { instantiate: false });
      Ember.TinyAuth.setup(container, application, opts.containers);
    }
  });
};

}());
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Ads DOM Remover
// @namespace    sagiegurari
// @version      0.64
// @author       Sagie Gur-Ari
// @description  Removes Ad Containers from DOM (doesn't replace adblocker extension, but blocks dynamic content which the adblocker fails to block by removing whole sections from the HTML DOM.)
// @homepage     https://github.com/sagiegurari/userscripts-ads-dom-remover
// @supportURL   https://github.com/sagiegurari/userscripts-ads-dom-remover/issues
// @match        http://www.ynet.co.il/home/*
// @match        http://www.ynet.co.il/articles/*
// @match        http://www.calcalist.co.il/*
// @match        http://www.globes.co.il/*
// @match        https://sourceforge.net/projects/*/download*
// @match        http://subscenter.cinemast.com/*
// @require      https://code.jquery.com/jquery-2.2.2.min.js
// @require https://greasyfork.org/scripts/18490-ads-dom-remover-runner/code/Ads%20DOM%20Remover%20Runner.js?version=122502
// @grant        none
// @license      MIT License
// ==/UserScript==

(function run($, runner) {
    'use strict';

    var selectorDefinitions = {
        ynet: [
            '#colorbox',
            '#cboxOverlay',
            '#ads.premium',
            'img[src*="dynamicyield"]',
            'div.MSCmainContent',
            '[id*="arketingCarouse"]',
            '[id*="arketingRecommended"]',
            '.mainVerticalArticleSharingLinks',
            '.OUTBRAIN',
            '.topBannerWrap',
            '.block.B3 .B3.ghcite.dyother.dyMonitor div',
            '.bigdealhomepage',
            '#ww6s_Main',
            '.buyandsavedy',
            '.area.footer.ghcite',
            '.hdr_set_homepage',
            '#c1_Hor',
            '#c2_Hor',
            '#c3_Hor',
            '#c4_Hor',
            '#c5_Hor',
            '#c6_Hor',
            '.homepagevideo-x6',
            '.buyandsave',
            '.general-image',
            '.PhotoArticlesTalkbacks',
            '[name="ExternalWebpageIframe"]',
            {
                selector: 'iframe',
                filter: function ($element) {
                    return !$element.parent().hasClass('news_ticker_iframe');
                }
            },
            {
                selector: 'div.B2b.block div',
                pre: function ($element) {
                    $element.parent().css({
                        height: '1px'
                    });
                }
            }
        ],
        globes: [
            '#chromeWindow',
            {
                selector: 'iframe',
                filter: function ($element) {
                    var id = $element.attr('id');
                    var src = $element.attr('src') || '';

                    return (id !== 'GlobalFinanceData_home') && (src.indexOf('/news/') !== -1);
                }
            }
        ],
        sourceforge: [
            '#content-for-adblock'
        ],
        subscenter: [
            '.weekBottom',
            '.reviewsWindow',
            '#banner_cinemast',
            '.bottomMenu',
            'footer',
            '#paypal',
            '#aboveSite'
        ]
    };

    Object.keys(selectorDefinitions).forEach(function (id) {
        selectorDefinitions[id] = {
            id: id,
            selectors: selectorDefinitions[id]
        };
    });

    runner($, {
        getSelectors: function (hostName) {
            var selectors;
            if (hostName.indexOf('globes') !== -1) {
                selectors = selectorDefinitions.globes;
            } else if (hostName.indexOf('sourceforge.net') !== -1) {
                selectors = selectorDefinitions.sourceforge;
            } else if (hostName.indexOf('subscenter.cinemast.com') !== -1) {
                selectors = selectorDefinitions.subscenter;
            } else { //ynet/calcalist
                selectors = selectorDefinitions.ynet;
            }

            return selectors;
        }
    });
}(window.jQuery.noConflict(true), window.adrRunner));
<commit_msg>bump versions<commit_after>// ==UserScript==
// @name         Ads DOM Remover
// @namespace    sagiegurari
// @version      0.65
// @author       Sagie Gur-Ari
// @description  Removes Ad Containers from DOM (doesn't replace adblocker extension, but blocks dynamic content which the adblocker fails to block by removing whole sections from the HTML DOM.)
// @homepage     https://github.com/sagiegurari/userscripts-ads-dom-remover
// @supportURL   https://github.com/sagiegurari/userscripts-ads-dom-remover/issues
// @match        http://www.ynet.co.il/home/*
// @match        http://www.ynet.co.il/articles/*
// @match        http://www.calcalist.co.il/*
// @match        http://www.globes.co.il/*
// @match        https://sourceforge.net/projects/*/download*
// @match        http://subscenter.cinemast.com/*
// @require      https://code.jquery.com/jquery-2.2.2.min.js
// @require https://greasyfork.org/scripts/18490-ads-dom-remover-runner/code/Ads%20DOM%20Remover%20Runner.js?version=122507
// @grant        none
// @license      MIT License
// ==/UserScript==

(function run($, runner) {
    'use strict';

    var selectorDefinitions = {
        ynet: [
            '#colorbox',
            '#cboxOverlay',
            '#ads.premium',
            'img[src*="dynamicyield"]',
            'div.MSCmainContent',
            '[id*="arketingCarouse"]',
            '[id*="arketingRecommended"]',
            '.mainVerticalArticleSharingLinks',
            '.OUTBRAIN',
            '.topBannerWrap',
            '.block.B3 .B3.ghcite.dyother.dyMonitor div',
            '.bigdealhomepage',
            '#ww6s_Main',
            '.buyandsavedy',
            '.area.footer.ghcite',
            '.hdr_set_homepage',
            '#c1_Hor',
            '#c2_Hor',
            '#c3_Hor',
            '#c4_Hor',
            '#c5_Hor',
            '#c6_Hor',
            '.homepagevideo-x6',
            '.buyandsave',
            '.general-image',
            '.PhotoArticlesTalkbacks',
            '[name="ExternalWebpageIframe"]',
            {
                selector: 'iframe',
                filter: function ($element) {
                    return !$element.parent().hasClass('news_ticker_iframe');
                }
            },
            {
                selector: 'div.B2b.block div',
                pre: function ($element) {
                    $element.parent().css({
                        height: '1px'
                    });
                }
            }
        ],
        globes: [
            '#chromeWindow',
            {
                selector: 'iframe',
                filter: function ($element) {
                    var id = $element.attr('id');
                    var src = $element.attr('src') || '';

                    return (id !== 'GlobalFinanceData_home') && (src.indexOf('/news/') !== -1);
                }
            }
        ],
        sourceforge: [
            '#content-for-adblock'
        ],
        subscenter: [
            '.weekBottom',
            '.reviewsWindow',
            '#banner_cinemast',
            '.bottomMenu',
            'footer',
            '#paypal',
            '#aboveSite'
        ]
    };

    Object.keys(selectorDefinitions).forEach(function (id) {
        selectorDefinitions[id] = {
            id: id,
            selectors: selectorDefinitions[id]
        };
    });

    runner($, {
        getSelectors: function (hostName) {
            var selectors;
            if (hostName.indexOf('globes') !== -1) {
                selectors = selectorDefinitions.globes;
            } else if (hostName.indexOf('sourceforge.net') !== -1) {
                selectors = selectorDefinitions.sourceforge;
            } else if (hostName.indexOf('subscenter.cinemast.com') !== -1) {
                selectors = selectorDefinitions.subscenter;
            } else { //ynet/calcalist
                selectors = selectorDefinitions.ynet;
            }

            return selectors;
        }
    });
}(window.jQuery.noConflict(true), window.adrRunner));
<|endoftext|>