<commit_before>
var ambigDateOfMonthRegex = /^\s*\d{4}-\d\d$/;
var ambigTimeOrZoneRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/;

// Creating
// -------------------------------------------------------------------------------------------------

// Creates a new moment, similar to the vanilla moment(...) constructor, but with
// extra features (ambiguous time, enhanced formatting). When gived an existing moment,
// it will function as a clone (and retain the zone of the moment). Anything else will
// result in a moment in the local zone.
fc.moment = function() {
	return makeMoment(arguments);
};

// Sames as fc.moment, but forces the resulting moment to be in the UTC timezone.
fc.moment.utc = function() {
	var mom = makeMoment(arguments, true);

	// Force it into UTC because makeMoment doesn't guarantee it.
	if (mom.hasTime()) { // don't give ambiguously-timed moments a UTC zone
		mom.utc();
	}

	return mom;
};

// Same as fc.moment, but when given an ISO8601 string, the timezone offset is preserved.
// ISO8601 strings with no timezone offset will become ambiguously zoned.
fc.moment.parseZone = function() {
	return makeMoment(arguments, true, true);
};

// Builds an FCMoment from args. When given an existing moment, it clones. When given a native
// Date, or called with no arguments (the current time), the resulting moment will be local.
// Anything else needs to be "parsed" (a string or an array), and will be affected by:
//    parseAsUTC - if there is no zone information, should we parse the input in UTC?
//    parseZone - if there is zone information, should we force the zone of the moment?
function makeMoment(args, parseAsUTC, parseZone) {
	var input = args[0];
	var isSingleString = args.length == 1 && typeof input === 'string';
	var isAmbigTime;
	var isAmbigZone;
	var ambigMatch;
	var output; // an object with fields for the new FCMoment object

	if (moment.isMoment(input)) {
		output = moment.apply(null, args); // clone it

		// the ambig properties have not been preserved in the clone, so reassign them
		if (input._ambigTime) {
			output._ambigTime = true;
		}
		if (input._ambigZone) {
			output._ambigZone = true;
		}
	}
	else if (isNativeDate(input) || input === undefined) {
		output = moment.apply(null, args); // will be local
	}
	else { // "parsing" is required
		isAmbigTime = false;
		isAmbigZone = false;

		if (isSingleString) {
			if (ambigDateOfMonthRegex.test(input)) {
				// accept strings like '2014-05', but convert to the first of the month
				input += '-01';
				args = [ input ]; // for when we pass it on to moment's constructor
				isAmbigTime = true;
				isAmbigZone = true;
			}
			else if ((ambigMatch = ambigTimeOrZoneRegex.exec(input))) {
				isAmbigTime = !ambigMatch[5]; // no time part?
				isAmbigZone = true;
			}
		}
		else if ($.isArray(input)) {
			// arrays have no timezone information, so assume ambiguous zone
			isAmbigZone = true;
		}
		// otherwise, probably a string with a format

		if (parseAsUTC) {
			output = moment.utc.apply(moment, args);
		}
		else {
			output = moment.apply(null, args);
		}

		if (isAmbigTime) {
			output._ambigTime = true;
			output._ambigZone = true; // ambiguous time always means ambiguous zone
		}
		else if (parseZone) { // let's record the inputted zone somehow
			if (isAmbigZone) {
				output._ambigZone = true;
			}
			else if (isSingleString) {
				output.zone(input); // if not a valid zone, will assign UTC
			}
		}
	}

	return new FCMoment(output);
}

// Our subclass of Moment.
// Accepts an object with the internal Moment properties that should be copied over to
// `this` object (most likely another Moment object). The values in this data must not
// be referenced by anything else (two moments sharing a Date object for example).
function FCMoment(internalData) {
	extend(this, internalData);
}

// Chain the prototype to Moment's
FCMoment.prototype = createObject(moment.fn);

// We need this because Moment's implementation won't create an FCMoment,
// nor will it copy over the ambig flags.
FCMoment.prototype.clone = function() {
	return makeMoment([ this ]);
};

// Time-of-day
// -------------------------------------------------------------------------------------------------

// GETTER
// Returns a Duration with the hours/minutes/seconds/ms values of the moment.
// If the moment has an ambiguous time, a duration of 00:00 will be returned.
//
// SETTER
// You can supply a Duration, a Moment, or a Duration-like argument.
// When setting the time, and the moment has an ambiguous time, it then becomes unambiguous.
FCMoment.prototype.time = function(time) {
	if (time == null) { // getter
		return moment.duration({
			hours: this.hours(),
			minutes: this.minutes(),
			seconds: this.seconds(),
			milliseconds: this.milliseconds()
		});
	}
	else { // setter

		delete this._ambigTime; // mark that the moment now has a time

		if (!moment.isDuration(time) && !moment.isMoment(time)) {
			time = moment.duration(time);
		}

		// The day value should cause overflow (so 24 hours becomes 00:00:00 of next day).
		// Only for Duration times, not Moment times.
		var dayHours = 0;
		if (moment.isDuration(time)) {
			dayHours = Math.floor(time.asDays()) * 24;
		}

		// We need to set the individual fields.
		// Can't use startOf('day') then add duration. In case of DST at start of day.
		return this.hours(dayHours + time.hours())
			.minutes(time.minutes())
			.seconds(time.seconds())
			.milliseconds(time.milliseconds());
	}
};

// Converts the moment to UTC, stripping out its time-of-day and timezone offset,
// but preserving its YMD. A moment with a stripped time will display no time
// nor timezone offset when .format() is called.
FCMoment.prototype.stripTime = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array

	// set the internal UTC flag
	moment.fn.utc.call(this); // call the original method, because we don't want to affect _ambigZone

	this._ambigTime = true;
	this._ambigZone = true; // if ambiguous time, also ambiguous timezone offset

	this.year(a[0]) // TODO: find a way to do this in one shot
		.month(a[1])
		.date(a[2])
		.hours(0)
		.minutes(0)
		.seconds(0)
		.milliseconds(0);

	return this; // for chaining
};

// Returns if the moment has a non-ambiguous time (boolean)
FCMoment.prototype.hasTime = function() {
	return !this._ambigTime;
};

// Timezone
// -------------------------------------------------------------------------------------------------

// Converts the moment to UTC, stripping out its timezone offset, but preserving its
// YMD and time-of-day. A moment with a stripped timezone offset will display no
// timezone offset when .format() is called.
FCMoment.prototype.stripZone = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array
	var wasAmbigTime = this._ambigTime;

	moment.fn.utc.call(this); // set the internal UTC flag

	this.year(a[0]) // TODO: find a way to do this in one shot
		.month(a[1])
		.date(a[2])
		.hours(a[3])
		.minutes(a[4])
		.seconds(a[5])
		.milliseconds(a[6]);

	if (wasAmbigTime) {
		// the above call to .utc()/.zone() unfortunately clears the ambig flags, so reassign
		this._ambigTime = true;
	}

	// Mark the zone as ambiguous. This needs to happen after the .utc() call, which calls .zone(), which
	// clears all ambig flags. Same concept with the .year/month/date calls in the case of moment-timezone.
	this._ambigZone = true;

	return this; // for chaining
};

// Returns of the moment has a non-ambiguous timezone offset (boolean)
FCMoment.prototype.hasZone = function() {
	return !this._ambigZone;
};

// this method implicitly marks a zone
FCMoment.prototype.zone = function(tzo) {

	if (tzo != null) {
		// FYI, the delete statements need to be before the .zone() call or else chaos ensues
		// for reasons I don't understand.
		delete this._ambigTime;
		delete this._ambigZone;
	}

	return moment.fn.zone.apply(this, arguments);
};

// this method implicitly marks a zone
FCMoment.prototype.local = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array
	var wasAmbigZone = this._ambigZone;

	// will happen anyway via .local()/.zone(), but don't want to rely on internal implementation
	delete this._ambigTime;
	delete this._ambigZone;

	moment.fn.local.apply(this, arguments);

	if (wasAmbigZone) {
		// If the moment was ambiguously zoned, the date fields were stored as UTC.
		// We want to preserve these, but in local time.
		this.year(a[0]) // TODO: find a way to do this in one shot
			.month(a[1])
			.date(a[2])
			.hours(a[3])
			.minutes(a[4])
			.seconds(a[5])
			.milliseconds(a[6]);
	}

	return this; // for chaining
};

// this method implicitly marks a zone
FCMoment.prototype.utc = function() {

	// will happen anyway via .local()/.zone(), but don't want to rely on internal implementation
	delete this._ambigTime;
	delete this._ambigZone;

	return moment.fn.utc.apply(this, arguments);
};

// Formatting
// -------------------------------------------------------------------------------------------------

FCMoment.prototype.format = function() {
	if (arguments[0]) {
		return formatDate(this, arguments[0]); // our extended formatting
	}
	if (this._ambigTime) {
		return momentFormat(this, 'YYYY-MM-DD');
	}
	if (this._ambigZone) {
		return momentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
	}
	return momentFormat(this); // default moment original formatting
};

FCMoment.prototype.toISOString = function() {
	if (this._ambigTime) {
		return momentFormat(this, 'YYYY-MM-DD');
	}
	if (this._ambigZone) {
		return momentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
	}
	return moment.fn.toISOString.apply(this, arguments);
};

// Querying
// -------------------------------------------------------------------------------------------------

// Is the moment within the specified range? `end` is exclusive.
FCMoment.prototype.isWithin = function(start, end) {
	var a = commonlyAmbiguate([ this, start, end ]);
	return a[0] >= a[1] && a[0] < a[2];
};

// Make these query methods work with ambiguous moments
$.each([
	'isBefore',
	'isAfter',
	'isSame'
], function(i, methodName) {
	FCMoment.prototype[methodName] = function(input, units) {
		var a = commonlyAmbiguate([ this, input ]);
		return moment.fn[methodName].call(a[0], a[1], units);
	};
});

// Misc Internals
// -------------------------------------------------------------------------------------------------

// given an array of moment-like inputs, return a parallel array w/ moments similarly ambiguated.
// for example, of one moment has ambig time, but not others, all moments will have their time stripped.
function commonlyAmbiguate(inputs) {
	var outputs = [];
	var anyAmbigTime = false;
	var anyAmbigZone = false;
	var i;

	for (i=0; i<inputs.length; i++) {
		outputs.push(fc.moment(inputs[i]));
		anyAmbigTime = anyAmbigTime || outputs[i]._ambigTime;
		anyAmbigZone = anyAmbigZone || outputs[i]._ambigZone;
	}

	for (i=0; i<outputs.length; i++) {
		if (anyAmbigTime) {
			outputs[i].stripTime();
		}
		else if (anyAmbigZone) {
			outputs[i].stripZone();
		}
	}

	return outputs;
}
<commit_msg>slight fix for stripTime when using moment-timezone<commit_after>
var ambigDateOfMonthRegex = /^\s*\d{4}-\d\d$/;
var ambigTimeOrZoneRegex = /^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/;

// Creating
// -------------------------------------------------------------------------------------------------

// Creates a new moment, similar to the vanilla moment(...) constructor, but with
// extra features (ambiguous time, enhanced formatting). When gived an existing moment,
// it will function as a clone (and retain the zone of the moment). Anything else will
// result in a moment in the local zone.
fc.moment = function() {
	return makeMoment(arguments);
};

// Sames as fc.moment, but forces the resulting moment to be in the UTC timezone.
fc.moment.utc = function() {
	var mom = makeMoment(arguments, true);

	// Force it into UTC because makeMoment doesn't guarantee it.
	if (mom.hasTime()) { // don't give ambiguously-timed moments a UTC zone
		mom.utc();
	}

	return mom;
};

// Same as fc.moment, but when given an ISO8601 string, the timezone offset is preserved.
// ISO8601 strings with no timezone offset will become ambiguously zoned.
fc.moment.parseZone = function() {
	return makeMoment(arguments, true, true);
};

// Builds an FCMoment from args. When given an existing moment, it clones. When given a native
// Date, or called with no arguments (the current time), the resulting moment will be local.
// Anything else needs to be "parsed" (a string or an array), and will be affected by:
//    parseAsUTC - if there is no zone information, should we parse the input in UTC?
//    parseZone - if there is zone information, should we force the zone of the moment?
function makeMoment(args, parseAsUTC, parseZone) {
	var input = args[0];
	var isSingleString = args.length == 1 && typeof input === 'string';
	var isAmbigTime;
	var isAmbigZone;
	var ambigMatch;
	var output; // an object with fields for the new FCMoment object

	if (moment.isMoment(input)) {
		output = moment.apply(null, args); // clone it

		// the ambig properties have not been preserved in the clone, so reassign them
		if (input._ambigTime) {
			output._ambigTime = true;
		}
		if (input._ambigZone) {
			output._ambigZone = true;
		}
	}
	else if (isNativeDate(input) || input === undefined) {
		output = moment.apply(null, args); // will be local
	}
	else { // "parsing" is required
		isAmbigTime = false;
		isAmbigZone = false;

		if (isSingleString) {
			if (ambigDateOfMonthRegex.test(input)) {
				// accept strings like '2014-05', but convert to the first of the month
				input += '-01';
				args = [ input ]; // for when we pass it on to moment's constructor
				isAmbigTime = true;
				isAmbigZone = true;
			}
			else if ((ambigMatch = ambigTimeOrZoneRegex.exec(input))) {
				isAmbigTime = !ambigMatch[5]; // no time part?
				isAmbigZone = true;
			}
		}
		else if ($.isArray(input)) {
			// arrays have no timezone information, so assume ambiguous zone
			isAmbigZone = true;
		}
		// otherwise, probably a string with a format

		if (parseAsUTC) {
			output = moment.utc.apply(moment, args);
		}
		else {
			output = moment.apply(null, args);
		}

		if (isAmbigTime) {
			output._ambigTime = true;
			output._ambigZone = true; // ambiguous time always means ambiguous zone
		}
		else if (parseZone) { // let's record the inputted zone somehow
			if (isAmbigZone) {
				output._ambigZone = true;
			}
			else if (isSingleString) {
				output.zone(input); // if not a valid zone, will assign UTC
			}
		}
	}

	return new FCMoment(output);
}

// Our subclass of Moment.
// Accepts an object with the internal Moment properties that should be copied over to
// `this` object (most likely another Moment object). The values in this data must not
// be referenced by anything else (two moments sharing a Date object for example).
function FCMoment(internalData) {
	extend(this, internalData);
}

// Chain the prototype to Moment's
FCMoment.prototype = createObject(moment.fn);

// We need this because Moment's implementation won't create an FCMoment,
// nor will it copy over the ambig flags.
FCMoment.prototype.clone = function() {
	return makeMoment([ this ]);
};

// Time-of-day
// -------------------------------------------------------------------------------------------------

// GETTER
// Returns a Duration with the hours/minutes/seconds/ms values of the moment.
// If the moment has an ambiguous time, a duration of 00:00 will be returned.
//
// SETTER
// You can supply a Duration, a Moment, or a Duration-like argument.
// When setting the time, and the moment has an ambiguous time, it then becomes unambiguous.
FCMoment.prototype.time = function(time) {
	if (time == null) { // getter
		return moment.duration({
			hours: this.hours(),
			minutes: this.minutes(),
			seconds: this.seconds(),
			milliseconds: this.milliseconds()
		});
	}
	else { // setter

		delete this._ambigTime; // mark that the moment now has a time

		if (!moment.isDuration(time) && !moment.isMoment(time)) {
			time = moment.duration(time);
		}

		// The day value should cause overflow (so 24 hours becomes 00:00:00 of next day).
		// Only for Duration times, not Moment times.
		var dayHours = 0;
		if (moment.isDuration(time)) {
			dayHours = Math.floor(time.asDays()) * 24;
		}

		// We need to set the individual fields.
		// Can't use startOf('day') then add duration. In case of DST at start of day.
		return this.hours(dayHours + time.hours())
			.minutes(time.minutes())
			.seconds(time.seconds())
			.milliseconds(time.milliseconds());
	}
};

// Converts the moment to UTC, stripping out its time-of-day and timezone offset,
// but preserving its YMD. A moment with a stripped time will display no time
// nor timezone offset when .format() is called.
FCMoment.prototype.stripTime = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array

	// set the internal UTC flag
	moment.fn.utc.call(this); // call the original method, because we don't want to affect _ambigZone

	this.year(a[0]) // TODO: find a way to do this in one shot
		.month(a[1])
		.date(a[2])
		.hours(0)
		.minutes(0)
		.seconds(0)
		.milliseconds(0);

	// Mark the time as ambiguous. This needs to happen after the .utc() call, which calls .zone(), which
	// clears all ambig flags. Same concept with the .year/month/date calls in the case of moment-timezone.
	this._ambigTime = true;
	this._ambigZone = true; // if ambiguous time, also ambiguous timezone offset

	return this; // for chaining
};

// Returns if the moment has a non-ambiguous time (boolean)
FCMoment.prototype.hasTime = function() {
	return !this._ambigTime;
};

// Timezone
// -------------------------------------------------------------------------------------------------

// Converts the moment to UTC, stripping out its timezone offset, but preserving its
// YMD and time-of-day. A moment with a stripped timezone offset will display no
// timezone offset when .format() is called.
FCMoment.prototype.stripZone = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array
	var wasAmbigTime = this._ambigTime;

	moment.fn.utc.call(this); // set the internal UTC flag

	this.year(a[0]) // TODO: find a way to do this in one shot
		.month(a[1])
		.date(a[2])
		.hours(a[3])
		.minutes(a[4])
		.seconds(a[5])
		.milliseconds(a[6]);

	if (wasAmbigTime) {
		// the above call to .utc()/.zone() unfortunately clears the ambig flags, so reassign
		this._ambigTime = true;
	}

	// Mark the zone as ambiguous. This needs to happen after the .utc() call, which calls .zone(), which
	// clears all ambig flags. Same concept with the .year/month/date calls in the case of moment-timezone.
	this._ambigZone = true;

	return this; // for chaining
};

// Returns of the moment has a non-ambiguous timezone offset (boolean)
FCMoment.prototype.hasZone = function() {
	return !this._ambigZone;
};

// this method implicitly marks a zone
FCMoment.prototype.zone = function(tzo) {

	if (tzo != null) {
		// FYI, the delete statements need to be before the .zone() call or else chaos ensues
		// for reasons I don't understand.
		delete this._ambigTime;
		delete this._ambigZone;
	}

	return moment.fn.zone.apply(this, arguments);
};

// this method implicitly marks a zone
FCMoment.prototype.local = function() {
	var a = this.toArray(); // year,month,date,hours,minutes,seconds as an array
	var wasAmbigZone = this._ambigZone;

	// will happen anyway via .local()/.zone(), but don't want to rely on internal implementation
	delete this._ambigTime;
	delete this._ambigZone;

	moment.fn.local.apply(this, arguments);

	if (wasAmbigZone) {
		// If the moment was ambiguously zoned, the date fields were stored as UTC.
		// We want to preserve these, but in local time.
		this.year(a[0]) // TODO: find a way to do this in one shot
			.month(a[1])
			.date(a[2])
			.hours(a[3])
			.minutes(a[4])
			.seconds(a[5])
			.milliseconds(a[6]);
	}

	return this; // for chaining
};

// this method implicitly marks a zone
FCMoment.prototype.utc = function() {

	// will happen anyway via .local()/.zone(), but don't want to rely on internal implementation
	delete this._ambigTime;
	delete this._ambigZone;

	return moment.fn.utc.apply(this, arguments);
};

// Formatting
// -------------------------------------------------------------------------------------------------

FCMoment.prototype.format = function() {
	if (arguments[0]) {
		return formatDate(this, arguments[0]); // our extended formatting
	}
	if (this._ambigTime) {
		return momentFormat(this, 'YYYY-MM-DD');
	}
	if (this._ambigZone) {
		return momentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
	}
	return momentFormat(this); // default moment original formatting
};

FCMoment.prototype.toISOString = function() {
	if (this._ambigTime) {
		return momentFormat(this, 'YYYY-MM-DD');
	}
	if (this._ambigZone) {
		return momentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
	}
	return moment.fn.toISOString.apply(this, arguments);
};

// Querying
// -------------------------------------------------------------------------------------------------

// Is the moment within the specified range? `end` is exclusive.
FCMoment.prototype.isWithin = function(start, end) {
	var a = commonlyAmbiguate([ this, start, end ]);
	return a[0] >= a[1] && a[0] < a[2];
};

// Make these query methods work with ambiguous moments
$.each([
	'isBefore',
	'isAfter',
	'isSame'
], function(i, methodName) {
	FCMoment.prototype[methodName] = function(input, units) {
		var a = commonlyAmbiguate([ this, input ]);
		return moment.fn[methodName].call(a[0], a[1], units);
	};
});

// Misc Internals
// -------------------------------------------------------------------------------------------------

// given an array of moment-like inputs, return a parallel array w/ moments similarly ambiguated.
// for example, of one moment has ambig time, but not others, all moments will have their time stripped.
function commonlyAmbiguate(inputs) {
	var outputs = [];
	var anyAmbigTime = false;
	var anyAmbigZone = false;
	var i;

	for (i=0; i<inputs.length; i++) {
		outputs.push(fc.moment(inputs[i]));
		anyAmbigTime = anyAmbigTime || outputs[i]._ambigTime;
		anyAmbigZone = anyAmbigZone || outputs[i]._ambigZone;
	}

	for (i=0; i<outputs.length; i++) {
		if (anyAmbigTime) {
			outputs[i].stripTime();
		}
		else if (anyAmbigZone) {
			outputs[i].stripZone();
		}
	}

	return outputs;
}
<|endoftext|>


<commit_before>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventRegistrationsCtrl', function ($rootScope, $scope, $modal, modalMessage, $http, RegistrationCache, conference, permissions, permissionConstants) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'registrations',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };

    function hasPermission(){
      if(permissions.permissionInt < permissionConstants.UPDATE){
        modalMessage.error('You do not have permission to perform this action. Please contact an event administrator to request permission.');
        return false;
      }else{
        return true;
      }
    }

    $scope.conference = conference;
    $scope.blocks = [];
    $scope.queryParameters = {
      block: [],
      page: 1,
      limit: 20,
      orderBy: 'last_name',
      order: 'ASC',
      filter: '',
      filterPayment: '',
      filterRegType: '',
      includeCheckedin: 'yes',
      includeWithdrawn: 'yes',
      includeIncomplete: 'no'
    };
    $scope.meta = {
      totalPages: 0
    };
    $scope.reversesort = false;
    $scope.visibleFilterRegistrantTypes = _.sortBy(angular.copy(conference.registrantTypes).concat({
      id: '',
      name: '-Any-'
    }), 'name');
    var expandedRegistrations = {};

    $scope.$watch('queryParameters', function(q, oldQ){
      //reset page
      if(q.page > 1 && q.page === oldQ.page){
        $scope.queryParameters.page = 1;
        return;
      }

      $scope.refreshRegistrations();
    }, true);

    //collect all blocks from the conferences' pages
    angular.forEach(conference.registrationPages, function (page) {
      angular.forEach(page.blocks, function (block) {
        if (block.type !== 'paragraphContent') {
          $scope.blocks.push(angular.copy(block));
        }
      });
    });
    //turn on visible blocks
    var visibleBlocks = localStorage.getItem('visibleBlocks:' + conference.id);
    if(!_.isNull(visibleBlocks)){
      visibleBlocks = JSON.parse(visibleBlocks);
      $scope.queryParameters.block = visibleBlocks;
      angular.forEach(visibleBlocks, function(blockId){
        var block = _.find($scope.blocks, { 'id': blockId });
        if(angular.isDefined(block)){
          block.visible = true;
        }
      });
    }

    // toggle (show/hide) column(s)
    $scope.toggleColumn = function (block) {
      $scope.blocks[block].visible = !$scope.blocks[block].visible;
      visibleBlocks =  _.pluck(_.where($scope.blocks, { 'visible': true }), 'id');
      localStorage.setItem('visibleBlocks:' + conference.id, JSON.stringify(visibleBlocks));
      $scope.queryParameters.block = visibleBlocks;
    };

    var throttleFilter = _.debounce(function(){
      $scope.$apply(function(){
        $scope.queryParameters.filter = $scope.strFilter;
      });
    }, 500);
    $scope.$watch('strFilter', function(strFilter){
      if(angular.isDefined(strFilter)){
        throttleFilter();
      }
    });

    $scope.refreshRegistrations = function(){
      RegistrationCache.getAllForConference(conference.id, $scope.queryParameters).then(function(data){
        $scope.meta = data.meta;
        $scope.registrations = data.registrations;
        $scope.registrants = _.flatten(data.registrations, 'registrants');
        expandedRegistrations = {};
      }, function(){
        $scope.registrations = [];
        $scope.registrants = [];
      });
    };

    $scope.blockIsVisible = function(block, registrantTypeId){
      return !_.contains(block.registrantTypes, registrantTypeId);
    };

    var findAnswer = function (registration, blockId) {
      return _.find(registration.answers, function (answer) {
        return angular.equals(answer.blockId, blockId);
      });
    };

    $scope.answerSort = function (registrant) {
      var orderBy = $scope.queryParameters.orderBy;
      if (angular.isUndefined(orderBy)) {
        return 0;
      }

      if(orderBy === 'completed_timestamp'){
        return $scope.getRegistration(registrant.registrationId).completedTimestamp;
      }else if(orderBy === 'created_timestamp'){
        return registrant.createdTimestamp;
      }else if(orderBy === 'registrant_type_id'){
        return registrant.registrantTypeId;
        //return $scope.getRegistrantType(registration.registrantTypeId).name;
      }else if(orderBy === 'first_name'){
        return registrant.firstName;
      }else if(orderBy === 'last_name'){
        return registrant.lastName;
      }else if(orderBy === 'email') {
        return registrant.email;
      }else if(orderBy === 'checked_in_timestamp') {
        return registrant.checkedInTimestamp;
      }else{
        if(angular.isUndefined(findAnswer(registrant, orderBy))) {
          return '';
        }

        var answerValue = findAnswer(registrant, orderBy).value;
        if(_.isObject(answerValue)){
          var blockType = _.find($scope.blocks, { 'id': orderBy }).type;
          if(blockType === 'checkboxQuestion'){
            return _.keys(_.pick(answerValue, function(val){ return val; })).join();
          }else{
            return _.values(answerValue).join();
          }
        }else{
          return answerValue;
        }
      }
    };

    $scope.setOrder = function (order) {
      if (order === $scope.queryParameters.orderBy) {
        $scope.reversesort = !$scope.reversesort;
      } else {
        $scope.reversesort = false;
      }
      $scope.queryParameters.orderBy = order;
      $scope.queryParameters.order = ($scope.reversesort ? 'DESC' : 'ASC');
    };

    $scope.viewPayments = function (registrationId) {
      $http.get('registrations/' + registrationId).success(function (registration) {
        var paymentModalOptions = {
          templateUrl: 'views/modals/paymentsModal.html',
          controller: 'paymentModal',
          size: 'lg',
          backdrop: 'static',
          resolve: {
            registration: function () {
              return registration;
            },
            conference: function () {
              return conference;
            },
            permissions: function () {
              return permissions;
            }
          }
        };

        $modal.open(paymentModalOptions).result.then(function (updatedRegistration) {
          var localUpdatedRegistrationIndex = _.findIndex($scope.registrations, { 'id': updatedRegistration.id });
          $scope.registrations[localUpdatedRegistrationIndex] = updatedRegistration;
        });
      }).error(function(){
        modalMessage.error('Error: registration data could be be retrieved.');
      });
    };

    $scope.paidInFull = function (registrantId) {
      var registration = _.find($scope.registrations, { 'id': registrantId });
      return registration.totalPaid >= registration.calculatedTotalDue;
    };

    $scope.expandRegistration = function (r) {
      if (expandedRegistrations[r] === 'open') {
        delete expandedRegistrations[r];
      } else {
        expandedRegistrations[r] = 'loading';

        $http.get('registrants/' + r).success(function (registrantData) {
          expandedRegistrations[r] = 'open';

          //update registrant
          var index = _.findIndex($scope.registrants, { 'id': registrantData.id });
          $scope.registrants[index] = registrantData;

          //update registration
          index = _.findIndex($scope.registrations, { 'id': registrantData.registrationId });
          var registrantIndex = _.findIndex($scope.registrations[index].registrants, { 'id': registrantData.id });
          $scope.registrations[index].registrants[registrantIndex] = registrantData;
        }).error(function(){
          modalMessage.error('Error: registrant data could be be retrieved.');
          delete expandedRegistrations[r];
        });
      }
    };

    $scope.expandedStatus = function (r) {
      return expandedRegistrations[r];
    };

    $scope.editRegistrant = function (r) {
      if(!hasPermission()){
        return;
      }

      $http.get('registrations/' + r.registrationId).success(function (registration) {
        var editRegistrationDialogOptions = {
          templateUrl: 'views/modals/editRegistration.html',
          controller: 'editRegistrationModalCtrl',
          resolve: {
            registrantId: function () {
              return r.id;
            },
            registration: function () {
              return registration;
            },
            conference: function () {
              return conference;
            }
          }
        };

        $modal.open(editRegistrationDialogOptions).result.then(function (registration) {
          //update registration
          var index = _.findIndex($scope.registrations, { 'id': registration.id });
          $scope.registrations[index] = registration;

          //update registrant
          r = _.find(registration.registrants, { 'id': r.id });
          index = _.findIndex($scope.registrants, { 'id': r.id });
          $scope.registrants[index] = r;
        });
      }).error(function(){
        modalMessage.error('Error: registrant data could be be retrieved.');
        delete expandedRegistrations[r];
      });
    };

    // Export conference registrations information to csv
    $scope.export = function () {
      $modal.open({
        templateUrl: 'views/modals/export.html',
        controller: 'exportDataModal',
        resolve: {
          conference: function() {
            return $scope.conference;
          },
          hasCost: function() {
            return $scope.eventHasCost();
          }
        }
      });
    };

    $scope.eventHasCost = function () {
      return _.max(_.flatten(conference.registrantTypes, 'cost')) > 0;
    };

    $scope.registerUser = function () {
      if(!hasPermission()){
        return;
      }

      $modal.open({
        templateUrl: 'views/modals/manualRegistration.html',
        controller: 'registrationModal',
        resolve: {
          conference: function () {
            return conference;
          }
        }
      });
    };

    $scope.getRegistration = function(id){
      return _.find($scope.registrations, { 'id': id });
    };

    $scope.getRegistrantType = function(id){
      return _.find(conference.registrantTypes, { 'id': id });
    };

    $scope.withdrawRegistrant = function(registrant, value){
      if(!hasPermission()){
        return;
      }

      registrant.withdrawn = value;
      if(value){
        //used to update front view only, backend generates its own timestamp
        registrant.withdrawnTimestamp = new Date();
      }

      //update registration
      var registrationIndex = _.findIndex($scope.registrations, { 'id': registrant.registrationId });
      var registrantIndex = _.findIndex($scope.registrations[registrationIndex].registrants, { 'id': registrant.id });
      $scope.registrations[registrationIndex].registrants[registrantIndex] = registrant;

      $rootScope.loadingMsg = (value ? 'Withdrawing ' : 'Reinstating ') + registrant.firstName;
      $http.put('registrations/' + registrant.registrationId, $scope.registrations[registrationIndex]).success(function(){
        $rootScope.loadingMsg = '';
      }).error(function(){
        $rootScope.loadingMsg = '';
        registrant.withdrawn = !value;
        modalMessage.error('An error occurred while withdrawing this registrant.');
      });
    };

    $scope.checkInRegistrant = function(registrant, value){
      if(!hasPermission()){
        return;
      }

      var originalValue = angular.copy(registrant.checkedInTimestamp);
      registrant.checkedInTimestamp = (value ? new Date().toJSON() : null);

      //update registration
      var registrationIndex = _.findIndex($scope.registrations, { 'id': registrant.registrationId });
      var registrantIndex = _.findIndex($scope.registrations[registrationIndex].registrants, { 'id': registrant.id });
      $scope.registrations[registrationIndex].registrants[registrantIndex] = registrant;

      $rootScope.loadingMsg = (value ? 'Checking in ' : 'Removing check-in for ') + registrant.firstName;
      $http.put('registrations/' + registrant.registrationId, $scope.registrations[registrationIndex]).success(function(){
        $rootScope.loadingMsg = '';
      }).error(function(){
        $rootScope.loadingMsg = '';
        registrant.checkedInTimestamp = originalValue;
        modalMessage.error('An error occurred while checking in this registrant.');
      });
    };

    $scope.deleteRegistrant = function (registrant) {
      if(!hasPermission()){
        return;
      }

      modalMessage.confirm('Delete Registration', 'Are you sure you want to delete this registration?<br>There is no recovering the data once deleted.', 'Delete', 'Cancel', true).then(function(){
        var registration = _.find($scope.registrations, { 'id': registrant.registrationId });
        var url = 'registrations/' + registration.id;

        if(registration.registrants.length > 1){
          //Delete Registrant
          url = 'registrants/' + registrant.id;
        }

        $http({
          method: 'DELETE',
          url: url
        }).success(function () {
          _.remove($scope.registrants, function (r) {
            return r.id === registrant.id;
          });

          _.remove(registration.registrants, function (r) {
            return r.id === registrant.id;
          });
        });
      });
    };
  });
<commit_msg>Remove redundant function calls<commit_after>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventRegistrationsCtrl', function ($rootScope, $scope, $modal, modalMessage, $http, RegistrationCache, conference, permissions, permissionConstants) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'registrations',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };

    function hasPermission(){
      if(permissions.permissionInt < permissionConstants.UPDATE){
        modalMessage.error('You do not have permission to perform this action. Please contact an event administrator to request permission.');
        return false;
      }else{
        return true;
      }
    }

    $scope.conference = conference;
    $scope.blocks = [];
    $scope.queryParameters = {
      block: [],
      page: 1,
      limit: 20,
      orderBy: 'last_name',
      order: 'ASC',
      filter: '',
      filterPayment: '',
      filterRegType: '',
      includeCheckedin: 'yes',
      includeWithdrawn: 'yes',
      includeIncomplete: 'no'
    };
    $scope.meta = {
      totalPages: 0
    };
    $scope.reversesort = false;
    $scope.visibleFilterRegistrantTypes = _.sortBy(angular.copy(conference.registrantTypes).concat({
      id: '',
      name: '-Any-'
    }), 'name');
    var expandedRegistrations = {};

    $scope.$watch('queryParameters', function(q, oldQ){
      //reset page
      if(q.page > 1 && q.page === oldQ.page){
        $scope.queryParameters.page = 1;
        return;
      }

      $scope.refreshRegistrations();
    }, true);

    //collect all blocks from the conferences' pages
    angular.forEach(conference.registrationPages, function (page) {
      angular.forEach(page.blocks, function (block) {
        if (block.type !== 'paragraphContent') {
          $scope.blocks.push(angular.copy(block));
        }
      });
    });
    //turn on visible blocks
    var visibleBlocks = localStorage.getItem('visibleBlocks:' + conference.id);
    if(!_.isNull(visibleBlocks)){
      visibleBlocks = JSON.parse(visibleBlocks);
      $scope.queryParameters.block = visibleBlocks;
      angular.forEach(visibleBlocks, function(blockId){
        var block = _.find($scope.blocks, { 'id': blockId });
        if(angular.isDefined(block)){
          block.visible = true;
        }
      });
    }

    // toggle (show/hide) column(s)
    $scope.toggleColumn = function (block) {
      $scope.blocks[block].visible = !$scope.blocks[block].visible;
      visibleBlocks =  _.pluck(_.where($scope.blocks, { 'visible': true }), 'id');
      localStorage.setItem('visibleBlocks:' + conference.id, JSON.stringify(visibleBlocks));
      $scope.queryParameters.block = visibleBlocks;
    };

    var throttleFilter = _.debounce(function(){
      $scope.$apply(function(){
        $scope.queryParameters.filter = $scope.strFilter;
      });
    }, 500);
    $scope.$watch('strFilter', function(strFilter){
      if(angular.isDefined(strFilter)){
        throttleFilter();
      }
    });

    $scope.refreshRegistrations = function(){
      RegistrationCache.getAllForConference(conference.id, $scope.queryParameters).then(function(data){
        $scope.meta = data.meta;
        $scope.registrations = data.registrations;
        $scope.registrants = _.flatten(data.registrations, 'registrants');
        expandedRegistrations = {};
      }, function(){
        $scope.registrations = [];
        $scope.registrants = [];
      });
    };

    $scope.blockIsVisible = function(block, registrantTypeId){
      return !_.contains(block.registrantTypes, registrantTypeId);
    };

    var findAnswer = function (registration, blockId) {
      return _.find(registration.answers, function (answer) {
        return angular.equals(answer.blockId, blockId);
      });
    };

    $scope.answerSort = function (registrant) {
      var orderBy = $scope.queryParameters.orderBy;
      if (angular.isUndefined(orderBy)) {
        return 0;
      }

      if(orderBy === 'completed_timestamp'){
        return $scope.getRegistration(registrant.registrationId).completedTimestamp;
      }else if(orderBy === 'created_timestamp'){
        return registrant.createdTimestamp;
      }else if(orderBy === 'registrant_type_id'){
        return registrant.registrantTypeId;
        //return $scope.getRegistrantType(registration.registrantTypeId).name;
      }else if(orderBy === 'first_name'){
        return registrant.firstName;
      }else if(orderBy === 'last_name'){
        return registrant.lastName;
      }else if(orderBy === 'email') {
        return registrant.email;
      }else if(orderBy === 'checked_in_timestamp') {
        return registrant.checkedInTimestamp;
      }else{
        var answerValue = findAnswer(registrant, orderBy);
        if(angular.isUndefined(answerValue)){
          return '';
        }

        answerValue = answerValue.value;
        if(_.isObject(answerValue)){
          var blockType = _.find($scope.blocks, { 'id': orderBy }).type;
          if(blockType === 'checkboxQuestion'){
            return _.keys(_.pick(answerValue, function(val){ return val; })).join();
          }else{
            return _.values(answerValue).join();
          }
        }else{
          return answerValue;
        }
      }
    };

    $scope.setOrder = function (order) {
      if (order === $scope.queryParameters.orderBy) {
        $scope.reversesort = !$scope.reversesort;
      } else {
        $scope.reversesort = false;
      }
      $scope.queryParameters.orderBy = order;
      $scope.queryParameters.order = ($scope.reversesort ? 'DESC' : 'ASC');
    };

    $scope.viewPayments = function (registrationId) {
      $http.get('registrations/' + registrationId).success(function (registration) {
        var paymentModalOptions = {
          templateUrl: 'views/modals/paymentsModal.html',
          controller: 'paymentModal',
          size: 'lg',
          backdrop: 'static',
          resolve: {
            registration: function () {
              return registration;
            },
            conference: function () {
              return conference;
            },
            permissions: function () {
              return permissions;
            }
          }
        };

        $modal.open(paymentModalOptions).result.then(function (updatedRegistration) {
          var localUpdatedRegistrationIndex = _.findIndex($scope.registrations, { 'id': updatedRegistration.id });
          $scope.registrations[localUpdatedRegistrationIndex] = updatedRegistration;
        });
      }).error(function(){
        modalMessage.error('Error: registration data could be be retrieved.');
      });
    };

    $scope.paidInFull = function (registrantId) {
      var registration = _.find($scope.registrations, { 'id': registrantId });
      return registration.totalPaid >= registration.calculatedTotalDue;
    };

    $scope.expandRegistration = function (r) {
      if (expandedRegistrations[r] === 'open') {
        delete expandedRegistrations[r];
      } else {
        expandedRegistrations[r] = 'loading';

        $http.get('registrants/' + r).success(function (registrantData) {
          expandedRegistrations[r] = 'open';

          //update registrant
          var index = _.findIndex($scope.registrants, { 'id': registrantData.id });
          $scope.registrants[index] = registrantData;

          //update registration
          index = _.findIndex($scope.registrations, { 'id': registrantData.registrationId });
          var registrantIndex = _.findIndex($scope.registrations[index].registrants, { 'id': registrantData.id });
          $scope.registrations[index].registrants[registrantIndex] = registrantData;
        }).error(function(){
          modalMessage.error('Error: registrant data could be be retrieved.');
          delete expandedRegistrations[r];
        });
      }
    };

    $scope.expandedStatus = function (r) {
      return expandedRegistrations[r];
    };

    $scope.editRegistrant = function (r) {
      if(!hasPermission()){
        return;
      }

      $http.get('registrations/' + r.registrationId).success(function (registration) {
        var editRegistrationDialogOptions = {
          templateUrl: 'views/modals/editRegistration.html',
          controller: 'editRegistrationModalCtrl',
          resolve: {
            registrantId: function () {
              return r.id;
            },
            registration: function () {
              return registration;
            },
            conference: function () {
              return conference;
            }
          }
        };

        $modal.open(editRegistrationDialogOptions).result.then(function (registration) {
          //update registration
          var index = _.findIndex($scope.registrations, { 'id': registration.id });
          $scope.registrations[index] = registration;

          //update registrant
          r = _.find(registration.registrants, { 'id': r.id });
          index = _.findIndex($scope.registrants, { 'id': r.id });
          $scope.registrants[index] = r;
        });
      }).error(function(){
        modalMessage.error('Error: registrant data could be be retrieved.');
        delete expandedRegistrations[r];
      });
    };

    // Export conference registrations information to csv
    $scope.export = function () {
      $modal.open({
        templateUrl: 'views/modals/export.html',
        controller: 'exportDataModal',
        resolve: {
          conference: function() {
            return $scope.conference;
          },
          hasCost: function() {
            return $scope.eventHasCost();
          }
        }
      });
    };

    $scope.eventHasCost = function () {
      return _.max(_.flatten(conference.registrantTypes, 'cost')) > 0;
    };

    $scope.registerUser = function () {
      if(!hasPermission()){
        return;
      }

      $modal.open({
        templateUrl: 'views/modals/manualRegistration.html',
        controller: 'registrationModal',
        resolve: {
          conference: function () {
            return conference;
          }
        }
      });
    };

    $scope.getRegistration = function(id){
      return _.find($scope.registrations, { 'id': id });
    };

    $scope.getRegistrantType = function(id){
      return _.find(conference.registrantTypes, { 'id': id });
    };

    $scope.withdrawRegistrant = function(registrant, value){
      if(!hasPermission()){
        return;
      }

      registrant.withdrawn = value;
      if(value){
        //used to update front view only, backend generates its own timestamp
        registrant.withdrawnTimestamp = new Date();
      }

      //update registration
      var registrationIndex = _.findIndex($scope.registrations, { 'id': registrant.registrationId });
      var registrantIndex = _.findIndex($scope.registrations[registrationIndex].registrants, { 'id': registrant.id });
      $scope.registrations[registrationIndex].registrants[registrantIndex] = registrant;

      $rootScope.loadingMsg = (value ? 'Withdrawing ' : 'Reinstating ') + registrant.firstName;
      $http.put('registrations/' + registrant.registrationId, $scope.registrations[registrationIndex]).success(function(){
        $rootScope.loadingMsg = '';
      }).error(function(){
        $rootScope.loadingMsg = '';
        registrant.withdrawn = !value;
        modalMessage.error('An error occurred while withdrawing this registrant.');
      });
    };

    $scope.checkInRegistrant = function(registrant, value){
      if(!hasPermission()){
        return;
      }

      var originalValue = angular.copy(registrant.checkedInTimestamp);
      registrant.checkedInTimestamp = (value ? new Date().toJSON() : null);

      //update registration
      var registrationIndex = _.findIndex($scope.registrations, { 'id': registrant.registrationId });
      var registrantIndex = _.findIndex($scope.registrations[registrationIndex].registrants, { 'id': registrant.id });
      $scope.registrations[registrationIndex].registrants[registrantIndex] = registrant;

      $rootScope.loadingMsg = (value ? 'Checking in ' : 'Removing check-in for ') + registrant.firstName;
      $http.put('registrations/' + registrant.registrationId, $scope.registrations[registrationIndex]).success(function(){
        $rootScope.loadingMsg = '';
      }).error(function(){
        $rootScope.loadingMsg = '';
        registrant.checkedInTimestamp = originalValue;
        modalMessage.error('An error occurred while checking in this registrant.');
      });
    };

    $scope.deleteRegistrant = function (registrant) {
      if(!hasPermission()){
        return;
      }

      modalMessage.confirm('Delete Registration', 'Are you sure you want to delete this registration?<br>There is no recovering the data once deleted.', 'Delete', 'Cancel', true).then(function(){
        var registration = _.find($scope.registrations, { 'id': registrant.registrationId });
        var url = 'registrations/' + registration.id;

        if(registration.registrants.length > 1){
          //Delete Registrant
          url = 'registrants/' + registrant.id;
        }

        $http({
          method: 'DELETE',
          url: url
        }).success(function () {
          _.remove($scope.registrants, function (r) {
            return r.id === registrant.id;
          });

          _.remove(registration.registrants, function (r) {
            return r.id === registrant.id;
          });
        });
      });
    };
  });
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const Plugin = require('broccoli-plugin');

function baseModule(options) {
  return `
    export const PROJECT_VERSION = '${options.projectVersion}';
    export const PROJECT_REVISION = '${options.projectRevision}';
    export const VERSION = '${options.buildTime}';
  `;
}

const EVERY_BUILD_STRATEGY = `self.CACHE_BUSTER = VERSION;`;
const PROJECT_REVISION_STRATEGY = `self.CACHE_BUSTER = PROJECT_REVISION;`;
const PROJECT_VERSION_STRATEGY = `self.CACHE_BUSTER = PROJECT_VERSION;`;

module.exports = class Config extends Plugin {
  constructor(inputNodes, options) {
    super(inputNodes, {
      name: options && options.name,
      annotation: options && options.annotation
    });

    this.options = options;
  }

  build() {
    let options = this.options;
    options.buildTime = (new Date).getTime() + '|' + Math.random();

    let module = baseModule(options);
    let versionStrategy = options.versionStrategy;

    if (!('versionStrategy' in options) || options.versionStrategy === 'every-build') {
      module += EVERY_BUILD_STRATEGY;
    }

    if (options.versionStrategy === 'project-revision') {
      module += PROJECT_REVISION_STRATEGY;
    }

    if (options.versionStrategy === 'project-version') {
      module += PROJECT_VERSION_STRATEGY;
    }

    let implicitImmediateClaim = !('immediateClaim' in options);
    let explicitImmediateClaim = !implicitImmediateClaim && options.immediateClaim === true;
    let skipWaiting = ('skipWaitingOnMessage' in options && options.skipWaitingOnMessage === true);

    if (implicitImmediateClaim || explicitImmediateClaim) {
      module += `
        self.addEventListener('install', function installEventListenerCallback(event) {
          return self.skipWaiting();
        });
      `;
    }
    if (!explicitImmediateClaim && skipWaiting) {
      module += `
        self.addEventListener('message', function skipWaitingMessageCallback(event) {
          if (event.data === 'skipWaiting') {
            return self.skipWaiting();
          }
        });
      `;
    }
    if (implicitImmediateClaim || explicitImmediateClaim || skipWaiting) {
      module += `
        self.addEventListener('activate', function installEventListenerCallback(event) {
          return self.clients.claim();
        });
      `;
    }

    fs.writeFileSync(path.join(this.outputPath, 'index.js'), module);
  }
};
<commit_msg>Consolidate listeners for readability<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const Plugin = require('broccoli-plugin');

function baseModule(options) {
  return `
    export const PROJECT_VERSION = '${options.projectVersion}';
    export const PROJECT_REVISION = '${options.projectRevision}';
    export const VERSION = '${options.buildTime}';
  `;
}

const EVERY_BUILD_STRATEGY = `self.CACHE_BUSTER = VERSION;`;
const PROJECT_REVISION_STRATEGY = `self.CACHE_BUSTER = PROJECT_REVISION;`;
const PROJECT_VERSION_STRATEGY = `self.CACHE_BUSTER = PROJECT_VERSION;`;
const INSTALL_EVENT_LISTENER = `
  self.addEventListener('install', function installEventListenerCallback(event) {
    return self.skipWaiting();
  });
`;
const IMMEDIATE_CLAIM_LISTENER = `
  self.addEventListener('message', function skipWaitingMessageCallback(event) {
    if (event.data === 'skipWaiting') {
      return self.skipWaiting();
    }
  });
`;
const SKIP_WAITING_LISTENER = `
  self.addEventListener('activate', function installEventListenerCallback(event) {
    return self.clients.claim();
  });
`;

module.exports = class Config extends Plugin {
  constructor(inputNodes, options) {
    super(inputNodes, {
      name: options && options.name,
      annotation: options && options.annotation
    });

    this.options = options;
  }

  build() {
    let options = this.options;
    options.buildTime = (new Date).getTime() + '|' + Math.random();

    let module = baseModule(options);
    let versionStrategy = options.versionStrategy;

    if (!('versionStrategy' in options) || options.versionStrategy === 'every-build') {
      module += EVERY_BUILD_STRATEGY;
    }

    if (options.versionStrategy === 'project-revision') {
      module += PROJECT_REVISION_STRATEGY;
    }

    if (options.versionStrategy === 'project-version') {
      module += PROJECT_VERSION_STRATEGY;
    }

    const implicitImmediateClaim = !('immediateClaim' in options);
    const explicitImmediateClaim = !implicitImmediateClaim && options.immediateClaim === true;
    const skipWaiting = ('skipWaitingOnMessage' in options && options.skipWaitingOnMessage === true);

    if (implicitImmediateClaim || explicitImmediateClaim) {
      module += INSTALL_EVENT_LISTENER;
    }
    if (!explicitImmediateClaim && skipWaiting) {
      module += IMMEDIATE_CLAIM_LISTENER;
    }
    if (implicitImmediateClaim || explicitImmediateClaim || skipWaiting) {
      module += SKIP_WAITING_LISTENER;
    }

    fs.writeFileSync(path.join(this.outputPath, 'index.js'), module);
  }
};
<|endoftext|>


<commit_before>"use strict";

define([	'src/citationEngine',
			'src/options',
			'src/dataInstance',
			'src/urlUtils',
			'external/codemirror',
			'external/codemirrorXmlMode',
			'jquery.layout'
		],
		function (
			CSLEDIT_citationEngine,
			CSLEDIT_options,
			CSLEDIT_data,
			CSLEDIT_urlUtils,
			CodeMirror,
			CodeMirrorXmlMode,
			jquery_layout
		) {
	var CSLEDIT_codeEditor = function (containerElement, userOptions) {
		var codeTimeout,
			editor,
			diffTimeout,
			diffMatchPatch = new diff_match_patch(),
			oldFormattedCitation = "",
			newFormattedCitation = "",
			oldFormattedBibliography = "",
			newFormattedBibliography = "",
			styleURL;

		containerElement = $(containerElement);

		CSLEDIT_options.setUserOptions(userOptions);

		$.ajax({
			url: CSLEDIT_urlUtils.getResourceUrl("html/codeEditor.html"),
			success : function (data) {
				containerElement.html(data);
				init();
			},
			error : function (jaXHR, textStatus, errorThrown) {
				alert("Couldn't fetch page: " + textStatus);
			},
			cache : false
		});

		var init = function () {
			var codeMirrorScroll,
				codeMirrorContainer;

			CodeMirror.defaults.onChange = function()
			{
				clearTimeout(codeTimeout);
				codeTimeout = setTimeout( function () {
					var result = CSLEDIT_data.setCslCode(editor.getValue());

					if ("error" in result) {
						$("#statusMessage").html(result.error);
						$("#formattedCitations").html("");
						$("#formattedBibliography").html("");
					} else {
						CSLEDIT_citationEngine.runCiteprocAndDisplayOutput(
							$("#statusMessage"), $("#exampleOutput"),
							$("#formattedCitations"), $("#formattedBibliography"));
					}
				}, 500);
			};

			editor = CodeMirror.fromTextArea($("#code")[0], {
					mode: { name: "xml" },
					lineNumbers: true
			});

			CSLEDIT_data.initPageStyle( function () {
				editor.setValue(CSLEDIT_data.getCslCode());
			});

			codeMirrorScroll = $('.CodeMirror-scroll');
			codeMirrorContainer = $('#codeMirrorContainer');

			var resizeCodeEditor = function () {

				codeMirrorScroll.css({
					height: codeMirrorContainer.height() + "px"
				});
			};

			containerElement.layout({
				north__size : 300,
				livePaneResizing : true,
				onresize : resizeCodeEditor
			});

			resizeCodeEditor();
		}
	};

	return CSLEDIT_codeEditor;
});
<commit_msg>we're using explicit data type for all ajax requests<commit_after>"use strict";

define([	'src/citationEngine',
			'src/options',
			'src/dataInstance',
			'src/urlUtils',
			'external/codemirror',
			'external/codemirrorXmlMode',
			'jquery.layout'
		],
		function (
			CSLEDIT_citationEngine,
			CSLEDIT_options,
			CSLEDIT_data,
			CSLEDIT_urlUtils,
			CodeMirror,
			CodeMirrorXmlMode,
			jquery_layout
		) {
	var CSLEDIT_codeEditor = function (containerElement, userOptions) {
		var codeTimeout,
			editor,
			diffTimeout,
			diffMatchPatch = new diff_match_patch(),
			oldFormattedCitation = "",
			newFormattedCitation = "",
			oldFormattedBibliography = "",
			newFormattedBibliography = "",
			styleURL;

		containerElement = $(containerElement);

		CSLEDIT_options.setUserOptions(userOptions);

		$.ajax({
			url: CSLEDIT_urlUtils.getResourceUrl("html/codeEditor.html"),
			success : function (data) {
				containerElement.html(data);
				init();
			},
			error : function (jaXHR, textStatus, errorThrown) {
				alert("Couldn't fetch page: " + textStatus);
			},
			cache : false,
			dataType : "text"
		});

		var init = function () {
			var codeMirrorScroll,
				codeMirrorContainer;

			CodeMirror.defaults.onChange = function()
			{
				clearTimeout(codeTimeout);
				codeTimeout = setTimeout( function () {
					var result = CSLEDIT_data.setCslCode(editor.getValue());

					if ("error" in result) {
						$("#statusMessage").html(result.error);
						$("#formattedCitations").html("");
						$("#formattedBibliography").html("");
					} else {
						CSLEDIT_citationEngine.runCiteprocAndDisplayOutput(
							$("#statusMessage"), $("#exampleOutput"),
							$("#formattedCitations"), $("#formattedBibliography"));
					}
				}, 500);
			};

			editor = CodeMirror.fromTextArea($("#code")[0], {
					mode: { name: "xml" },
					lineNumbers: true
			});

			CSLEDIT_data.initPageStyle( function () {
				editor.setValue(CSLEDIT_data.getCslCode());
			});

			codeMirrorScroll = $('.CodeMirror-scroll');
			codeMirrorContainer = $('#codeMirrorContainer');

			var resizeCodeEditor = function () {

				codeMirrorScroll.css({
					height: codeMirrorContainer.height() + "px"
				});
			};

			containerElement.layout({
				north__size : 300,
				livePaneResizing : true,
				onresize : resizeCodeEditor
			});

			resizeCodeEditor();
		}
	};

	return CSLEDIT_codeEditor;
});
<|endoftext|>


<commit_before>/*eslint-env browser*/
/*eslint max-len: 0*/
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import TitleBar from "../components/framework/title-bar";
import Title from "../components/framework/title";
import { headerFont, materialButtonOutline } from "../globalStyles";
import Flex from "../components/framework/flex";
import { analyticsNewPage } from "../util/googleAnalytics";
// import Card from "./framework/card";

const styles = {
  cardMainText: {
    fontFamily: headerFont,
    fontWeight: 500,
    fontSize: 28,
    position: "absolute",
    paddingTop: 10,
    paddingBottom: 10,
    paddingLeft: 20,
    paddingRight: 20,
    top: "40px",
    left: "20px",
    color: "white",
    background: "rgba(0, 0, 0, 0.7)"
  },
  cardSubText: {
    color: "white",
    fontStyle: "italic",
    fontSize: 16,
    fontWeight: 400,
    lineHeight: 0.3,
    textAlign: "right"
  },
  cardOuterDiv: {
    backgroundColor: "#FFFFFF",
    // marginLeft: 10,
    // marginRight: 10,
    // marginTop: 5,
    // marginBottom: 5,
    padding: 0,
    overflow: "hidden",
    position: "relative"
    // boxSizing: "content-box"
  },
  cardInnerDiv: {
    boxShadow: "3px 3px 4px 1px rgba(215,215,215,0.85)",
    borderRadius: 2,
    marginLeft: 10,
    marginRight: 10,
    marginTop: 5,
    marginBottom: 5
    // display: "flex",
    // justifyContent: "center",
    // alignItems: "center",
    // overflow: "hidden"
  },
  cardImg: {
    objectFit: "cover",
    width: "100%"
  }
};

const generateCard = (title, imgRequired, to) => (

      <Link to={to}>

          {title[0]}
          {title.length === 2 ?
{title[1]}
 : null}

      </Link>

);

const Splash = () => {
  analyticsNewPage();
  return(
    <g>
      <TitleBar logoHidden={true} titleHidden={true}/>

            <Title/>

            Real-time tracking of virus evolution

            This website aims to provide a real-time snapshot of evolving virus populations to aid epidemiological understanding and improve outbreak response

            <Link to="/about">
              <button style={materialButtonOutline}>
                Learn More
              </button>
            </Link>

        {/* THE CLICKABLE CARDS
          images styalized in lunapic witht he grey filter
          https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/197-Zika_Virus-ZikaVirus.tif/lossy-page1-800px-197-Zika_Virus-ZikaVirus.tif.jpg
          http://www.cidresearch.org/uploads/12/10/ebola_virus_particles_budding_VERO_E6_cell_blue_yellow_NIAID.jpg
          http://cdn1.bostonmagazine.com/wp-content/uploads/2013/10/flu-virus-main.jpg
        */}

                {generateCard(["Ebola"], require("../images/ebola.png"), "/ebola?c=division&r=division")}

                {generateCard(["Zika"], require("../images/zika.png"), "/zika")}

                {generateCard(["Influenza", "(uses nextflu.org)"], require("../images/influenza.png"), "/flu")}

    </g>
  );
};

export default Splash;
<commit_msg>Improve splash text slightly. Per #218.<commit_after>/*eslint-env browser*/
/*eslint max-len: 0*/
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import TitleBar from "../components/framework/title-bar";
import Title from "../components/framework/title";
import { headerFont, materialButtonOutline } from "../globalStyles";
import Flex from "../components/framework/flex";
import { analyticsNewPage } from "../util/googleAnalytics";
// import Card from "./framework/card";

const styles = {
  cardMainText: {
    fontFamily: headerFont,
    fontWeight: 500,
    fontSize: 28,
    position: "absolute",
    paddingTop: 10,
    paddingBottom: 10,
    paddingLeft: 20,
    paddingRight: 20,
    top: "40px",
    left: "20px",
    color: "white",
    background: "rgba(0, 0, 0, 0.7)"
  },
  cardSubText: {
    color: "white",
    fontStyle: "italic",
    fontSize: 16,
    fontWeight: 400,
    lineHeight: 0.3,
    textAlign: "right"
  },
  cardOuterDiv: {
    backgroundColor: "#FFFFFF",
    // marginLeft: 10,
    // marginRight: 10,
    // marginTop: 5,
    // marginBottom: 5,
    padding: 0,
    overflow: "hidden",
    position: "relative"
    // boxSizing: "content-box"
  },
  cardInnerDiv: {
    boxShadow: "3px 3px 4px 1px rgba(215,215,215,0.85)",
    borderRadius: 2,
    marginLeft: 10,
    marginRight: 10,
    marginTop: 5,
    marginBottom: 5
    // display: "flex",
    // justifyContent: "center",
    // alignItems: "center",
    // overflow: "hidden"
  },
  cardImg: {
    objectFit: "cover",
    width: "100%"
  }
};

const generateCard = (title, imgRequired, to) => (

      <Link to={to}>

          {title[0]}
          {title.length === 2 ?
{title[1]}
 : null}

      </Link>

);

const Splash = () => {
  analyticsNewPage();
  return(
    <g>
      <TitleBar logoHidden={true} titleHidden={true}/>

            <Title/>

            Real-time tracking of virus evolution

            Nextstrain is an open-source project to harness the scientific and public health potential of pathogen genome data. We provide a continually-updated view of publicly available data with powerful analytics and visualizations showing pathogen evolution and epidemic spread. Our goal is to aid epidemiological understanding and improve outbreak response.

            <Link to="/about">
              <button style={materialButtonOutline}>
                Learn More
              </button>
            </Link>

        {/* THE CLICKABLE CARDS
          images styalized in lunapic witht he grey filter
          https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/197-Zika_Virus-ZikaVirus.tif/lossy-page1-800px-197-Zika_Virus-ZikaVirus.tif.jpg
          http://www.cidresearch.org/uploads/12/10/ebola_virus_particles_budding_VERO_E6_cell_blue_yellow_NIAID.jpg
          http://cdn1.bostonmagazine.com/wp-content/uploads/2013/10/flu-virus-main.jpg
        */}

                {generateCard(["Ebola"], require("../images/ebola.png"), "/ebola?c=division&r=division")}

                {generateCard(["Zika"], require("../images/zika.png"), "/zika")}

                {generateCard(["Influenza", "(uses nextflu.org)"], require("../images/influenza.png"), "/flu")}

    </g>
  );
};

export default Splash;
<|endoftext|>


<commit_before>'use strict'
require('.')
<commit_msg>test(api): cover with tests the JavaScript API<commit_after>'use strict'
const describe = require('mocha').describe
const it = require('mocha').it
const expect = require('chai').expect
const mos = require('.')

describe('mos', () => {
  describe('use', () => {
    it('should register mos plugin', done => {
      const processor = mos().use(md => ({ foo: 'foo' }))
      return processor.process('<!--@foo--><!--/@-->', {filePath: __filename})
        .then(newmd => {
          expect(newmd).to.eq('<!--@foo-->\nfoo\n<!--/@-->\n')
          done()
        })
        .catch(done)
    })
  })
})
<|endoftext|>


<commit_before>/**
 * @file
 * Environment initialisation library.
 */
'use strict';

var
  shell,
  libUtils;

shell = require('shelljs');
libUtils = require('../utils');

exports.init = function (force) {
  // Make sure we don't run this twice.
  if (libUtils.config.checkInit() && !force) {
    throw new Error("Init has already been run. Use '--force' to force a reinit.");
  }

  if (force) {
    libUtils.logger.warn('This will delete any Docker images and containers you may have.');
    // @TODO: Prompt for continue.
  }

  // Install boot2docker.
  if (shell.which('boot2docker') === null) {
    libUtils.logger.info("You don't appear to have boot2docker, installing now.");
    libUtils.common.shell('brew', [
      'update'
    ]);
    libUtils.common.shell('brew', [
      'install',
      'boot2docker'
    ]);
  }

  // Re-init boot2docker image, even if there is an instance of it.
  libUtils.logger.info('Downloading and setting up boot2docker image...');
  libUtils.common.shell('boot2docker', ['poweroff']);
  libUtils.common.shell('boot2docker', ['download']);
  libUtils.common.shell('boot2docker', ['delete']);
  libUtils.common.shell('boot2docker', ['init']);
  libUtils.common.shell('boot2docker', ['up']);

  // Download profile file so that the docker daemon waits for the local network
  // to come up before starting. This will hopefully be fixed in boot2docker
  // v1.7.1. See https://github.com/boot2docker/boot2docker/issues/824.
  // @TODO: Make this less reliant on bash or atleast explicitly run in bash.
  libUtils.common.shell('ssh', [
    '-i $HOME/.ssh/id_boot2docker',
    "-p $(boot2docker config 2>&1 | awk '/SSHPort/ {print $3}')",
    'docker@localhost',
    '"sudo curl -o /var/lib/boot2docker/profile https://gist.githubusercontent.com/chinthakagodawita/e603c3c0699f5d2fd4cc/raw/3d09c77aae38b4f2809d504784965f5a16f2de4c/profile"'
  ]);

  // Restart boot2docker image. We do a force-halt just incase there are
  // problems bringing it down.
  libUtils.logger.info('Restarting boot2docker machine, post-config...');
  libUtils.common.shell('boot2docker', ['poweroff']);
  libUtils.common.shell('boot2docker', ['up']);

  // Prevent multiple initialisation.
  libUtils.config.setInit();
};
<commit_msg>#2: Init now uses custom boot2docker image from chinthakagodawita/boot2docker-custom.<commit_after>/**
 * @file
 * Environment initialisation library.
 */
'use strict';

var
  shell,
  libUtils;

shell = require('shelljs');
libUtils = require('../utils');

exports.init = function (force) {
  // Make sure we don't run this twice.
  if (libUtils.config.checkInit() && !force) {
    throw new Error("Init has already been run. Use '--force' to force a reinit.");
  }

  if (force) {
    libUtils.logger.warn('This will delete any Docker images and containers you may have.');
    // @TODO: Prompt for continue.
  }

  // Install boot2docker.
  if (shell.which('boot2docker') === null) {
    libUtils.logger.info("You don't appear to have boot2docker, installing now.");
    libUtils.common.shell('brew', [
      'update'
    ]);
    libUtils.common.shell('brew', [
      'install',
      'boot2docker'
    ]);
  }

  // Re-init boot2docker image, even if there is an instance of it.
  libUtils.logger.info('Downloading and setting up boot2docker image...');
  libUtils.common.shell('boot2docker', ['poweroff']);
  libUtils.common.shell('boot2docker', [
    'download',
    '--iso-url="https://api.github.com/repos/chinthakagodawita/boot2docker-custom/releases"'
  ]);
  libUtils.common.shell('boot2docker', ['delete']);
  libUtils.common.shell('boot2docker', ['init']);
  libUtils.common.shell('boot2docker', ['up']);

  // Download profile file so that the docker daemon waits for the local network
  // to come up before starting. This will hopefully be fixed in boot2docker
  // v1.7.1. See https://github.com/boot2docker/boot2docker/issues/824.
  // @TODO: Make this less reliant on bash or atleast explicitly run in bash.
  // libUtils.common.shell('ssh', [
  //   '-i $HOME/.ssh/id_boot2docker',
  //   "-p $(boot2docker config 2>&1 | awk '/SSHPort/ {print $3}')",
  //   'docker@localhost',
  //   '"sudo curl -o /var/lib/boot2docker/profile https://gist.githubusercontent.com/chinthakagodawita/e603c3c0699f5d2fd4cc/raw/3d09c77aae38b4f2809d504784965f5a16f2de4c/profile"'
  // ]);

  // Restart boot2docker image. We do a force-halt just incase there are
  // problems bringing it down.
  // libUtils.logger.info('Restarting boot2docker machine, post-config...');
  // libUtils.common.shell('boot2docker', ['poweroff']);
  // libUtils.common.shell('boot2docker', ['up']);

  // Prevent multiple initialisation.
  libUtils.config.setInit();
};
<|endoftext|>


<commit_before>/*!
	Structures results from SELECT queries
	eliminating JOIN's artifact
*/

import keypath from './keypath.js';

// return the innermost relationship of the tree (aka the root)
const root_rel = (rel) => {
	while (rel.superset) {
		rel = rel.superset;
	}
	return rel;
};
const build_tree = (rels) => {
	// roots are all the bottom resources in the superset chain
	const roots =
		rels.map((rel) => root_rel(rel))
		// remove dupes
		.filter((rel, i, all) => {
			return i === all.map(x => keypath(x)).indexOf(keypath(rel))
		});
	// build the rest of the tree
	roots.forEach((root) => {
		root.children = build_tree(
				// same ancestor
			rels.filter((rel) => keypath(root) === keypath(root_rel(rel)))
				// deepen one more level
				.reduce((new_rels, sub_rel) => {
					if (sub_rel.superset === undefined) return new_rels;
					let sup = sub_rel;
					while (sup.superset.superset) {
						sup = sup.superset;
					}
					delete sup.superset;
					return new_rels.concat(sub_rel);
				}, [])
		);
	});
	return roots;
};

const structureArray = (unmerged, parent_type, tree, context) => {

	// utility equivalent to is_array(x) ? x : [x]
	const arrayfy = (x) => [].concat(x);

	const merge = (already_merged, to_merge) => {
		tree.forEach((rel) => {
			const key = rel.relationship.name;
			already_merged[key] =
				arrayfy(already_merged[key]).concat(to_merge[key]);
		});
	};

	const pk = context.resources[parent_type].primary_key;
	let merged = [];

	merged = unmerged.reduce((merged, to_merge) => {
		const is_first_occurence = merged.every((already_merged) => {
			// if we found an occurence of this resource
			// before, merge it to the previous resource
			if (already_merged[pk] === to_merge[pk] && to_merge[pk] !== null) {
				merge(already_merged, to_merge);
				return false;
			}
			return true;
		});
		// if it's the first time we encounter
		// the resource, we push it to the collection,
		// otherwise we merged it before so we just
		// return the collection as-is
		if (!is_first_occurence) return merged;
		return merged.concat(to_merge);
	}, []);

	// we make sure one-to-many relationships are arrays
	// even if they contain only one resource
	// (in which case they would still not be array at this point)
	tree.forEach((rel) => {
		merged.forEach((res) => {
			const key = rel.relationship.name;
			if (rel.relationship.to === 'many') {
				res[key] = arrayfy(res[key]);
				if (res[key][0][context.resources[rel.relationship.type].primary_key] === null) {
					res[key] = [];
				}
			}
		});
	});

	// recursive step: merge subresources
	tree.forEach((rel) => {
		merged.forEach((res) => {
			const key = rel.relationship.name;
			// merges subresources
			res[key] = structureArray(
				arrayfy(res[key]),
				rel.type,
				rel.children,
				context
			);
			// we unwrap one-to-one relationships from the
			// array container which structureArray() puts
			if (rel.relationship.to === 'one') {
				res[key] = res[key][0];
				if (res[key][0][context.resources[rel.relationship.type].primary_key] === null) {
					res[key] = null;
				}
			}
		})
	});

	return merged;
};

export default function (results, request, context) {
	return structureArray(
		results.map(x => x[request.main.type]),
		request.main.type,
		build_tree(request.related),
		context
	)
}
<commit_msg>fixed typo<commit_after>/*!
	Structures results from SELECT queries
	eliminating JOIN's artifact
*/

import keypath from './keypath.js';

// return the innermost relationship of the tree (aka the root)
const root_rel = (rel) => {
	while (rel.superset) {
		rel = rel.superset;
	}
	return rel;
};
const build_tree = (rels) => {
	// roots are all the bottom resources in the superset chain
	const roots =
		rels.map((rel) => root_rel(rel))
		// remove dupes
		.filter((rel, i, all) => {
			return i === all.map(x => keypath(x)).indexOf(keypath(rel))
		});
	// build the rest of the tree
	roots.forEach((root) => {
		root.children = build_tree(
				// same ancestor
			rels.filter((rel) => keypath(root) === keypath(root_rel(rel)))
				// deepen one more level
				.reduce((new_rels, sub_rel) => {
					if (sub_rel.superset === undefined) return new_rels;
					let sup = sub_rel;
					while (sup.superset.superset) {
						sup = sup.superset;
					}
					delete sup.superset;
					return new_rels.concat(sub_rel);
				}, [])
		);
	});
	return roots;
};

const structureArray = (unmerged, parent_type, tree, context) => {

	// utility equivalent to is_array(x) ? x : [x]
	const arrayfy = (x) => [].concat(x);

	const merge = (already_merged, to_merge) => {
		tree.forEach((rel) => {
			const key = rel.relationship.name;
			already_merged[key] =
				arrayfy(already_merged[key]).concat(to_merge[key]);
		});
	};

	const pk = context.resources[parent_type].primary_key;
	let merged = [];

	merged = unmerged.reduce((merged, to_merge) => {
		const is_first_occurence = merged.every((already_merged) => {
			// if we found an occurence of this resource
			// before, merge it to the previous resource
			if (already_merged[pk] === to_merge[pk] && to_merge[pk] !== null) {
				merge(already_merged, to_merge);
				return false;
			}
			return true;
		});
		// if it's the first time we encounter
		// the resource, we push it to the collection,
		// otherwise we merged it before so we just
		// return the collection as-is
		if (!is_first_occurence) return merged;
		return merged.concat(to_merge);
	}, []);

	// we make sure one-to-many relationships are arrays
	// even if they contain only one resource
	// (in which case they would still not be array at this point)
	tree.forEach((rel) => {
		merged.forEach((res) => {
			const key = rel.relationship.name;
			if (rel.relationship.to === 'many') {
				res[key] = arrayfy(res[key]);
				if (res[key][0][context.resources[rel.relationship.type].primary_key] === null) {
					res[key] = [];
				}
			}
		});
	});

	// recursive step: merge subresources
	tree.forEach((rel) => {
		merged.forEach((res) => {
			const key = rel.relationship.name;
			// merges subresources
			res[key] = structureArray(
				arrayfy(res[key]),
				rel.type,
				rel.children,
				context
			);
			// we unwrap one-to-one relationships from the
			// array container which structureArray() puts
			if (rel.relationship.to === 'one') {
				res[key] = res[key][0];
				if (res[key][context.resources[rel.relationship.type].primary_key] === null) {
					res[key] = null;
				}
			}
		})
	});

	return merged;
};

export default function (results, request, context) {
	return structureArray(
		results.map(x => x[request.main.type]),
		request.main.type,
		build_tree(request.related),
		context
	)
}
<|endoftext|>


<commit_before>module('storage/async', function( exports ) {

var SQL = {
	CREATE : "CREATE TABLE IF NOT EXISTS dict(key TEXT UNIQUE, value TEXT)",
	DROP   : "DROP TABLE IF EXISTS dict",
	REPLACE: "INSERT OR REPLACE INTO dict values(?, ?)",
	DELETE : "DELETE FROM dict WHERE key = ?",
	SELECT : "SELECT value FROM dict WHERE key = ?",
	COUNT  : "SELECT COUNT(*) AS c FROM dict WHERE key = ?",
	SELECT_ALL_KEYS : "SELECT key FROM dict",
	SELECT_ALL_PAIRS: "SELECT key, value FROM dict",
	SELECT_KEYS : "SELECT key FROM dict WHERE substr(key, 1, ?) = ?",
	SELECT_PAIRS: "SELECT key, value FROM dict WHERE substr(key, 1, ?) = ?"
};

function reportError( error ) {
	console.error( error );
}

function creationCallback( db ) {
	db.changeVersion( '', '1', createTable, reportError );
}

function createTable( t ) {
	t.executeSql( SQL.CREATE );
}

function resetTable( t ) {
	t.executeSql( SQL.DROP );
	t.executeSql( SQL.CREATE );
}

function dropTable( t ) {
	t.executeSql( SQL.DROP );
}

var DictStorage = exports.DictStorage = Class({

	open: function( name, estimatedSize ) {
		this._db = openDatabase(
			'dict.' + name,
			'',
			'',
			( estimatedSize == null ? 2*1024*1024 : estimatedSize )
			//, creationCallback // bug?
		);

		this._db.transaction( createTable, reportError );
	},

	reset: function( errCb, cb ) {
		this._db.transaction( resetTable, errCb, cb );
	},

	erase: function( errCb, cb ) {
		var db = this._db;
		this._db = null;

		db.transaction( dropTable, errCb, cb );
	},

	readTransaction: function( cb, errCb, succCb ) {
		this._db.readTransaction(
			function( t ) {
				cb( new ReadTransaction(t) );
			},
			errCb,
			succCb
		);
	},

	transaction: function( cb, errCb, succCb ) {
		this._db.transaction(
			function( t ) {
				cb( new Transaction(t) );
			},
			errCb,
			succCb
		);
	},

	hasKey: function( key, errCb, cb ) {
		this._db.readTransaction(
			function( t ) {
				new ReadTransaction( t ).hasKey( key, cb );
			},
			errCb,
			null
		);
	},

	getValue: function( key, errCb, cb ) {
		this._db.readTransaction(
			function( t ) {
				new ReadTransaction( t ).getValue( key, cb );
			},
			errCb,
			null
		);
	},

	set: function( key, value, errCb, cb ) {
		this._db.transaction(
			function( t ) {
				new Transaction( t ).set( key, value );
			},
			errCb,
			cb
		);
	},

	remove: function( key, errCb, cb ) {
		this._db.transaction(
			function( t ) {
				new Transaction( t ).remove( key );
			},
			errCb,
			cb
		);
	},

	keys: function( prefix, errCb, cb ) {
		var keys = [], sql, args;

		if ( prefix ) {
			sql = SQL.SELECT_KEYS;
			args = [ prefix.length, prefix ];

		} else {
			sql = SQL.SELECT_ALL_KEYS;
			args = null;
		}

		this._db.readTransaction(
			function( t ) {
				t.executeSql( sql, args, function( t, r ) {
					for ( var i = 0, l = r.rows.length; i < l; ++i ) {
						keys.push( r.rows.item(i).key );
					}
				});
			},
			errCb,
			function() {
				cb( keys );
			}
		);
	},

	each: function( prefix, proc, errCb, cb ) {
		var sql, args;

		if ( prefix ) {
			sql = SQL.SELECT_PAIRS;
			args = [ prefix.length, prefix ];

		} else {
			sql = SQL.SELECT_ALL_PAIRS;
			args = null;
		}

		this._db.readTransaction(
			function( t ) {
				t.executeSql( sql, args, function( t, r ) {
					for ( var item, i = 0, l = r.rows.length; i < l; ++i ) {
						row = r.rows.item(i);
						proc( row.key, row.value );
					}
				});
			},
			errCb,
			cb
		);
	},

	updateWithObject: function( obj, errCb, cb ) {
		var sql = SQL.REPLACE;

		this._db.transaction(function( t ) {
			for ( var key in obj ) {
				t.executeSql( sql, [ key, obj[key] ] );
			}
		}, errCb, cb);
	}
});

DictStorage.open = function() {
	var ds = new DictStorage();
	ds.open.apply( ds, arguments );
	return ds;
};

DictStorage.erase = function( name ) {
	DictStorage.open( name, 0 ).erase();
};

var ReadTransaction = Class({

	constructor: function( tr ) {
		this._tr = tr;
	},

	getValue: function( key, cb, errCb ) {
		this._tr.executeSql( SQL.SELECT, [ key ],
			function( t, r ) {
				cb( r.rows.length ? r.rows.item(0).value : undefined );
			},
			errCb && function(t,e){ errCb(e); }
		);
	},

	hasKey: function( key, cb, errCb ) {
		this._tr.executeSql( SQL.COUNT, [ key ],
			function( t, r ) {
				cb( r.rows.item(0).c > 0 );
			},
			errCb && function(t,e){ errCb(e); }
		);
	}
});

var Transaction = Class( ReadTransaction, {

	set: function( key, value, errCb ) {
		this._tr.executeSql( SQL.REPLACE, [ key, value ],
			null,
			errCb && function(t,e){ errCb(e); }
		);
	},

	remove: function( key, errCb ) {
		this._tr.executeSql( SQL.DELETE, [ key ],
			null,
			errCb && function(t,e){ errCb(e); }
		);
	}
});

});
<commit_msg>Uppercase SQL.<commit_after>module('storage/async', function( exports ) {

var SQL = {
	CREATE : "CREATE TABLE IF NOT EXISTS dict(key TEXT UNIQUE, value TEXT)",
	DROP   : "DROP TABLE IF EXISTS dict",
	REPLACE: "INSERT OR REPLACE INTO dict VALUES (?, ?)",
	DELETE : "DELETE FROM dict WHERE key = ?",
	SELECT : "SELECT value FROM dict WHERE key = ?",
	COUNT  : "SELECT COUNT(*) AS c FROM dict WHERE key = ?",
	SELECT_ALL_KEYS : "SELECT key FROM dict",
	SELECT_ALL_PAIRS: "SELECT key, value FROM dict",
	SELECT_KEYS : "SELECT key FROM dict WHERE substr(key, 1, ?) = ?",
	SELECT_PAIRS: "SELECT key, value FROM dict WHERE substr(key, 1, ?) = ?"
};

function reportError( error ) {
	console.error( error );
}

function creationCallback( db ) {
	db.changeVersion( '', '1', createTable, reportError );
}

function createTable( t ) {
	t.executeSql( SQL.CREATE );
}

function resetTable( t ) {
	t.executeSql( SQL.DROP );
	t.executeSql( SQL.CREATE );
}

function dropTable( t ) {
	t.executeSql( SQL.DROP );
}

var DictStorage = exports.DictStorage = Class({

	open: function( name, estimatedSize ) {
		this._db = openDatabase(
			'dict.' + name,
			'',
			'',
			( estimatedSize == null ? 2*1024*1024 : estimatedSize )
			//, creationCallback // bug?
		);

		this._db.transaction( createTable, reportError );
	},

	reset: function( errCb, cb ) {
		this._db.transaction( resetTable, errCb, cb );
	},

	erase: function( errCb, cb ) {
		var db = this._db;
		this._db = null;

		db.transaction( dropTable, errCb, cb );
	},

	readTransaction: function( cb, errCb, succCb ) {
		this._db.readTransaction(
			function( t ) {
				cb( new ReadTransaction(t) );
			},
			errCb,
			succCb
		);
	},

	transaction: function( cb, errCb, succCb ) {
		this._db.transaction(
			function( t ) {
				cb( new Transaction(t) );
			},
			errCb,
			succCb
		);
	},

	hasKey: function( key, errCb, cb ) {
		this._db.readTransaction(
			function( t ) {
				new ReadTransaction( t ).hasKey( key, cb );
			},
			errCb,
			null
		);
	},

	getValue: function( key, errCb, cb ) {
		this._db.readTransaction(
			function( t ) {
				new ReadTransaction( t ).getValue( key, cb );
			},
			errCb,
			null
		);
	},

	set: function( key, value, errCb, cb ) {
		this._db.transaction(
			function( t ) {
				new Transaction( t ).set( key, value );
			},
			errCb,
			cb
		);
	},

	remove: function( key, errCb, cb ) {
		this._db.transaction(
			function( t ) {
				new Transaction( t ).remove( key );
			},
			errCb,
			cb
		);
	},

	keys: function( prefix, errCb, cb ) {
		var keys = [], sql, args;

		if ( prefix ) {
			sql = SQL.SELECT_KEYS;
			args = [ prefix.length, prefix ];

		} else {
			sql = SQL.SELECT_ALL_KEYS;
			args = null;
		}

		this._db.readTransaction(
			function( t ) {
				t.executeSql( sql, args, function( t, r ) {
					for ( var i = 0, l = r.rows.length; i < l; ++i ) {
						keys.push( r.rows.item(i).key );
					}
				});
			},
			errCb,
			function() {
				cb( keys );
			}
		);
	},

	each: function( prefix, proc, errCb, cb ) {
		var sql, args;

		if ( prefix ) {
			sql = SQL.SELECT_PAIRS;
			args = [ prefix.length, prefix ];

		} else {
			sql = SQL.SELECT_ALL_PAIRS;
			args = null;
		}

		this._db.readTransaction(
			function( t ) {
				t.executeSql( sql, args, function( t, r ) {
					for ( var item, i = 0, l = r.rows.length; i < l; ++i ) {
						row = r.rows.item(i);
						proc( row.key, row.value );
					}
				});
			},
			errCb,
			cb
		);
	},

	updateWithObject: function( obj, errCb, cb ) {
		this._db.transaction(function( t ) {
			var sql = SQL.REPLACE;

			for ( var key in obj ) {
				t.executeSql( sql, [ key, obj[key] ] );
			}
		}, errCb, cb);
	}
});

DictStorage.open = function() {
	var ds = new DictStorage();
	ds.open.apply( ds, arguments );
	return ds;
};

DictStorage.erase = function( name ) {
	DictStorage.open( name, 0 ).erase();
};

var ReadTransaction = Class({

	constructor: function( tr ) {
		this._tr = tr;
	},

	getValue: function( key, cb, errCb ) {
		this._tr.executeSql( SQL.SELECT, [ key ],
			function( t, r ) {
				cb( r.rows.length ? r.rows.item(0).value : undefined );
			},
			errCb && function(t,e){ errCb(e); }
		);
	},

	hasKey: function( key, cb, errCb ) {
		this._tr.executeSql( SQL.COUNT, [ key ],
			function( t, r ) {
				cb( r.rows.item(0).c > 0 );
			},
			errCb && function(t,e){ errCb(e); }
		);
	}
});

var Transaction = Class( ReadTransaction, {

	set: function( key, value, errCb ) {
		this._tr.executeSql( SQL.REPLACE, [ key, value ],
			null,
			errCb && function(t,e){ errCb(e); }
		);
	},

	remove: function( key, errCb ) {
		this._tr.executeSql( SQL.DELETE, [ key ],
			null,
			errCb && function(t,e){ errCb(e); }
		);
	}
});

});
<|endoftext|>


<commit_before>TrelloPowerUp.initialize({
  'card-badges' : function(t, card) {
    t.card('attachments').then(function(attachments){
      if(!attachments || !attachments.length) return;

      return attachments.map(function(attachment){
        var url = new URL(attachment.url);
        return {
          icon: 'https://api.faviconkit.com/icons/' + url.hostname + '/144.png'
        }
      });
    })
  },

  'format-url' : function(t, options) {
    return {
      icon: 'https://api.faviconkit.com/icons/apple.com/144.png',
      text: options.url
    }
  }
});<commit_msg>logging<commit_after>TrelloPowerUp.initialize({
  'card-badges' : function(t, card) {
    t.card('attachments').then(function(attachments){
      console.log(attachments);
      if(!attachments || !attachments.length) return;

      return attachments.map(function(attachment){
        var url = new window.URL(attachment.url);
        return {
          icon: 'https://api.faviconkit.com/icons/' + url.hostname + '/144.png'
        }
      });
    })
  },

  'format-url' : function(t, options) {
    return {
      icon: 'https://api.faviconkit.com/icons/apple.com/144.png',
      text: options.url
    }
  }
});<|endoftext|>


<commit_before>'use_strict';

var ItemParser = require('./item-parser.js');
var Search = require('./search.js');
var Scrobble = require('./scrobble.js');

function ContentController() {
  this.item = null;
  this.scrobble = undefined;

  if (location.href.match(/watch/)) {
    ItemParser.start(this.storeItem.bind(this));
  }
};

ContentController.prototype = {
  onSearchSuccess: function(response) {
    this.sendAnalyticsEvent({ name: 'onSearchSuccess', value: this.item.title });

    this.scrobble = new Scrobble({
      response: response,
      type: this.item.type,
      scrubber: this.item.getScrubber.bind(this.item),
      success: this.onScrobbleSuccess.bind(this),
      error: this.onScrobbleError.bind(this)
    });

    this.setActiveIcon();
    this.scrobble.start();
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'start' });
  },

  onSearchError: function(status, response) {
    this.sendAnalyticsEvent({ name: 'onSearchError', value: (this.item && this.item.title) ? this.item.title : status });
    console.error('traktflix: Search error', status, response, this.item.title);
  },

  onScrobbleSuccess: function() {
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'onSuccess' });
  },

  onScrobbleError: function() {
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'onError' });
    console.error('traktflix: Scrobble error');
  },

  storeItem: function(item) {
    this.item = item;

    if (this.item !== null) {
      var search = new Search({ item: this.item });
      search.find({
        success: this.onSearchSuccess.bind(this),
        error: this.onSearchError.bind(this)
      });
    } else {
      this.scrobble = undefined;
    }
  },

  onPlay: function(e) {
    if (this.item === null && this.scrobble === undefined) {
      ItemParser.start(this.storeItem.bind(this));
    } else {
      this.setActiveIcon();
      this.scrobble.start();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'start' });
    }
  },

  onPause: function(e) {
    if (this.scrobble != undefined) {
      this.setInactiveIcon();
      this.scrobble.pause();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'pause' });
    }
  },

  onStop: function(e) {
    if (this.scrobble !== undefined) {
      this.setInactiveIcon();
      this.scrobble.stop();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'stop' });
    }
    this.storeItem(null);
  },

  setInactiveIcon: function() {
    chrome.runtime.sendMessage({ type: 'setInactiveIcon' });
  },

  setActiveIcon: function() {
    chrome.runtime.sendMessage({ type: 'setActiveIcon' });
  },

  sendAnalyticsEvent: function(options) {
    chrome.runtime.sendMessage({
      type: 'sendEvent', name: options.name, value: options.value
    });
  },

  getCurrentItem: function() {
    if (this.item && this.item.type === 'show') {
      return { item: this.scrobble.item.episode };
    } else if (this.item && this.item.type === 'movie') {
      return { item: this.scrobble.item.movie };
    }
  }
};

module.exports = ContentController;<commit_msg>Could still be smart to log the status even if the title is set.<commit_after>'use_strict';

var ItemParser = require('./item-parser.js');
var Search = require('./search.js');
var Scrobble = require('./scrobble.js');

function ContentController() {
  this.item = null;
  this.scrobble = undefined;

  if (location.href.match(/watch/)) {
    ItemParser.start(this.storeItem.bind(this));
  }
};

ContentController.prototype = {
  onSearchSuccess: function(response) {
    this.sendAnalyticsEvent({ name: 'onSearchSuccess', value: this.item.title });

    this.scrobble = new Scrobble({
      response: response,
      type: this.item.type,
      scrubber: this.item.getScrubber.bind(this.item),
      success: this.onScrobbleSuccess.bind(this),
      error: this.onScrobbleError.bind(this)
    });

    this.setActiveIcon();
    this.scrobble.start();
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'start' });
  },

  onSearchError: function(status, response) {
    this.sendAnalyticsEvent({ name: 'onSearchError', value: status + (this.item && this.item.title) ? this.item.title : "Invalid item title" });
    console.error('traktflix: Search error', status, response, this.item.title);
  },

  onScrobbleSuccess: function() {
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'onSuccess' });
  },

  onScrobbleError: function() {
    this.sendAnalyticsEvent({ name: 'Scrobble', value: 'onError' });
    console.error('traktflix: Scrobble error');
  },

  storeItem: function(item) {
    this.item = item;

    if (this.item !== null) {
      var search = new Search({ item: this.item });
      search.find({
        success: this.onSearchSuccess.bind(this),
        error: this.onSearchError.bind(this)
      });
    } else {
      this.scrobble = undefined;
    }
  },

  onPlay: function(e) {
    if (this.item === null && this.scrobble === undefined) {
      ItemParser.start(this.storeItem.bind(this));
    } else {
      this.setActiveIcon();
      this.scrobble.start();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'start' });
    }
  },

  onPause: function(e) {
    if (this.scrobble != undefined) {
      this.setInactiveIcon();
      this.scrobble.pause();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'pause' });
    }
  },

  onStop: function(e) {
    if (this.scrobble !== undefined) {
      this.setInactiveIcon();
      this.scrobble.stop();
      this.sendAnalyticsEvent({ name: 'Scrobble', value: 'stop' });
    }
    this.storeItem(null);
  },

  setInactiveIcon: function() {
    chrome.runtime.sendMessage({ type: 'setInactiveIcon' });
  },

  setActiveIcon: function() {
    chrome.runtime.sendMessage({ type: 'setActiveIcon' });
  },

  sendAnalyticsEvent: function(options) {
    chrome.runtime.sendMessage({
      type: 'sendEvent', name: options.name, value: options.value
    });
  },

  getCurrentItem: function() {
    if (this.item && this.item.type === 'show') {
      return { item: this.scrobble.item.episode };
    } else if (this.item && this.item.type === 'movie') {
      return { item: this.scrobble.item.movie };
    }
  }
};

module.exports = ContentController;<|endoftext|>


<commit_before>export {
  getFile, putFile
} from 'blockstack-storage'

export * as storage from 'blockstack-storage'
<commit_msg>invalid syntax<commit_after>export {
  getFile, putFile
} from 'blockstack-storage'
<|endoftext|>