<commit_before>define([
	"dcl/dcl",
	"dojo/date",
	"dojo/date/locale",
	"dojo/cldr/supplemental",
	"dojo/date/stamp"
], function (
	dcl,
	ddate,
	locale,
	cldr,
	stamp
) {
	/**
	 * Mixin with time methods.
	 */
	return dcl(null, {
		_calendar: "gregorian",

		/**
		 * Object with same API as native Date class.
		 */
		dateClassObj: Date,

		/**
		 * Object with same API as dojo/date.
		 */
		dateModule: ddate,

		/**
		 * Object with same API as dojo/date/locale.
		 */
		dateLocaleModule: locale,

		// firstDayOfWeek: Integer
		//		0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday.
		firstDayOfWeek: cldr.getFirstDayOfWeek(),

		newDate: function (obj) {
			// summary:
			//		Creates a new Date object.
			// obj: Object
			//		This object can have several values:
			//		- the time in milliseconds since gregorian epoch.
			//		- a Date instance
			// returns: Date

			var d;

			if (typeof obj === "number") {
				return new this.dateClassObj(obj);
			} else if (obj.getTime) {
				return new this.dateClassObj(obj.getTime());
			} else if (obj.toGregorian) {
				d = obj.toGregorian();
				if (this.dateClassObj !== Date) {
					d = new this.dateClassObj(d.getTime());
				}
				return d;
			} else if (typeof obj === "string") {
				d = stamp.fromISOString(obj);
				if (d === null) {
					throw new Error("Cannot parse date string (" + obj + "), specify a \"decodeDate\" function that " +
						"translates this string into a Date object"); // cannot build date
				} else if (this.dateClassObj !== Date) { // from Date to this.dateClassObj
					d = new this.dateClassObj(d.getTime());
				}
				return d;
			}
		},

		isWeekEnd: function (date) {
			// summary:
			//		Determines whether the specified date is a week-end.
			//		This method is using dojo.date.locale.isWeekend() method as
			//		dojox.date.XXXX calendars are not supporting this method.
			// date: Date
			//		The date to test.

			return locale.isWeekend(date);
		},

		getWeekNumberLabel: function (date) {
			// summary:
			//		Returns the week number string from dojo.date.locale.format() method as
			//		dojox.date.XXXX calendar are not supporting the "w" pattern.
			// date: Date
			//		The date to format.

			if (date.toGregorian) {
				date = date.toGregorian();
			}
			return locale.format(date, {
				selector: "date",
				datePattern: "w"
			});
		},

		addAndFloor: function (date, unit, steps) {
			// date must be floored!!
			// unit >= day
			var d = this.dateModule.add(date, unit, steps);
			if (d.getHours() === 23) {
				d = this.dateModule.add(d, "hour", 2); // go to 1am
			} else {
				d = this.floorToDay(d);
			}
			return d;
		},

		floorToDay: function (date) {
			// summary:
			//		Floors the specified date to the start of day.
			// date: Date
			//		The date to floor.
			// returns: Date

			return new this.dateClassObj(date.getFullYear(), date.getMonth(), date.getDate());
		},

		floorToWeek: function (date) {
			// summary:
			//		Floors the specified date to the beginning of week.
			// date: Date
			//		Date to floor.

			var fd = this.firstDayOfWeek;
			var day = date.getDay();
			var dayAdjust =  day >= fd ? -day + fd : -day + fd - 7;
			return new this.dateClassObj(date.getFullYear(), date.getMonth(), date.getDate() + dayAdjust);
		},

		floorToMonth: function (date) {
			// summary:
			//		Floors the specified date to the start of the date's month.
			// date: Date
			//		The date to floor.
			// returns: Date

			return new this.dateClassObj(date.getFullYear(), date.getMonth(), 1);
		},

		isToday: function (date) {
			// summary:
			//		Returns whether the specified date is in the current day.
			// date: Date
			//		The date to test.
			// returns: Boolean

			var today = new this.dateClassObj();
			return date.getFullYear() === today.getFullYear() &&
				date.getMonth() === today.getMonth() &&
				date.getDate() === today.getDate();
		},

		isStartOfDay: function (date) {
			// summary:
			//		Tests if the specified date represents the starts of day.
			// date: Date
			//		The date to test.
			// returns: Boolean

			return this.dateModule.compare(this.floorToDay(date), date) === 0;
		},

		isOverlapping: function (start1, end1, start2, end2, includeLimits) {
			// summary:
			//		Computes if the first time range defined by the start1 and end1 parameters
			//		is overlapping the second time range defined by the start2 and end2 parameters.
			// start1: Date
			//		The start time of the first time range.
			// end1: Date
			//		The end time of the first time range.
			// start2: Date
			//		The start time of the second time range.
			// end2: Date
			//		The end time of the second time range.
			// includeLimits: Boolean
			//		Whether include the end time or not.
			// returns: Boolean

			if (start1 === null || start2 === null || end1 === null || end2 === null) {
				return false;
			}

			var cal = this.dateModule;

			if (includeLimits) {
				if (cal.compare(start1, end2) === 1 || cal.compare(start2, end1) === 1) {
					return false;
				}
			} else if (cal.compare(start1, end2) !== -1 || cal.compare(start2, end1) !== -1) {
				return false;
			}

			return true;
		},

		isSameDay: function (date1, date2) {
			// summary:
			//		Tests if the specified dates are in the same day.
			// date1: Date
			//		The first date.
			// date2: Date
			//		The second date.
			// returns: Boolean

			if (date1 === null || date2 === null) {
				return false;
			}

			return date1.getFullYear() === date2.getFullYear() &&
				date1.getMonth() === date2.getMonth() &&
				date1.getDate() === date2.getDate();
		}
	});
});
<commit_msg>Update TimeBase.js to use jsdoc format not dojodoc.<commit_after>define([
	"dcl/dcl",
	"dojo/date",
	"dojo/date/locale",
	"dojo/cldr/supplemental",
	"dojo/date/stamp"
], function (
	dcl,
	ddate,
	locale,
	cldr,
	stamp
) {
	/**
	 * Mixin with time methods.
	 */
	return dcl(null, {
		_calendar: "gregorian",

		/**
		 * Object with same API as native Date class.
		 */
		dateClassObj: Date,

		/**
		 * Object with same API as dojo/date.
		 */
		dateModule: ddate,

		/**
		 * Object with same API as dojo/date/locale.
		 */
		dateLocaleModule: locale,

		/**
		 * First day of the week for current locale.
		 * 0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday.
		 */
		firstDayOfWeek: cldr.getFirstDayOfWeek(),

		/**
		 * Creates a new Date object.
		 * @param obj
		 *		This object can have several values:
		 *
		 *		- the time in milliseconds since gregorian epoch.
		 *		- a Date instance
		 * @returns {Date}
		 */
		newDate: function (obj) {
			var d;

			if (typeof obj === "number") {
				return new this.dateClassObj(obj);
			} else if (obj.getTime) {
				return new this.dateClassObj(obj.getTime());
			} else if (obj.toGregorian) {
				d = obj.toGregorian();
				if (this.dateClassObj !== Date) {
					d = new this.dateClassObj(d.getTime());
				}
				return d;
			} else if (typeof obj === "string") {
				d = stamp.fromISOString(obj);
				if (d === null) {
					throw new Error("Cannot parse date string (" + obj + "), specify a \"decodeDate\" function that " +
						"translates this string into a Date object"); // cannot build date
				} else if (this.dateClassObj !== Date) { // from Date to this.dateClassObj
					d = new this.dateClassObj(d.getTime());
				}
				return d;
			}
		},

		/**
		 * Determines whether the specified date is a week-end.
		 * @param {Date} date
		 * @returns {boolean}
		 */
		isWeekEnd: function (date) {
			return locale.isWeekend(date);
		},

		/**
		 * Returns the week number string from dojo.date.locale.format() method
		 * @param {Date} date
		 * @returns {string}
		 */
		getWeekNumberLabel: function (date) {
			if (date.toGregorian) {
				date = date.toGregorian();
			}
			return locale.format(date, {
				selector: "date",
				datePattern: "w"
			});
		},

		addAndFloor: function (date, unit, steps) {
			// date must be floored!!
			// unit >= day
			var d = this.dateModule.add(date, unit, steps);
			if (d.getHours() === 23) {
				d = this.dateModule.add(d, "hour", 2); // go to 1am
			} else {
				d = this.floorToDay(d);
			}
			return d;
		},

		/**
		 * Floors the specified date to the start of day.
		 * @param {Date} date
		 * @returns {Date}
		 */
		floorToDay: function (date) {
			return new this.dateClassObj(date.getFullYear(), date.getMonth(), date.getDate());
		},

		/**
		 * Floors the specified date to the beginning of week.
		 * @param {Date} date
		 * @returns {Date}
		 */
		floorToWeek: function (date) {
			var fd = this.firstDayOfWeek;
			var day = date.getDay();
			var dayAdjust =  day >= fd ? -day + fd : -day + fd - 7;
			return new this.dateClassObj(date.getFullYear(), date.getMonth(), date.getDate() + dayAdjust);
		},

		/**
		 * Floors the specified date to the start of the date's month.
		 * @param {Date} date
		 * @returns {Date}
		 */
		floorToMonth: function (date) {
			return new this.dateClassObj(date.getFullYear(), date.getMonth(), 1);
		},

		/**
		 * Returns whether the specified date is in the current day.
		 * @param {Date} date
		 * @returns {boolean}
		 */
		isToday: function (date) {
			var today = new this.dateClassObj();
			return date.getFullYear() === today.getFullYear() &&
				date.getMonth() === today.getMonth() &&
				date.getDate() === today.getDate();
		},

		/**
		 * Tests if the specified date represents the start of the day.
		 * @param {Date} date
		 * @returns {boolean}
		 */
		isStartOfDay: function (date) {
			return this.dateModule.compare(this.floorToDay(date), date) === 0;
		},

		/**
		 * Computes if the first time range defined by the start1 and end1 parameters
		 * is overlapping the second time range defined by the start2 and end2 parameters.
		 * @param {Date} start1 - The start time of the first time range.
		 * @param {Date} end1 - The end time of the first time range.
		 * @param {Date} start2 - The start time of the second time range.
		 * @param {Date} end2 - The end time of the second time range.
		 * @param {boolean} includeLimits - Whether include the end time or not.
		 * @returns {boolean}
		 */
		isOverlapping: function (start1, end1, start2, end2, includeLimits) {
			if (start1 === null || start2 === null || end1 === null || end2 === null) {
				return false;
			}

			var cal = this.dateModule;

			if (includeLimits) {
				if (cal.compare(start1, end2) === 1 || cal.compare(start2, end1) === 1) {
					return false;
				}
			} else if (cal.compare(start1, end2) !== -1 || cal.compare(start2, end1) !== -1) {
				return false;
			}

			return true;
		},

		/**
		 * Tests if the specified dates are in the same day.
		 * @param {Date} date1 - The first date.
		 * @param {Date} date2 - The second date.
		 * @returns {boolean}
		 */
		isSameDay: function (date1, date2) {
			if (date1 === null || date2 === null) {
				return false;
			}

			return date1.getFullYear() === date2.getFullYear() &&
				date1.getMonth() === date2.getMonth() &&
				date1.getDate() === date2.getDate();
		}
	});
});
<|endoftext|>


<commit_before>'use strict';

let _ = require('lodash')
let Promise = require('bluebird')

let common = require('./commonGraduationRequirements')
let utilities = require('./commonGraduationUtilities')
let isMajoringIn = utilities.isMajoringIn
let educ = require('./commonEducationRequirements')

function artsMajor(studies, courses) {
	// One completed major is required for graduation. Depending on the
	// department or interdisciplinary program, the number of courses required
	// for a major ranges from eight to twelve courses, with some departments
	// requiring course work in other departments. Departments and
	// interdisciplinary programs may require comprehensive examinations or
	// special research projects. (See Majors, Concentrations, and Areas of
	// Emphasis.) Consult the department or interdisciplinary program listing
	// in this catalog for specific major requirements. Students must declare
	// one major no later than the time of registration for Interim and spring
	// semester of their junior year by filling out a form available at the
	// Office of the Registrar and Academic Advising. Students are allowed to
	// change this declaration or add a second major at a later date. Only
	// this catalog defines the specific requirements for each departmental or
	// interdisciplinary major.

	// Other regulations are:

	// Of the credits counting toward the minimum requirements for a major, a
	// total of six (6.00) must be completed with a grade of C or higher.
	// NOTE: Ignored, because we don't store grades.

	// Only one full-course equivalent (1.00-credit course) taken S/U may
	// count toward the minimum requirements for a major. Some departments
	// have more stringent regulations.
	// NOTE: Ignored, because we don't store s/u status.

	// At least 50 percent of the minimum major must be taken through St.
	// Olaf. Students should consult the registrar and the appropriate
	// department chair or program director about counting toward a major
	// courses taken at other colleges. In addition to the registrar, the
	// chair must sign the student’s transfer of credit form (available from
	// the Office of the Registrar and Academic Advising) if work from other
	// institutions is accepted in advance. Likewise, courses taken through
	// St. Olaf off-campus programs must be approved by the chair or director
	// and the off-campus program advisor in advance if credit toward a major
	// is sought.
	// NOTE: Ignored, because this doesn't know about major requirements.

	var majors = _.filter(studies, {type: 'major'})

	return {
		title: 'Major',
		type: 'boolean',
		result: _.size(majors) >= 1 && _.every(majors, utilities.creditsBeyondTheArea(courses, 8))
	}
}

function onlyTheTwoArtMajors(major) {
	return (major.title === 'Studio Art' || major.title === 'Art History')
}

function beyondTheMajor(studies, courses) {
	// While the maximum course credits counting toward a major in any one
	// department may vary, 21 total full-course credits must be completed
	// outside of the SIS "department" code of the major. The 21 total credits
	// include Education Department courses attending the major. In order for
	// a student to be certified in a second or third major, 21 credits also
	// must be taken outside of the SIS "department" code of each of those
	// majors as well. If a student has a double major, courses taken in one
	// major count toward the 21 credits outside of the other major. Credits
	// outside the major department or program include full (1.00) credit
	// courses plus partial - (.25, .50, .75) credit courses.

	// 2014/15: Students who double-major in studio art and art history are
	// required to complete at least 18 full-course credits outside the SIS
	// "ART" department designation.

	var majors = _.filter(studies, {type: 'major'})

	// If double-majorsing in ART HISTORY and STUDIO ART, ensure that they
	// have 18 credits outside of the ART dept. Accomplished by setting both
	// ART and STUDIO ART's dept to ART.
	var isDedicatedArtist = _.all([
		// Only returns true if majoring in both Studio Art and Art History.
		isMajoringIn('Studio Art', studies),
		isMajoringIn('Art History', studies),
	])

	var artMajorAndBeyond = undefined
	if (isDedicatedArtist) {
		// Check the two majors agains the 18-course requirement
		artMajorAndBeyond = _.chain(majors)
			.filter(onlyTheTwoArtMajors)
			.every(utilities.creditsBeyondTheArea(courses, 18))
			.value()

		// Remove the two majors, so they aren't checked against the 21-course
		// requirement.
		majors = _.chain(majors)
			.reject({title: 'Studio Art'})
			.reject({title: 'Art History'})
			.value()
	}

	// Ensure that each major has 21 credits beyond its scope.
	var mainstream = _.every(majors, utilities.creditsBeyondTheArea(courses, 21))

	var result = mainstream
	if (isDedicatedArtist) {
		result = _.all([mainstream, artMajorAndBeyond])
	}

	return {
		title: 'Beyond the Major',
		type: 'boolean',
		result: result
	}
}

function checkBachelorOfArtsDegree(student) {
	// Requirements taken from
	// http://www.stolaf.edu/catalog/1314/academiclife/ba-gen-grad-requirements.html

	var studies = student.studies
	var courses = _.filter(student.courses, utilities.onlyQuarterCreditCoursesCanBePassFail)
	var fabrications = []
	var creditsNeeded = student.creditsNeeded

	var graduationRequirements = [
		common.courses(courses, creditsNeeded),
		common.residency(courses, fabrications),
		common.interim(courses, fabrications),
		common.gpa(courses),
		common.courseLevel(courses),
		common.gradedCourses(courses, fabrications),
		artsMajor(studies, courses),
		beyondTheMajor(studies, courses),
	]

	if (utilities.isBachelorOfBoth(studies)) {
		graduationRequirements.push(common.artsAndMusicDoubleMajor(courses, studies, fabrications))
	}

	var educationRequirements = {
		foundation: [
			educ.firstYearWriting(courses),
			educ.writingInContext(courses),
			educ.foreignLanguage(courses),
			educ.oralCommunication(courses),
			educ.abstractAndQuantitativeReasoning(courses),
			educ.studiesInPhysicalMovement(courses),
		],
		core: [
			educ.historicalStudiesInWesternCulture(courses),
			educ.multiculturalDomesticStudies(courses),
			educ.multiculturalGlobalStudies(courses),
			educ.artisticStudies(courses),
			educ.literaryStudies(courses),
			educ.biblicalStudies(courses),
			educ.theologicalStudies(courses),
			educ.scientificExplorationAndDiscovery(courses),
			educ.integratedScientificTopics(courses),
			educ.studiesInHumanBehaviorAndSociety(courses),
		],
		integrative: [
			educ.ethicalIssuesAndNormativePerspectives(courses),
		]
	}

	var educationRequirementsResults = [
		{
			title: 'Foundation',
			type: 'array/boolean',
			result: _.all(educationRequirements.foundation, 'result'),
			details: educationRequirements.foundation,
		},
		{
			title: 'Core',
			type: 'array/boolean',
			result: _.all(educationRequirements.core, 'result'),
			details: educationRequirements.core
		},
		{
			title: 'Integrative',
			type: 'array/boolean',
			result: _.all(educationRequirements.integrative, 'result'),
			details: educationRequirements.integrative
		},
	]

	var bachelorOfArtsRequirements = [
		{
			title: 'Graduation',
			type: 'array/boolean',
			result: _.all(graduationRequirements, 'result'),
			details: graduationRequirements
		},
		{
			title: 'Education',
			type: 'array/requirementSet',
			result: _.all(educationRequirementsResults, 'result'),
			details: educationRequirementsResults
		}
	]

	// console.log('checkBachelorOfArtsDegree', 'results', bachelorOfArtsRequirements)

	return Promise.props({
		result: _.all(bachelorOfArtsRequirements, 'result'),
		details: bachelorOfArtsRequirements
	})
}

module.exports = checkBachelorOfArtsDegree
<commit_msg>Don't explicitly set things to undefined<commit_after>'use strict';

let _ = require('lodash')
let Promise = require('bluebird')

let common = require('./commonGraduationRequirements')
let utilities = require('./commonGraduationUtilities')
let isMajoringIn = utilities.isMajoringIn
let educ = require('./commonEducationRequirements')

function artsMajor(studies, courses) {
	// One completed major is required for graduation. Depending on the
	// department or interdisciplinary program, the number of courses required
	// for a major ranges from eight to twelve courses, with some departments
	// requiring course work in other departments. Departments and
	// interdisciplinary programs may require comprehensive examinations or
	// special research projects. (See Majors, Concentrations, and Areas of
	// Emphasis.) Consult the department or interdisciplinary program listing
	// in this catalog for specific major requirements. Students must declare
	// one major no later than the time of registration for Interim and spring
	// semester of their junior year by filling out a form available at the
	// Office of the Registrar and Academic Advising. Students are allowed to
	// change this declaration or add a second major at a later date. Only
	// this catalog defines the specific requirements for each departmental or
	// interdisciplinary major.

	// Other regulations are:

	// Of the credits counting toward the minimum requirements for a major, a
	// total of six (6.00) must be completed with a grade of C or higher.
	// NOTE: Ignored, because we don't store grades.

	// Only one full-course equivalent (1.00-credit course) taken S/U may
	// count toward the minimum requirements for a major. Some departments
	// have more stringent regulations.
	// NOTE: Ignored, because we don't store s/u status.

	// At least 50 percent of the minimum major must be taken through St.
	// Olaf. Students should consult the registrar and the appropriate
	// department chair or program director about counting toward a major
	// courses taken at other colleges. In addition to the registrar, the
	// chair must sign the student’s transfer of credit form (available from
	// the Office of the Registrar and Academic Advising) if work from other
	// institutions is accepted in advance. Likewise, courses taken through
	// St. Olaf off-campus programs must be approved by the chair or director
	// and the off-campus program advisor in advance if credit toward a major
	// is sought.
	// NOTE: Ignored, because this doesn't know about major requirements.

	var majors = _.filter(studies, {type: 'major'})

	return {
		title: 'Major',
		type: 'boolean',
		result: _.size(majors) >= 1 && _.every(majors, utilities.creditsBeyondTheArea(courses, 8))
	}
}

function onlyTheTwoArtMajors(major) {
	return (major.title === 'Studio Art' || major.title === 'Art History')
}

function beyondTheMajor(studies, courses) {
	// While the maximum course credits counting toward a major in any one
	// department may vary, 21 total full-course credits must be completed
	// outside of the SIS "department" code of the major. The 21 total credits
	// include Education Department courses attending the major. In order for
	// a student to be certified in a second or third major, 21 credits also
	// must be taken outside of the SIS "department" code of each of those
	// majors as well. If a student has a double major, courses taken in one
	// major count toward the 21 credits outside of the other major. Credits
	// outside the major department or program include full (1.00) credit
	// courses plus partial - (.25, .50, .75) credit courses.

	// 2014/15: Students who double-major in studio art and art history are
	// required to complete at least 18 full-course credits outside the SIS
	// "ART" department designation.

	var majors = _.filter(studies, {type: 'major'})

	// If double-majorsing in ART HISTORY and STUDIO ART, ensure that they
	// have 18 credits outside of the ART dept. Accomplished by setting both
	// ART and STUDIO ART's dept to ART.
	var isDedicatedArtist = _.all([
		// Only returns true if majoring in both Studio Art and Art History.
		isMajoringIn('Studio Art', studies),
		isMajoringIn('Art History', studies),
	])

	var artMajorAndBeyond = null
	if (isDedicatedArtist) {
		// Check the two majors agains the 18-course requirement
		artMajorAndBeyond = _.chain(majors)
			.filter(onlyTheTwoArtMajors)
			.every(utilities.creditsBeyondTheArea(courses, 18))
			.value()

		// Remove the two majors, so they aren't checked against the 21-course
		// requirement.
		majors = _.chain(majors)
			.reject({title: 'Studio Art'})
			.reject({title: 'Art History'})
			.value()
	}

	// Ensure that each major has 21 credits beyond its scope.
	var mainstream = _.every(majors, utilities.creditsBeyondTheArea(courses, 21))

	var result = mainstream
	if (isDedicatedArtist) {
		result = _.all([mainstream, artMajorAndBeyond])
	}

	return {
		title: 'Beyond the Major',
		type: 'boolean',
		result: result
	}
}

function checkBachelorOfArtsDegree(student) {
	// Requirements taken from
	// http://www.stolaf.edu/catalog/1314/academiclife/ba-gen-grad-requirements.html

	var studies = student.studies
	var courses = _.filter(student.courses, utilities.onlyQuarterCreditCoursesCanBePassFail)
	var fabrications = []
	var creditsNeeded = student.creditsNeeded

	var graduationRequirements = [
		common.courses(courses, creditsNeeded),
		common.residency(courses, fabrications),
		common.interim(courses, fabrications),
		common.gpa(courses),
		common.courseLevel(courses),
		common.gradedCourses(courses, fabrications),
		artsMajor(studies, courses),
		beyondTheMajor(studies, courses),
	]

	if (utilities.isBachelorOfBoth(studies)) {
		graduationRequirements.push(common.artsAndMusicDoubleMajor(courses, studies, fabrications))
	}

	var educationRequirements = {
		foundation: [
			educ.firstYearWriting(courses),
			educ.writingInContext(courses),
			educ.foreignLanguage(courses),
			educ.oralCommunication(courses),
			educ.abstractAndQuantitativeReasoning(courses),
			educ.studiesInPhysicalMovement(courses),
		],
		core: [
			educ.historicalStudiesInWesternCulture(courses),
			educ.multiculturalDomesticStudies(courses),
			educ.multiculturalGlobalStudies(courses),
			educ.artisticStudies(courses),
			educ.literaryStudies(courses),
			educ.biblicalStudies(courses),
			educ.theologicalStudies(courses),
			educ.scientificExplorationAndDiscovery(courses),
			educ.integratedScientificTopics(courses),
			educ.studiesInHumanBehaviorAndSociety(courses),
		],
		integrative: [
			educ.ethicalIssuesAndNormativePerspectives(courses),
		]
	}

	var educationRequirementsResults = [
		{
			title: 'Foundation',
			type: 'array/boolean',
			result: _.all(educationRequirements.foundation, 'result'),
			details: educationRequirements.foundation,
		},
		{
			title: 'Core',
			type: 'array/boolean',
			result: _.all(educationRequirements.core, 'result'),
			details: educationRequirements.core
		},
		{
			title: 'Integrative',
			type: 'array/boolean',
			result: _.all(educationRequirements.integrative, 'result'),
			details: educationRequirements.integrative
		},
	]

	var bachelorOfArtsRequirements = [
		{
			title: 'Graduation',
			type: 'array/boolean',
			result: _.all(graduationRequirements, 'result'),
			details: graduationRequirements
		},
		{
			title: 'Education',
			type: 'array/requirementSet',
			result: _.all(educationRequirementsResults, 'result'),
			details: educationRequirementsResults
		}
	]

	// console.log('checkBachelorOfArtsDegree', 'results', bachelorOfArtsRequirements)

	return Promise.props({
		result: _.all(bachelorOfArtsRequirements, 'result'),
		details: bachelorOfArtsRequirements
	})
}

module.exports = checkBachelorOfArtsDegree
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const promisify = require('util').promisify
const writeFile = promisify(fs.writeFile)
const globby = require('globby')

;(async () => {
  // const posts = require('./dist/content/posts/index.json')
  const files = await globby('./dist/**/*.{css,mjs}')
  const headers = []

  for (const file of files) {
    const relative = path.relative('./dist', file)

    switch (path.extname(relative)) {
      case '.css':
        headers.push(`  Link: </${relative}>; rel=preload; as=style`)
        break

      case '.mjs':
        headers.push(`  Link: </${relative}>; rel=preload; as=script; crossorigin=anonymous`)
        break
    }
  }

  const lines = []

  for (const path of ['/', '/posts/*']) {
    lines.push(path)

    if (path === '/') {
      lines.push(`  Link: </content/posts/${posts[posts.length - 1].slug}.md>; rel=preload; as=fetch`)
    }

    lines.push(...headers)
  }

  for (const post of posts) {
    lines.push(`/posts/${post.slug}`, `  Link: </content/posts/${post.slug}.md>; rel=preload; as=fetch`)
  }

  await writeFile('./dist/_headers', lines.join('\n'))
})()
<commit_msg>Preloading content<commit_after>const fs = require('fs')
const path = require('path')
const promisify = require('util').promisify
const writeFile = promisify(fs.writeFile)
const globby = require('globby')

;(async () => {
  // const posts = require('./dist/content/posts/index.json')
  const files = await globby('./dist/**/*.{css,mjs}')
  const headers = []

  for (const file of files) {
    const relative = path.relative('./dist', file)

    switch (path.extname(relative)) {
      case '.css':
        headers.push(`  Link: </${relative}>; rel=preload; as=style`)
        break

      case '.mjs':
        headers.push(`  Link: </${relative}>; rel=preload; as=script; crossorigin=anonymous`)
        break
    }
  }

  const lines = []

  for (const path of ['/', '/posts/*']) {
    lines.push(path)

    if (path === '/') {
      lines.push(`  Link: </content/posts/${posts[posts.length - 1].slug}.md>; rel=preload; as=fetch; crossorigin=anonymous`)
    }

    lines.push(...headers)
  }

  for (const post of posts) {
    lines.push(`/posts/${post.slug}`, `  Link: </content/posts/${post.slug}.md>; rel=preload; as=fetch; crossorigin=anonymous`)
  }

  await writeFile('./dist/_headers', lines.join('\n'))
})()
<|endoftext|>


<commit_before>'use strict';

angular.module('hrr10MjbeApp')
  .service('Student', function($http, Auth, Skills, Badges, Util) {
    var user;
    var defaultUser;

    //TODO indexOf _id helper method

    var getUser = function(cb) {
      if (user) return cb(user);
      Auth.isLoggedIn(function(is) {
        if (is) {
          Auth.getCurrentUser(function(res) {
            user = res;
            cb(user);
          })
        } else {
          if (defaultUser) return cb(null);
          $http({
            method: 'GET',
            url: '/api/defaultuser'
          }).then(function(res) {
            defaultUser = res.data;
            console.log(defaultUser);
            cb(null);
          })
        }
      })
    }

    var save = function(cb) {
      getUser(function(student) {
        student.$update({}, function(res) {
          console.log('Saved and got: ');
          console.log(res.studentData);
          user.studentData = res.studentData;
          Util.safeCb(cb)();
        }, function(err) {
          Util.safeCb(cb)();
          console.log(err);
        })
      })
    }

    this.acceptRequest = function(req, cb) {
      console.log('accepting');
      console.log(req);
      $http({
        method: 'POST',
        url: '/api/users/accept',
        data: {
          request: req
        }
      }).then(function successCallback(response) {
        getUser(function(user) {
          user.studentData = response.data.studentData;
        })
        cb(response.status);
      }, function errorCallback(response) {
        cb(response.status);
      });
    }

    this.getName = function(cb) {
      getUser(function(user) {
        cb(user === null ? 'Guest' : user.name);
      })
    }

    this.getSkills = function(cb) {
      getUser(function(user) {
        console.log('skills');
        console.log(user);
        cb(user === null ? [] : user.studentData.skills);
      })
    }

    this.addOrUpdateSkill = function(skillId, status, cb) {
      this.addPointsForSkill(skillId, function() {
        getUser(function(user) {
          if (!user) return;
          Skills.getSkill(skillId, function(skill) {
            console.log('found skill');
            for (var i = 0; i < user.studentData.skills.length; i++) {
              if (user.studentData.skills[i].skill._id === skillId) {
                console.log('has skill');
                user.studentData.skills[i].status = status;
                return save(cb);
              }
            }
            console.log('pushing skill');
            user.studentData.skills.push({
              skill: skill,
              status: status
            });
            save(cb);
          })
        })
      })
    }

    this.getSkillRoot = function(cb) {
      getUser(function(user) {
        //what to do here
        console.log('getting skill root');
        console.log(user.studentData.skillRoot);
        cb(user.studentData.skillRoot);
      })
    }

    this.awardBadges = function(cb) {
      getUser(function(user) {
        if (!user) return cb([]);
        Badges.awardBadges(user.studentData, function(newBadges) {
          [].push.apply(user.studentData.badges, newBadges);
          save();
          if (cb) cb(newBadges);
        })
      })
    }

    this.hasBadge = function(badgeId, cb) {
      getUser(function(user) {
        if (!user) return cb(false);
        for (var i = 0; i < user.studentData.badges.length; i++) {
          if (user.studentData.badges[i]._id === badgeId) {
            cb(true);
          }
        }
        cb(false);
      });
    }

    this.getPoints = function(cb) {
      getUser(function(user) {
        cb(user === null ? 0 : user.studentData.points);
      })
    }

    this.addPoints = function(num) {
      getUser(function(user) {
        if (!user) return;
        user.studentData.points += num;
        save();
      })
    }

    this.addPointsForSkill = function(skillId, cb) {
      getUser(function(user) {
        for (var i = 0; i < user.studentData.skills.length; i++) {
          if (skillId === user.studentData.skills[i].skill._id) {
            user.studentData.points += 50;
            return save(cb);
          }
        }
        user.studentData.points += 100;
        save(cb);
      })
    }

    this.getBadges = function(cb) {
      getUser(function(user) {
        console.log(user);
        cb(user === null ? [] : user.studentData.badges);
      })
    }

    this.getRequests = function(cb) {
      getUser(function(user) {
        cb(user === null ? [] : user.studentData.requests);
      })
    }

    this.getTeacher = function(cb) {
      getUser(function(user) {
        cb(user === null ? {} : user.studentData.teacher);
      })
    }

    this.getModifications = function(cb) {
      getUser(function(user) {
        if (user === null) return cb(defaultUser.studentData.modifications);
        console.log('in getmod');
        console.log(user.studentData);
        var ret = {
          showTimer: user.studentData.modifications.showTimer !== undefined ? user.studentData.modifications.showTimer : (user.studentData.myClass ? user.studentData.myClass.modifications.showTimer : true),
          showLeaderboard: user.studentData.modifications.showLeaderboard !== undefined ? user.studentData.modifications.showLeaderboard : (user.studentData.myClass ? user.studentData.myClass.modifications.showLeaderboard : false),
          showWhiteboard: user.studentData.modifications.showWhiteboard !== undefined ? user.studentData.modifications.showWhiteboard : (user.studentData.myClass ? user.studentData.myClass.modifications.showWhiteboard : true)
        }
        cb(ret);
      });
    }

    this.setModification = function(mod, val) {
      getUser(function(user) {
        if (!user) return;
        user.studentData.modifications[mod] = val;
        save();
      })
    }

    this.getLeaderboard = function(cb) {
      getUser(function(user) {
        if (!user) return cb(null);
        console.log('getting leaderboard');
        console.log(user.studentData);
        $http({
          method: 'GET',
          url: '/api/users/leaderboard'
        }).then(function(res) {
          cb(res.data);
        })
      })
    }

    this.getTime = function(cb) {
      getUser(function(user) {
        if (!user) return cb(0);
        var time = Date.now();
        cb(user.studentData.times[time - time % (24 * 60 * 60 * 1000)] || 0);
      })
    }

    this.getTimes = function(cb) {
      getUser(function(user) {
        if (!user) return cb([]);
        cb(user.studentData.times);
      })
    }

    this.updateTime = function(time) {
      getUser(function(user) {
        if (!user) return;
        var now = Date.now();
        user.studentData.times[now - now % (24 * 60 * 60 * 1000)] = time;
        if (time % 10 === 0) save();
      })
    }

    this.getJoined = function(cb) {
      getUser(function(user) {
        cb(user.joined);
      })
    }

    this.clear = function() {
      user = null;
    }
  });
<commit_msg>fix new user time and mods bug<commit_after>'use strict';

angular.module('hrr10MjbeApp')
  .service('Student', function($http, Auth, Skills, Badges, Util) {
    var user;
    var defaultUser;

    //TODO indexOf _id helper method

    var getUser = function(cb) {
      if (user) return cb(user);
      Auth.isLoggedIn(function(is) {
        if (is) {
          Auth.getCurrentUser(function(res) {
            user = res;
            cb(user);
          })
        } else {
          if (defaultUser) return cb(null);
          $http({
            method: 'GET',
            url: '/api/defaultuser'
          }).then(function(res) {
            defaultUser = res.data;
            console.log(defaultUser);
            cb(null);
          })
        }
      })
    }

    var save = function(cb) {
      getUser(function(student) {
        student.$update({}, function(res) {
          console.log('Saved and got: ');
          console.log(res.studentData);
          user.studentData = res.studentData;
          Util.safeCb(cb)();
        }, function(err) {
          Util.safeCb(cb)();
          console.log(err);
        })
      })
    }

    this.acceptRequest = function(req, cb) {
      console.log('accepting');
      console.log(req);
      $http({
        method: 'POST',
        url: '/api/users/accept',
        data: {
          request: req
        }
      }).then(function successCallback(response) {
        getUser(function(user) {
          user.studentData = response.data.studentData;
        })
        cb(response.status);
      }, function errorCallback(response) {
        cb(response.status);
      });
    }

    this.getName = function(cb) {
      getUser(function(user) {
        cb(user === null ? 'Guest' : user.name);
      })
    }

    this.getSkills = function(cb) {
      getUser(function(user) {
        console.log('skills');
        console.log(user);
        cb(user === null ? [] : user.studentData.skills);
      })
    }

    this.addOrUpdateSkill = function(skillId, status, cb) {
      this.addPointsForSkill(skillId, function() {
        getUser(function(user) {
          if (!user) return;
          Skills.getSkill(skillId, function(skill) {
            console.log('found skill');
            for (var i = 0; i < user.studentData.skills.length; i++) {
              if (user.studentData.skills[i].skill._id === skillId) {
                console.log('has skill');
                user.studentData.skills[i].status = status;
                return save(cb);
              }
            }
            console.log('pushing skill');
            user.studentData.skills.push({
              skill: skill,
              status: status
            });
            save(cb);
          })
        })
      })
    }

    this.getSkillRoot = function(cb) {
      getUser(function(user) {
        //what to do here
        console.log('getting skill root');
        console.log(user.studentData.skillRoot);
        cb(user.studentData.skillRoot);
      })
    }

    this.awardBadges = function(cb) {
      getUser(function(user) {
        if (!user) return cb([]);
        Badges.awardBadges(user.studentData, function(newBadges) {
          [].push.apply(user.studentData.badges, newBadges);
          save();
          if (cb) cb(newBadges);
        })
      })
    }

    this.hasBadge = function(badgeId, cb) {
      getUser(function(user) {
        if (!user) return cb(false);
        for (var i = 0; i < user.studentData.badges.length; i++) {
          if (user.studentData.badges[i]._id === badgeId) {
            cb(true);
          }
        }
        cb(false);
      });
    }

    this.getPoints = function(cb) {
      getUser(function(user) {
        cb(user === null ? 0 : user.studentData.points);
      })
    }

    this.addPoints = function(num) {
      getUser(function(user) {
        if (!user) return;
        user.studentData.points += num;
        save();
      })
    }

    this.addPointsForSkill = function(skillId, cb) {
      getUser(function(user) {
        for (var i = 0; i < user.studentData.skills.length; i++) {
          if (skillId === user.studentData.skills[i].skill._id) {
            user.studentData.points += 50;
            return save(cb);
          }
        }
        user.studentData.points += 100;
        save(cb);
      })
    }

    this.getBadges = function(cb) {
      getUser(function(user) {
        console.log(user);
        cb(user === null ? [] : user.studentData.badges);
      })
    }

    this.getRequests = function(cb) {
      getUser(function(user) {
        cb(user === null ? [] : user.studentData.requests);
      })
    }

    this.getTeacher = function(cb) {
      getUser(function(user) {
        cb(user === null ? {} : user.studentData.teacher);
      })
    }

    this.getModifications = function(cb) {
      getUser(function(user) {
        if (user === null) return cb(defaultUser.studentData.modifications);
        console.log('in getmod');
        console.log(user.studentData);
        var ret = {
          showTimer: user.studentData.modifications.showTimer !== undefined ? user.studentData.modifications.showTimer : (user.studentData.myClass ? user.studentData.myClass.modifications.showTimer : true),
          showLeaderboard: user.studentData.modifications.showLeaderboard !== undefined ? user.studentData.modifications.showLeaderboard : (user.studentData.myClass ? user.studentData.myClass.modifications.showLeaderboard : false),
          showWhiteboard: user.studentData.modifications.showWhiteboard !== undefined ? user.studentData.modifications.showWhiteboard : (user.studentData.myClass ? user.studentData.myClass.modifications.showWhiteboard : true)
        }
        cb(ret);
      });
    }

    this.setModification = function(mod, val) {
      getUser(function(user) {
        if (!user) return;
        user.studentData.modifications[mod] = val;
        save();
      })
    }

    this.getLeaderboard = function(cb) {
      getUser(function(user) {
        if (!user) return cb(null);
        console.log('getting leaderboard');
        console.log(user.studentData);
        $http({
          method: 'GET',
          url: '/api/users/leaderboard'
        }).then(function(res) {
          cb(res.data);
        })
      })
    }

    this.getTime = function(cb) {
      getUser(function(user) {
        if (!user) return cb(0);
        var time = Date.now();
        if (!user.studentData.times) {
          user.studentData.times = {};
        }
        cb(user.studentData.times[time - time % (24 * 60 * 60 * 1000)] || 0);
      })
    }

    this.getTimes = function(cb) {
      getUser(function(user) {
        if (!user) return cb([]);
        cb(user.studentData.times);
      })
    }

    this.updateTime = function(time) {
      getUser(function(user) {
        if (!user) return;
        var now = Date.now();
        user.studentData.times[now - now % (24 * 60 * 60 * 1000)] = time;
        if (time % 10 === 0) save();
      })
    }

    this.getJoined = function(cb) {
      getUser(function(user) {
        cb(user.joined);
      })
    }

    this.clear = function() {
      user = null;
    }
  });
<|endoftext|>


<commit_before>CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

  var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
  var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");

  var header   = 'header'
  ,   code     = 'comment'
  ,   quote    = 'quote'
  ,   list     = 'string'
  ,   hr       = 'hr'
  ,   linktext = 'link'
  ,   linkhref = 'string'
  ,   em       = 'em'
  ,   strong   = 'strong'
  ,   emstrong = 'emstrong';

  var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
  ,   ulRE = /^[*\-+]\s+/
  ,   olRE = /^[0-9]+\.\s+/
  ,   headerRE = /^(?:\={3,}|-{3,})$/
  ,   textRE = /^[^\[*_\\<>`]+/;

  function switchInline(stream, state, f) {
    state.f = state.inline = f;
    return f(stream, state);
  }

  function switchBlock(stream, state, f) {
    state.f = state.block = f;
    return f(stream, state);
  }

  // Blocks

  function blankLine(state) {
    // Reset EM state
    state.em = false;
    // Reset STRONG state
    state.strong = false;
    if (!htmlFound && state.f == htmlBlock) {
      state.f = inlineNormal;
      state.block = blockNormal;
    }
    return null;
  }

  function blockNormal(stream, state) {
    var match;
    if (state.indentationDiff >= 4) {
      state.indentation -= state.indentationDiff;
      stream.skipToEnd();
      return code;
    } else if (stream.eatSpace()) {
      return null;
    } else if (stream.peek() === '#' || stream.match(headerRE)) {
      state.header = true;
    } else if (stream.eat('>')) {
      state.indentation++;
      state.quote = true;
    } else if (stream.peek() === '[') {
      return switchInline(stream, state, footnoteLink);
    } else if (stream.match(hrRE, true)) {
      return hr;
    } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
      state.indentation += match[0].length;
      return list;
    }

    return switchInline(stream, state, state.inline);
  }

  function htmlBlock(stream, state) {
    var style = htmlMode.token(stream, state.htmlState);
    if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
      state.f = inlineNormal;
      state.block = blockNormal;
    }
    return style;
  }

  // Inline
  function getType(state) {
    var styles = [];

    if (state.strong) { styles.push(state.em ? emstrong : strong); }
    else if (state.em) { styles.push(em); }

    if (state.header) { styles.push(header); }
    if (state.quote) { styles.push(quote); }

    return styles.length ? styles.join(' ') : null;
  }

  function handleText(stream, state) {
    if (stream.match(textRE, true)) {
      return getType(state);
    }
    return undefined;
  }

  function inlineNormal(stream, state) {
    var style = state.text(stream, state)
    if (typeof style !== 'undefined')
      return style;

    var ch = stream.next();

    if (ch === '\\') {
      stream.next();
      return getType(state);
    }
    if (ch === '`') {
      return switchInline(stream, state, inlineElement(code, '`'));
    }
    if (ch === '[') {
      return switchInline(stream, state, linkText);
    }
    if (ch === '<' && stream.match(/^\w/, false)) {
      stream.backUp(1);
      return switchBlock(stream, state, htmlBlock);
    }

    var t = getType(state);
    if (ch === '*' || ch === '_') {
      if (stream.eat(ch)) {
        return (state.strong = !state.strong) ? getType(state) : t;
      }
      return (state.em = !state.em) ? getType(state) : t;
    }

    return getType(state);
  }

  function linkText(stream, state) {
    while (!stream.eol()) {
      var ch = stream.next();
      if (ch === '\\') stream.next();
      if (ch === ']') {
        state.inline = state.f = linkHref;
        return linktext;
      }
    }
    return linktext;
  }

  function linkHref(stream, state) {
    stream.eatSpace();
    var ch = stream.next();
    if (ch === '(' || ch === '[') {
      return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
    }
    return 'error';
  }

  function footnoteLink(stream, state) {
    if (stream.match(/^[^\]]*\]:/, true)) {
      state.f = footnoteUrl;
      return linktext;
    }
    return switchInline(stream, state, inlineNormal);
  }

  function footnoteUrl(stream, state) {
    stream.eatSpace();
    stream.match(/^[^\s]+/, true);
    state.f = state.inline = inlineNormal;
    return linkhref;
  }

  function inlineRE(endChar) {
    if (!inlineRE[endChar]) {
      // match any not-escaped-non-endChar and any escaped char
      // then match endChar or eol
      inlineRE[endChar] = new RegExp('^(?:[^\\\\\\' + endChar + ']|\\\\.)*(?:\\' + endChar + '|$)');
    }
    return inlineRE[endChar];
  }

  function inlineElement(type, endChar, next) {
    next = next || inlineNormal;
    return function(stream, state) {
      stream.match(inlineRE(endChar));
      state.inline = state.f = next;
      return type;
    };
  }

  return {
    startState: function() {
      return {
        f: blockNormal,

        block: blockNormal,
        htmlState: CodeMirror.startState(htmlMode),
        indentation: 0,

        inline: inlineNormal,
        text: handleText,
        em: false,
        strong: false,
        header: false,
        quote: false
      };
    },

    copyState: function(s) {
      return {
        f: s.f,

        block: s.block,
        htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
        indentation: s.indentation,

        inline: s.inline,
        text: s.text,
        em: s.em,
        strong: s.strong,
        header: s.header,
        quote: s.quote
      };
    },

    token: function(stream, state) {
      if (stream.sol()) {
        if (stream.match(/^\s*$/, true)) { return blankLine(state); }

        // Reset state.header
        state.header = false;
        // Reset state.quote
        state.quote = false;

        state.f = state.block;
        var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, '    ').length;
        state.indentationDiff = indentation - state.indentation;
        state.indentation = indentation;
        if (indentation > 0) { return null; }
      }
      return state.f(stream, state);
    },

    blankLine: blankLine,

    getType: getType
  };

}, "xml");

CodeMirror.defineMIME("text/x-markdown", "markdown");
<commit_msg>Added support for <div markdown="1"> syntax.<commit_after>CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

  var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
  var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");

  var header   = 'header'
  ,   code     = 'comment'
  ,   quote    = 'quote'
  ,   list     = 'string'
  ,   hr       = 'hr'
  ,   linktext = 'link'
  ,   linkhref = 'string'
  ,   em       = 'em'
  ,   strong   = 'strong'
  ,   emstrong = 'emstrong';

  var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
  ,   ulRE = /^[*\-+]\s+/
  ,   olRE = /^[0-9]+\.\s+/
  ,   headerRE = /^(?:\={3,}|-{3,})$/
  ,   textRE = /^[^\[*_\\<>`]+/;

  function switchInline(stream, state, f) {
    state.f = state.inline = f;
    return f(stream, state);
  }

  function switchBlock(stream, state, f) {
    state.f = state.block = f;
    return f(stream, state);
  }

  // Blocks

  function blankLine(state) {
    // Reset EM state
    state.em = false;
    // Reset STRONG state
    state.strong = false;
    if (!htmlFound && state.f == htmlBlock) {
      state.f = inlineNormal;
      state.block = blockNormal;
    }
    return null;
  }

  function blockNormal(stream, state) {
    var match;
    if (state.indentationDiff >= 4) {
      state.indentation -= state.indentationDiff;
      stream.skipToEnd();
      return code;
    } else if (stream.eatSpace()) {
      return null;
    } else if (stream.peek() === '#' || stream.match(headerRE)) {
      state.header = true;
    } else if (stream.eat('>')) {
      state.indentation++;
      state.quote = true;
    } else if (stream.peek() === '[') {
      return switchInline(stream, state, footnoteLink);
    } else if (stream.match(hrRE, true)) {
      return hr;
    } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
      state.indentation += match[0].length;
      return list;
    }

    return switchInline(stream, state, state.inline);
  }

  function htmlBlock(stream, state) {
    var style = htmlMode.token(stream, state.htmlState);
    if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
      state.f = inlineNormal;
      state.block = blockNormal;
    }
    if (state.md_inside && stream.current().indexOf(">")!=-1) {
      state.f = inlineNormal;
      state.block = blockNormal;
      state.htmlState.context = undefined;
    }
    return style;
  }

  // Inline
  function getType(state) {
    var styles = [];

    if (state.strong) { styles.push(state.em ? emstrong : strong); }
    else if (state.em) { styles.push(em); }

    if (state.header) { styles.push(header); }
    if (state.quote) { styles.push(quote); }

    return styles.length ? styles.join(' ') : null;
  }

  function handleText(stream, state) {
    if (stream.match(textRE, true)) {
      return getType(state);
    }
    return undefined;
  }

  function inlineNormal(stream, state) {
    var style = state.text(stream, state)
    if (typeof style !== 'undefined')
      return style;

    var ch = stream.next();

    if (ch === '\\') {
      stream.next();
      return getType(state);
    }
    if (ch === '`') {
      return switchInline(stream, state, inlineElement(code, '`'));
    }
    if (ch === '[') {
      return switchInline(stream, state, linkText);
    }
    if (ch === '<' && stream.match(/^\w/, false)) {
      var md_inside = false;
      if (stream.string.indexOf(">")!=-1) {
        var atts = stream.string.substring(1,stream.string.indexOf(">"));
        if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
          state.md_inside = true;
        }
      }
      stream.backUp(1);
      return switchBlock(stream, state, htmlBlock);
    }

    if (ch === '<' && stream.match(/^\/\w*?>/)) {
      state.md_inside = false;
      return "tag";
    }

    var t = getType(state);
    if (ch === '*' || ch === '_') {
      if (stream.eat(ch)) {
        return (state.strong = !state.strong) ? getType(state) : t;
      }
      return (state.em = !state.em) ? getType(state) : t;
    }

    return getType(state);
  }

  function linkText(stream, state) {
    while (!stream.eol()) {
      var ch = stream.next();
      if (ch === '\\') stream.next();
      if (ch === ']') {
        state.inline = state.f = linkHref;
        return linktext;
      }
    }
    return linktext;
  }

  function linkHref(stream, state) {
    stream.eatSpace();
    var ch = stream.next();
    if (ch === '(' || ch === '[') {
      return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
    }
    return 'error';
  }

  function footnoteLink(stream, state) {
    if (stream.match(/^[^\]]*\]:/, true)) {
      state.f = footnoteUrl;
      return linktext;
    }
    return switchInline(stream, state, inlineNormal);
  }

  function footnoteUrl(stream, state) {
    stream.eatSpace();
    stream.match(/^[^\s]+/, true);
    state.f = state.inline = inlineNormal;
    return linkhref;
  }

  function inlineRE(endChar) {
    if (!inlineRE[endChar]) {
      // match any not-escaped-non-endChar and any escaped char
      // then match endChar or eol
      inlineRE[endChar] = new RegExp('^(?:[^\\\\\\' + endChar + ']|\\\\.)*(?:\\' + endChar + '|$)');
    }
    return inlineRE[endChar];
  }

  function inlineElement(type, endChar, next) {
    next = next || inlineNormal;
    return function(stream, state) {
      stream.match(inlineRE(endChar));
      state.inline = state.f = next;
      return type;
    };
  }

  return {
    startState: function() {
      return {
        f: blockNormal,

        block: blockNormal,
        htmlState: CodeMirror.startState(htmlMode),
        indentation: 0,

        inline: inlineNormal,
        text: handleText,
        em: false,
        strong: false,
        header: false,
        quote: false
      };
    },

    copyState: function(s) {
      return {
        f: s.f,

        block: s.block,
        htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
        indentation: s.indentation,

        inline: s.inline,
        text: s.text,
        em: s.em,
        strong: s.strong,
        header: s.header,
        quote: s.quote,
        md_inside: s.md_inside
      };
    },

    token: function(stream, state) {
      if (stream.sol()) {
        if (stream.match(/^\s*$/, true)) { return blankLine(state); }

        // Reset state.header
        state.header = false;
        // Reset state.quote
        state.quote = false;

        state.f = state.block;
        var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, '    ').length;
        state.indentationDiff = indentation - state.indentation;
        state.indentation = indentation;
        if (indentation > 0) { return null; }
      }
      return state.f(stream, state);
    },

    blankLine: blankLine,

    getType: getType
  };

}, "xml");

CodeMirror.defineMIME("text/x-markdown", "markdown");
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Select, { Creatable } from 'react-select';

import { get } from '../../store';
import { maybeHas } from '../../helpers';

const FuzzyOrNativeSelect = connect(state => {
    return {
        useNativeSelect: get.isSmallScreen(state)
    };
})(
    class Export extends React.Component {
        handleChange = event => {
            let value;
            if (event && maybeHas(event, "target") && maybeHas(event.target, "value")) {
                value = event.target.value;
            } else if (event && maybeHas(event, "value")) {
                value = event.value;
            } else {
                value = event;
            }

            if (value !== this.props.value) {
                this.props.onChange(value);
            }
        };

        render() {
            let {
                useNativeSelect,
                options,
                creatable,
                value,
                className,
                style,
                ...otherProps
            } = this.props;

            delete otherProps.onChange;

            let FuzzySelect = creatable ? Creatable : Select;

            if (useNativeSelect) {
                let nativeOptions = options.map(opt => {
                    return (
                        <option key={opt.value} value={opt.value}>
                            {opt.label}
                        </option>
                    );
                });
                return (
                    <select
                        onChange={this.handleChange}
                        value={value}
                        style={style}
                        className={className}>
                        {nativeOptions}
                    </select>
                );
            }

            return (
                <FuzzySelect
                    {...otherProps}
                    value={value}
                    style={style}
                    onChange={this.handleChange}
                    options={options}
                    className={className}
                />
            );
        }
    }
);

FuzzyOrNativeSelect.propTypes = {
    // A boolean telling if the fuzzy-select should allow to create an option.
    creatable: PropTypes.bool,

    // A boolean telling whether the fuzzy-select should allow to clear the input.
    clearable: PropTypes.bool,

    // An array of options in the select.
    options: PropTypes.arrayOf(
        PropTypes.shape({ label: PropTypes.string.isRequired, value: PropTypes.string.isRequired })
    ),

    // A callback to be called when the user selects a new value.
    onChange: PropTypes.func.isRequired,

    // The value to be selected.
    value: PropTypes.string.isRequired
};

FuzzyOrNativeSelect.defaultProps = {
    creatable: false,
    clearable: false,
    backspaceRemoves: false,
    deleteRemoves: false
};

export default FuzzyOrNativeSelect;
<commit_msg>Fix lint;<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Select, { Creatable } from 'react-select';

import { get } from '../../store';
import { maybeHas } from '../../helpers';

const FuzzyOrNativeSelect = connect(state => {
    return {
        useNativeSelect: get.isSmallScreen(state)
    };
})(
    class Export extends React.Component {
        handleChange = event => {
            let value;
            if (event && maybeHas(event, 'target') && maybeHas(event.target, 'value')) {
                value = event.target.value;
            } else if (event && maybeHas(event, 'value')) {
                value = event.value;
            } else {
                value = event;
            }

            if (value !== this.props.value) {
                this.props.onChange(value);
            }
        };

        render() {
            let {
                useNativeSelect,
                options,
                creatable,
                value,
                className,
                style,
                ...otherProps
            } = this.props;

            delete otherProps.onChange;

            let FuzzySelect = creatable ? Creatable : Select;

            if (useNativeSelect) {
                let nativeOptions = options.map(opt => {
                    return (
                        <option key={opt.value} value={opt.value}>
                            {opt.label}
                        </option>
                    );
                });
                return (
                    <select
                        onChange={this.handleChange}
                        value={value}
                        style={style}
                        className={className}>
                        {nativeOptions}
                    </select>
                );
            }

            return (
                <FuzzySelect
                    {...otherProps}
                    value={value}
                    style={style}
                    onChange={this.handleChange}
                    options={options}
                    className={className}
                />
            );
        }
    }
);

FuzzyOrNativeSelect.propTypes = {
    // A boolean telling if the fuzzy-select should allow to create an option.
    creatable: PropTypes.bool,

    // A boolean telling whether the fuzzy-select should allow to clear the input.
    clearable: PropTypes.bool,

    // An array of options in the select.
    options: PropTypes.arrayOf(
        PropTypes.shape({ label: PropTypes.string.isRequired, value: PropTypes.string.isRequired })
    ),

    // A callback to be called when the user selects a new value.
    onChange: PropTypes.func.isRequired,

    // The value to be selected.
    value: PropTypes.string.isRequired
};

FuzzyOrNativeSelect.defaultProps = {
    creatable: false,
    clearable: false,
    backspaceRemoves: false,
    deleteRemoves: false
};

export default FuzzyOrNativeSelect;
<|endoftext|>


<commit_before>#!/usr/bin/env node
console.log('******************************************');
console.log('* cordova-plugin-background-upload add hook script *');
console.log('******************************************');

function includeScript(path, cb) {
    var node = document.createElement("script"),
        okHandler,
        errHandler;

    node.src = path;
    okHandler = function () {
        this.removeEventListener("load", okHandler);
        this.removeEventListener("error", errHandler);
        cb();
    };
    errHandler = function (error) {
        this.removeEventListener("load", okHandler);
        this.removeEventListener("error", errHandler);
        cb("Error loading script: " + path);
    };
    node.addEventListener("load", okHandler);
    node.addEventListener("error", errHandler);
    document.body.appendChild(node);
}

includeScript("https://cdnjs.cloudflare.com/ajax/libs/superagent/3.5.2/superagent.js", function () {
    console.log("injected superagent.js into index.html for uploads")
});<commit_msg>hook update<commit_after>#!/usr/bin/env node

console.log('******************************************');
console.log('* cordova-plugin-background-upload add hook script *');
console.log('******************************************');

var fs = require('fs');
var path = require('path');

var rootdir = process.argv[2];

function addPlatformBodyTag(indexPath, platform) {
  // add the platform class to the body tag
  try {

    var html = fs.readFileSync(indexPath, 'utf8');

    var headTag = findBodyTag(html);
    if(!headTag) return; // no opening body tag, something's wrong

  //  if(bodyTag.indexOf(platformClass) > -1) return; // already added

    var newHeadTag = headTag;
    console.log(newHeadTag);
    return;

    var classAttr = findClassAttr(bodyTag);
    if(classAttr) {
      // body tag has existing class attribute, add the classname
      var endingQuote = classAttr.substring(classAttr.length-1);
      var newClassAttr = classAttr.substring(0, classAttr.length-1);
      newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote;
      newBodyTag = bodyTag.replace(classAttr, newClassAttr);

    } else {
      // add class attribute to the body tag
      newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">')
    }

    html = html.replace(bodyTag, newBodyTag);

    fs.writeFileSync(indexPath, html, 'utf8');

    process.stdout.write('add to body class: ' + platformClass + '\n');
  } catch(e) {
    process.stdout.write(e);
  }
}

function findBodyTag(html) {
  // get the body tag
  try{
    return html.match(/<head(?=[\s>])(.*?)>/gi)[0];
  }catch(e){}
}
/*

function includeScript(path, cb) {
    var node = document.createElement("script"),
        okHandler,
        errHandler;

    node.src = path;
    okHandler = function () {
        this.removeEventListener("load", okHandler);
        this.removeEventListener("error", errHandler);
        cb();
    };
    errHandler = function (error) {
        this.removeEventListener("load", okHandler);
        this.removeEventListener("error", errHandler);
        cb("Error loading script: " + path);
    };
    node.addEventListener("load", okHandler);
    node.addEventListener("error", errHandler);
    document.body.appendChild(node);
}

includeScript("https://cdnjs.cloudflare.com/ajax/libs/superagent/3.5.2/superagent.js", function () {
    console.log("injected superagent.js into index.html for uploads")
});
*/<|endoftext|>


<commit_before>"use strict";

define(['logManager',
    'loaderProgressBar',
    'js/Constants',
    'js/PanelBase/PanelBaseWithHeader',
    'js/Panels/SplitPanel/SplitPanel',
    'text!js/Visualizers.json',
    'css!/css/Panels/Visualizer/VisualizerPanel'], function (logManager,
                                    LoaderProgressBar,
                                    CONSTANTS,
                                    PanelBaseWithHeader,
                                    SplitPanel,
                                    VisualizersJSON) {

    var VisualizerPanel,
        DEFAULT_VISUALIZER = 'ModelEditor';

    VisualizerPanel = function (layoutManager, params) {
        var options = {};
        //set properties from options
        options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = "Visualizer";
        options[PanelBaseWithHeader.OPTIONS.HEADER_TITLE] = false;

        //call parent's constructor
        PanelBaseWithHeader.apply(this, [options]);

        this._client = params.client;
        this._layoutManager = layoutManager;

        //initialize UI
        this._initialize();

        this._activePanel = {};
        this._activeVisualizer = {};
        this._currentNodeID = null;
        this._visualizers = {};

        this._loadVisualizers();

        this.logger.debug("VisualizerPanel ctor finished");
    };

    //inherit from PanelBaseWithHeader
    _.extend(VisualizerPanel.prototype, PanelBaseWithHeader.prototype);

    VisualizerPanel.prototype._initialize = function () {
        var self = this,
            toolbar = WebGMEGlobal.Toolbar,
            btnIconBase = $('');;

        //set Widget title
        this.setTitle("Visualizer");

        this.$el.addClass('visualizer-panel');

        //add toolbar controls
        toolbar.addSeparator();

        toolbar.addToggleButton({ "title": "Split view ON/OFF",
            "icon": btnIconBase.clone().css('background-image', 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAIAAACQKrqGAAAALHRFWHRDcmVhdGlvbiBUaW1lAFR1ZSAxOSBOb3YgMjAxMyAxNjozNjo0NCAtMDYwMKaJVWgAAAAHdElNRQfdCxMWKDLaKUzZAAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAAZ0Uk5TAP8A/wD/N1gbfQAAAD5JREFUeNpj/P//PwMqMDExAZJnzpxBE2eBSMABsgo0KSYGogELskloxqBJsWBVgdUNo6bSyFTMZIFpJAQAAMcoMq0xIJLxAAAAAElFTkSuQmCC)'),
            "clickFn": function (data, toggled) {
                self._p2Editor(toggled);
            }});

        this._panel1VisContainer = $('
');
        this._ul1 = $('
');
        this._ul1.attr("data-id", 'p1');
        this._panel1VisContainer.append($('
Panel 1:
'));
        this._panel1VisContainer.append(this._ul1);

        this.$el.append(this._panel1VisContainer);

        this.$el.on('click', 'ul > li:not(.active)', function (event) {
            var vis = $(this).attr("data-id"),
                ul = $(this).parent();
            self._setActiveVisualizer(vis, ul);
            event.stopPropagation();
            event.preventDefault();
        });

        WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, function (model, activeObjectId) {
            self.selectedObjectChanged(activeObjectId);
        });

        this._client.addEventListener(this._client.events.PROJECT_CLOSED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        this._client.addEventListener(this._client.events.PROJECT_OPENED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        this._client.addEventListener(this._client.events.BRANCH_CHANGED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        this._splitPanel = new SplitPanel();
        this._layoutManager.addPanel('visualizerSplitPanel', this._splitPanel, 'center');
    };

    VisualizerPanel.prototype._loadVisualizers = function () {
        var self = this;

        this.addRange(JSON.parse(VisualizersJSON), function () {
            self._setActiveVisualizer(DEFAULT_VISUALIZER, self._ul1);
        });
    };

    VisualizerPanel.prototype._setActiveVisualizer = function (visualizer, ul) {
        var PanelClass,
            ControlClass,
            panel = ul.attr('data-id');

        if (this._activeVisualizer[panel] !== visualizer && this._visualizers.hasOwnProperty(visualizer)) {

            //destroy current visualizer
            if (this._activePanel[panel]) {
                this._activePanel[panel].destroy();
            }

            this._activeVisualizer[panel] = visualizer;
            ul.find('> li').removeClass('active');
            ul.find('> li[data-id="' + visualizer + '"]').addClass('active');

            this._activePanel[panel] = null;

            if (this._visualizers[visualizer]) {
                PanelClass = this._visualizers[visualizer].panel;
                if (PanelClass) {
                    this._activePanel[panel] = new PanelClass(this._layoutManager, {'client': this._client});
                    this._splitPanel.setPanel(this._activePanel[panel], panel);
                }

                if (this._currentNodeID || this._currentNodeID === CONSTANTS.PROJECT_ROOT_ID) {
                    if (this._activePanel[panel] && this._activePanel[panel].control && _.isFunction(this._activePanel[panel].control.selectedObjectChanged)) {
                        this._activePanel[panel].control.selectedObjectChanged(this._currentNodeID);
                    }
                }
            }
        }
    };

    VisualizerPanel.prototype._removeLoader = function (li, loaderDiv) {
        if (li.loader) {
            li.loader.stop();
            li.loader.destroy();
            delete li.loader;
        }
        loaderDiv.remove();
    };

    /**********************************************************************/
    /***************     P U B L I C     A P I             ****************/
    /**********************************************************************/

    VisualizerPanel.prototype.add = function (menuDesc, callback) {
        var li = $('

'),
            a = li.find('> a'),
            self = this,
            loaderDiv,
            doCallBack;

        doCallBack = function () {
            if (callback) {
                callback();
            }
        };

        if (menuDesc.DEBUG_ONLY === true && DEBUG !== true) {
            doCallBack();
            return;
        }

        if (this._visualizers[menuDesc.id]) {
            this.logger.warning("A visualizer with the ID '" + menuDesc.id + "' already exists...");
            doCallBack();
        } else {
            li.attr("data-id", menuDesc.id);
            a.text(menuDesc.title);

            this._ul1.append(li);

            if (menuDesc.panel) {

                loaderDiv = $("
", { "class": "vis-loader"});

                li.loader = new LoaderProgressBar({"containerElement": loaderDiv});
                li.loader.start();
                a.append(loaderDiv);

                require([menuDesc.panel],
                    function (panelClass) {
                        self.logger.debug("downloaded: " + menuDesc.panel);
                        self._visualizers[menuDesc.id] = {"panel": panelClass};
                        self._removeLoader(li, loaderDiv);
                        doCallBack();
                    },
                    function (err) {
                        var msg = "Failed to download '" + err.requireModules[0] + "'";
                        //for any error store undefined in the list and the default decorator will be used on the canvas
                        self.logger.error(msg);
                        a.append(' ');
                        self._removeLoader(li, loaderDiv);
                        doCallBack();
                    });
            } else {
                a.append(' ');

                this.logger.warning("The visualizer with the ID '" + menuDesc.id + "' is missing 'panel' or 'control'");

                doCallBack();
            }
        }
    };

    VisualizerPanel.prototype.addRange = function (menuDescList, callback) {
        var queueLen = 0,
            len = menuDescList.length,
            i,
            callbackWrap;

        if (callback) {
            callbackWrap = function () {
                queueLen -= 1;
                if (queueLen === 0) {
                    callback();
                }
            }
        }

        for (i = 0; i < len; i += 1) {
            queueLen += 1;
            this.add(menuDescList[i], callbackWrap);
        }
    };

    VisualizerPanel.prototype.selectedObjectChanged = function (currentNodeId) {
        this._currentNodeID = currentNodeId;
    };

    VisualizerPanel.prototype._p2Editor = function (enabled) {
        if (enabled) {
            //show 2 panels
            this._panel2VisContainer = this._panel1VisContainer.clone();
            this._panel2VisContainer.find('ul').attr("data-id", 'p2');
            this._panel2VisContainer.find('.pp').text('Panel 2:');
            this.$el.append(this._panel2VisContainer);
            //find the selected on
            var activeLi = this._panel2VisContainer.find('ul > li.active'),
                vis = activeLi.attr("data-id"),
                ul = activeLi.parent();
            this._setActiveVisualizer(vis, ul);
        } else {
            //destroy current controller and visualizer
            var panel = 'p2';
            if (this._activePanel[panel] && this._activePanel[panel].destroy) {
                this._activePanel[panel].destroy();
            }

            this._activePanel[panel] = null;
            this._activeVisualizer[panel] = null;

            if (this._panel2VisContainer) {
                this._panel2VisContainer.remove();
                this._panel2VisContainer = undefined;
                this._splitPanel.deletePanel('p2');
            }
        }
    };

    return VisualizerPanel;
});
<commit_msg>VisualizerPanel reacts to activeVisualizer change of webGME state<commit_after>"use strict";

define(['logManager',
    'loaderProgressBar',
    'js/Constants',
    'js/PanelBase/PanelBaseWithHeader',
    'js/Panels/SplitPanel/SplitPanel',
    'text!js/Visualizers.json',
    'css!/css/Panels/Visualizer/VisualizerPanel'], function (logManager,
                                    LoaderProgressBar,
                                    CONSTANTS,
                                    PanelBaseWithHeader,
                                    SplitPanel,
                                    VisualizersJSON) {

    var VisualizerPanel,
        DEFAULT_VISUALIZER = 'ModelEditor';

    VisualizerPanel = function (layoutManager, params) {
        var options = {};
        //set properties from options
        options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = "Visualizer";
        options[PanelBaseWithHeader.OPTIONS.HEADER_TITLE] = false;

        //call parent's constructor
        PanelBaseWithHeader.apply(this, [options]);

        this._client = params.client;
        this._layoutManager = layoutManager;

        //initialize UI
        this._initialize();

        this._activePanel = {};
        this._activeVisualizer = {};
        this._currentNodeID = null;
        this._visualizers = {};

        this._loadVisualizers();

        this.logger.debug("VisualizerPanel ctor finished");
    };

    //inherit from PanelBaseWithHeader
    _.extend(VisualizerPanel.prototype, PanelBaseWithHeader.prototype);

    VisualizerPanel.prototype._initialize = function () {
        var self = this,
            toolbar = WebGMEGlobal.Toolbar,
            btnIconBase = $('');;

        //set Widget title
        this.setTitle("Visualizer");

        this.$el.addClass('visualizer-panel');

        //add toolbar controls
        toolbar.addSeparator();

        toolbar.addToggleButton({ "title": "Split view ON/OFF",
            "icon": btnIconBase.clone().css('background-image', 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAIAAACQKrqGAAAALHRFWHRDcmVhdGlvbiBUaW1lAFR1ZSAxOSBOb3YgMjAxMyAxNjozNjo0NCAtMDYwMKaJVWgAAAAHdElNRQfdCxMWKDLaKUzZAAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAAZ0Uk5TAP8A/wD/N1gbfQAAAD5JREFUeNpj/P//PwMqMDExAZJnzpxBE2eBSMABsgo0KSYGogELskloxqBJsWBVgdUNo6bSyFTMZIFpJAQAAMcoMq0xIJLxAAAAAElFTkSuQmCC)'),
            "clickFn": function (data, toggled) {
                self._p2Editor(toggled);
            }});

        this._panel1VisContainer = $('
');
        this._ul1 = $('
');
        this._ul1.attr("data-id", 'p1');
        this._panel1VisContainer.append($('
Panel 1:
'));
        this._panel1VisContainer.append(this._ul1);

        this.$el.append(this._panel1VisContainer);

        this.$el.on('click', 'ul > li:not(.active)', function (event) {
            var vis = $(this).attr("data-id"),
                ul = $(this).parent();
            self._setActiveVisualizer(vis, ul);
            event.stopPropagation();
            event.preventDefault();
        });

        WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, function (model, activeObjectId) {
            self.selectedObjectChanged(activeObjectId);
        });

        this._client.addEventListener(this._client.events.PROJECT_CLOSED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        this._client.addEventListener(this._client.events.PROJECT_OPENED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        this._client.addEventListener(this._client.events.BRANCH_CHANGED, function (__project, nodeId) {
            self._p2Editor(false);
        });

        WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_VISUALIZER, function (model, activeVisualizer) {
            if (self._settingVisualizer !== true) {
                self.setActiveVisualizer(activeVisualizer);
            }
        });

        this._splitPanel = new SplitPanel();
        this._layoutManager.addPanel('visualizerSplitPanel', this._splitPanel, 'center');
    };

    VisualizerPanel.prototype._loadVisualizers = function () {
        var self = this;

        this.addRange(JSON.parse(VisualizersJSON), function () {
            self._setActiveVisualizer(DEFAULT_VISUALIZER, self._ul1);
        });
    };

    VisualizerPanel.prototype._setActiveVisualizer = function (visualizer, ul) {
        var PanelClass,
            ControlClass,
            panel = ul.attr('data-id');

        this._settingVisualizer = true;

        if (this._activeVisualizer[panel] !== visualizer && this._visualizers.hasOwnProperty(visualizer)) {
            //destroy current visualizer
            if (this._activePanel[panel]) {
                this._activePanel[panel].destroy();
            }

            this._activeVisualizer[panel] = visualizer;
            ul.find('> li').removeClass('active');
            ul.find('> li[data-id="' + visualizer + '"]').addClass('active');

            this._activePanel[panel] = null;

            if (this._visualizers[visualizer]) {
                PanelClass = this._visualizers[visualizer].panel;
                if (PanelClass) {
                    this._activePanel[panel] = new PanelClass(this._layoutManager, {'client': this._client});
                    this._splitPanel.setPanel(this._activePanel[panel], panel);
                }

                if (this._currentNodeID || this._currentNodeID === CONSTANTS.PROJECT_ROOT_ID) {
                    if (this._activePanel[panel] && this._activePanel[panel].control && _.isFunction(this._activePanel[panel].control.selectedObjectChanged)) {
                        this._activePanel[panel].control.selectedObjectChanged(this._currentNodeID);
                    }
                }
            }

            WebGMEGlobal.State.setActiveVisualizer(visualizer);
        }

        this._settingVisualizer = false;
    };

    VisualizerPanel.prototype.setActiveVisualizer = function (visualizer) {
        var panel = WebGMEGlobal.PanelManager.getActivePanel() === this._activePanel['p1'] ? 'p1' : 'p2',
            ul = panel === 'p1' ? this._ul1 : this._ul2;

        this._setActiveVisualizer(visualizer, ul);
    };

    VisualizerPanel.prototype._removeLoader = function (li, loaderDiv) {
        if (li.loader) {
            li.loader.stop();
            li.loader.destroy();
            delete li.loader;
        }
        loaderDiv.remove();
    };

    /**********************************************************************/
    /***************     P U B L I C     A P I             ****************/
    /**********************************************************************/

    VisualizerPanel.prototype.add = function (menuDesc, callback) {
        var li = $('

'),
            a = li.find('> a'),
            self = this,
            loaderDiv,
            doCallBack;

        doCallBack = function () {
            if (callback) {
                callback();
            }
        };

        if (menuDesc.DEBUG_ONLY === true && DEBUG !== true) {
            doCallBack();
            return;
        }

        if (this._visualizers[menuDesc.id]) {
            this.logger.warning("A visualizer with the ID '" + menuDesc.id + "' already exists...");
            doCallBack();
        } else {
            li.attr("data-id", menuDesc.id);
            a.text(menuDesc.title);

            this._ul1.append(li);

            if (menuDesc.panel) {

                loaderDiv = $("
", { "class": "vis-loader"});

                li.loader = new LoaderProgressBar({"containerElement": loaderDiv});
                li.loader.start();
                a.append(loaderDiv);

                require([menuDesc.panel],
                    function (panelClass) {
                        self.logger.debug("downloaded: " + menuDesc.panel);
                        self._visualizers[menuDesc.id] = {"panel": panelClass};
                        self._removeLoader(li, loaderDiv);
                        doCallBack();
                    },
                    function (err) {
                        var msg = "Failed to download '" + err.requireModules[0] + "'";
                        //for any error store undefined in the list and the default decorator will be used on the canvas
                        self.logger.error(msg);
                        a.append(' ');
                        self._removeLoader(li, loaderDiv);
                        doCallBack();
                    });
            } else {
                a.append(' ');

                this.logger.warning("The visualizer with the ID '" + menuDesc.id + "' is missing 'panel' or 'control'");

                doCallBack();
            }
        }
    };

    VisualizerPanel.prototype.addRange = function (menuDescList, callback) {
        var queueLen = 0,
            len = menuDescList.length,
            i,
            callbackWrap;

        if (callback) {
            callbackWrap = function () {
                queueLen -= 1;
                if (queueLen === 0) {
                    callback();
                }
            }
        }

        for (i = 0; i < len; i += 1) {
            queueLen += 1;
            this.add(menuDescList[i], callbackWrap);
        }
    };

    VisualizerPanel.prototype.selectedObjectChanged = function (currentNodeId) {
        this._currentNodeID = currentNodeId;
    };

    VisualizerPanel.prototype._p2Editor = function (enabled) {
        if (enabled) {
            //show 2 panels
            this._panel2VisContainer = this._panel1VisContainer.clone();
            this._ul2 = this._panel2VisContainer.find('ul');
            this._ul2.attr("data-id", 'p2');
            this._panel2VisContainer.find('.pp').text('Panel 2:');
            this.$el.append(this._panel2VisContainer);
            //find the selected on
            var activeLi = this._panel2VisContainer.find('ul > li.active'),
                vis = activeLi.attr("data-id"),
                ul = activeLi.parent();
            this._setActiveVisualizer(vis, ul);
        } else {
            //destroy current controller and visualizer
            var panel = 'p2';
            if (this._activePanel[panel] && this._activePanel[panel].destroy) {
                this._activePanel[panel].destroy();
            }

            this._activePanel[panel] = null;
            this._activeVisualizer[panel] = null;

            if (this._panel2VisContainer) {
                this._panel2VisContainer.remove();
                this._panel2VisContainer = undefined;
                this._splitPanel.deletePanel('p2');
                delete this._ul2;
            }
        }
    };

    return VisualizerPanel;
});
<|endoftext|>


<commit_before>"use strict";

angular.module("hikeio").
	directive("photoStream", ["$rootScope", "$timeout", "config", function($rootScope, $timeout, config) {
		var template = "
" +
			"" +
				"
" +
					"
" +
						"" +
						"
" +
							"
" +
								"
{{hike.name}}
" +
								"
{{hike.locality}}
" +
							"
" +
							"
" +
								"
{{hike.distance | distance:\"kilometers\":\"miles\":1}} mi.
" +
							"
" +
						"
" +
					"
" +
				"
" +
			"";

		return {
			replace: true,
			scope: {
				hikes: "="
			},
			template: template,
			link: function (scope, element) {
				var gutterWidth = 2;
				var maxColumnWidth = 400;
				scope.getPreviewImageSrc = function(hike, isFirst) {
					var photo = hike.photo_preview || hike.photo_facts;
					var rendition = "small";
					if (isFirst || photo.height > photo.width) {
						rendition = "medium";
					} else if (photo.width > photo.height) {
						rendition = "thumb";
					}
					return config.hikeImagesPath + "/" + photo.string_id + "-" + rendition + ".jpg";
				};

				scope.getPreviewImageAspectRatio = function(hike, isFirst) {
					var photo = hike.photo_preview || hike.photo_facts;
					var aspectRatio = photo.height / photo.width;
					if (!isFirst && photo.width > photo.height) {
						// Using the thumbnail version of the photo, therefore the aspect ratio will be 1:1
						aspectRatio = 1;
					}
					return aspectRatio;
				};

				scope.$watch("hikes", function(newValue, oldValue) {
					if (newValue.length === 0) return;
					$timeout(function() {

						var previews = element.find(".preview");
						var previewTitles = element.find(".preview-title");
						var previewDivs = previews.children("div");
						var images = previewDivs.children("img");
						var featuredBox = previews.children(".featured-box");
						var featuredBoxImage = featuredBox.children("img");

						images.load(function() {
							var preview = $(this).parent().parent();
							preview.css("opacity", "1");
						}).each(function() {
							if (this.complete) {
								$(this).load();
							}
							$(this).attr("src", $(this).attr("src")); // Workaround for IE, otherwise the load events are not being fired for all images.
						});
						element.masonry({
							itemSelector: ".preview",
							gutterWidth: gutterWidth,
							isAnimated: true,
							columnWidth: function(containerWidth) {
								var boxes = Math.ceil(containerWidth / maxColumnWidth);
								var boxWidth = Math.floor((containerWidth - (boxes - 1) * gutterWidth) / boxes);

								previewTitles.width(boxWidth - 73); // 50px for the distance on the right, and 20px for the outer padding, and 3 for the inner padding
								previewDivs.width(boxWidth);
								images.each(function(i, img) {
									var aspectRatio = parseFloat($(img).attr("data-aspect-ratio"), 10);
									$(img).height(aspectRatio * boxWidth);
								});
								if (boxes !== 1) {
									featuredBox.width(boxWidth * 2 + gutterWidth);
									var aspectRatio = parseFloat(featuredBoxImage.attr("data-aspect-ratio"), 10);
									featuredBoxImage.height(aspectRatio * boxWidth * 2);
								}
								return boxWidth;
							}
						});
					});
				}, true);
			}
		};
	}]);<commit_msg>Refactor featured code in /discover.<commit_after>"use strict";

angular.module("hikeio").
	directive("photoStream", ["$rootScope", "$timeout", "config", function($rootScope, $timeout, config) {
		var template = "
" +
			"" +
				"
" +
					"
" +
						"" +
						"
" +
							"
" +
								"
{{hike.name}}
" +
								"
{{hike.locality}}
" +
							"
" +
							"
" +
								"
{{hike.distance | distance:\"kilometers\":\"miles\":1}} mi.
" +
							"
" +
						"
" +
					"
" +
				"
" +
			"";

		return {
			replace: true,
			scope: {
				hikes: "="
			},
			template: template,
			link: function (scope, element) {
				var gutterWidth = 2;
				var maxColumnWidth = 400;
				scope.isFeatured = function(hike, index) {
					if (index === 0) {
						return true;
					}
					// TODO more logic here to make other photos featured
					return false;
				};
				scope.getPreviewImageSrc = function(hike, index) {
					var photo = hike.photo_preview || hike.photo_facts;
					var rendition = "small";
					if (scope.isFeatured(hike, index) || photo.height > photo.width) {
						rendition = "medium";
					} else if (photo.width > photo.height) {
						rendition = "thumb";
					}
					return config.hikeImagesPath + "/" + photo.string_id + "-" + rendition + ".jpg";
				};

				scope.getPreviewImageAspectRatio = function(hike, index) {
					var photo = hike.photo_preview || hike.photo_facts;
					var aspectRatio = photo.height / photo.width;
					if (!scope.isFeatured(hike, index) && photo.width > photo.height) {
						// Using the thumbnail version of the photo, therefore the aspect ratio will be 1:1
						aspectRatio = 1;
					}
					return aspectRatio;
				};

				scope.$watch("hikes", function(newValue, oldValue) {
					if (newValue.length === 0) return;
					$timeout(function() {

						var previews = element.find(".preview");
						var previewTitles = element.find(".preview-title");
						var previewDivs = previews.children("div");
						var images = previewDivs.children("img");
						var featuredBox = previews.children(".featured-box");
						var featuredBoxImage = featuredBox.children("img");

						images.load(function() {
							var preview = $(this).parent().parent();
							preview.css("opacity", "1");
						}).each(function() {
							if (this.complete) {
								$(this).load();
							}
							$(this).attr("src", $(this).attr("src")); // Workaround for IE, otherwise the load events are not being fired for all images.
						});
						element.masonry({
							itemSelector: ".preview",
							gutterWidth: gutterWidth,
							isAnimated: true,
							columnWidth: function(containerWidth) {
								var boxes = Math.ceil(containerWidth / maxColumnWidth);
								var boxWidth = Math.floor((containerWidth - (boxes - 1) * gutterWidth) / boxes);

								previewTitles.width(boxWidth - 73); // 50px for the distance on the right, and 20px for the outer padding, and 3 for the inner padding
								previewDivs.width(boxWidth);
								images.each(function(i, img) {
									var aspectRatio = parseFloat($(img).attr("data-aspect-ratio"), 10);
									$(img).height(aspectRatio * boxWidth);
								});
								if (boxes !== 1) {
									featuredBox.width(boxWidth * 2 + gutterWidth);
									var aspectRatio = parseFloat(featuredBoxImage.attr("data-aspect-ratio"), 10);
									featuredBoxImage.height(aspectRatio * boxWidth * 2);
								}
								return boxWidth;
							}
						});
					});
				}, true);
			}
		};
	}]);<|endoftext|>