<commit_before>require("../js/theory/theory.js");
require("../js/progression/progression.js");
require("../js/mn-scale.js");
require("../js/mn-note.js");
require("../js/mn-utils.js");

require("./playback-engine.js")
require("./harmony-engine.js")

var extend = require("extend")
var peg = require("pegjs");
var fs = require('fs');

var EventEmitter = require('events').EventEmitter;
var util = require('util');

// -----------------------------------------------------------------------------

var Publisher = function()
{
}

util.inherits(Publisher, EventEmitter);

Publisher.prototype.report = function(info)
{
	this.emit('info', info);
}

// -----------------------------------------------------------------------------

var Application = function()
{
	console.log("loading grammar..");
	fs.readFile( __dirname + '/grammar.txt', function (err, data) {
	  if (err) {
	    throw err;
	  }
	  this.parser = peg.generate(data.toString());
		console.log("loaded.");
	});

	this.publisher_ = new Publisher();
}

// Init merely sets up the data and parameters

Application.prototype.init = function(options) {

	var parameters =
	{
		device: "",
		tempo: 120,
		resolution: 16,  // In sixteenth
		length: 0.5,      // percentage
		ticksPerBeat: 24,
	}

	extend(parameters, options);

	this.engine_ = new PlaybackEngine();
	this.engine_.init(parameters.device)

	this.harmony_ = new HarmonyEngine();
};

Application.prototype.start = function()
{
	var publisher = this.publisher_;
	this.engine_.run();
}

Application.prototype.updateSequence = function()
{
	if (this.progression_.length != 0)
	{
		// create chord progression
		var chordSequence = makeChordProgression(this.rootNote_, this.scale_, this.progression_);
		// apply desired inversion to the first chord
		chordSequence[0].notes = invertChord(chordSequence[0].notes,this.inversion_);
		// apply voicing
		rectify_progression(chordSequence, this.rectificationMethod_);
		console.log("should send chord seaquence")
		this.chordSequencer_.setContent(chordSequence);
	}
}

Application.prototype.currentSequenceString = function()
{
/*	var chordnameList = "Chord sequence: ";
	var chordSequence = this.chordSequencer_.getContent();
	chordSequence.forEach(function (chord)
	{
		chordnameList += chordname(chord.notes) + ",";
	})
	return chordnameList;*/
}

Application.prototype.parse = function(command)
{
	var result = parser.parse(command); // returns something like a function call: method, arg1, arg2, arg3
	console.log("executing: " + JSON.stringify(result));
	return this[result.method](result.arguments);
};

Application.prototype.exit = function(arguments)
{
	process.exit();
	return "Bye, dave";
}

Application.prototype.rebuild = function()
{
	var chordSequence = this.harmony_.rebuild();
	if (chordSequence)
	{
		this.engine_.setChordSequence(chordSequence);
	}
}

Application.prototype.setScale = function(arguments)
{
	var scale = arguments.scale;
	var rootNote = arguments.root;
	this.harmony_.setScale(scale, rootNote);

	this.rebuild();

	var scaleChords = makeChordProgression(rootNote+"4", scale, [1,2,3,4,5,6,7]);
	scaleChordsNameList = "";
	scaleChords.forEach(function (chord)
	{
		scaleChordsNameList += chordname(chord.notes) + ",";
	})

	return "Scale chords: " + scaleChordsNameList;
}

Application.prototype.setRectification = function(argument)
{
	this.harmony_.setRectification(parseInt(argument));
	this.rebuild();
	return "";
}

Application.prototype.setInversion = function(argument)
{
	this.harmony.setInversion(parseInt(argument));
	this.rebuild();
	return "";
}

Application.prototype.setProgression = function(arguments)
{
	var chords = [];
	 arguments.forEach(function(element) {
	 	chords.push(element)
	 });

	this.harmony_.setProgression(chords);
	this.rebuild();

	return this.currentSequenceString();
}

Application.prototype.analyseNotes = function(argument)
{
	var result = scalesFromNotes(argument);
	return "score: " + result.score_ + "\n" + result.scaleList_;
	return this.currentSequenceString();
}

Application.prototype.analyseChords = function(argument)
{
	var result = scalesFromChords(argument);
	return "score: " + result.score_ + "\n" + result.scaleList_;
	return this.currentSequenceString();
}

Application.prototype.setSignature = function(arguments)
{
	this.signature_.numerator = arguments.numerator;
	this.signature_.denominator =  arguments.denominator;
	return "";
}

Application.prototype.debug = function(arguments)
{
	console.log(this);
}
module.exports = new Application();
<commit_msg>restore writing chord sequence to terminal<commit_after>require("../js/theory/theory.js");
require("../js/progression/progression.js");
require("../js/mn-scale.js");
require("../js/mn-note.js");
require("../js/mn-utils.js");

require("./playback-engine.js")
require("./harmony-engine.js")

var extend = require("extend")
var peg = require("pegjs");
var fs = require('fs');

var EventEmitter = require('events').EventEmitter;
var util = require('util');

// -----------------------------------------------------------------------------

var Publisher = function()
{
}

util.inherits(Publisher, EventEmitter);

Publisher.prototype.report = function(info)
{
	this.emit('info', info);
}

// -----------------------------------------------------------------------------

var Application = function()
{
	console.log("loading grammar..");
	fs.readFile( __dirname + '/grammar.txt', function (err, data) {
	  if (err) {
	    throw err;
	  }
	  this.parser = peg.generate(data.toString());
		console.log("loaded.");
	});

	this.publisher_ = new Publisher();
	this.currentSequence_ = null;
}

// Init merely sets up the data and parameters

Application.prototype.init = function(options) {

	var parameters =
	{
		device: "",
		tempo: 120,
		resolution: 16,  // In sixteenth
		length: 0.5,      // percentage
		ticksPerBeat: 24,
	}

	extend(parameters, options);

	this.engine_ = new PlaybackEngine();
	this.engine_.init(parameters.device)

	this.harmony_ = new HarmonyEngine();
};

Application.prototype.start = function()
{
	var publisher = this.publisher_;
	this.engine_.run();
}

Application.prototype.updateSequence = function()
{
	if (this.progression_.length != 0)
	{
		// create chord progression
		var chordSequence = makeChordProgression(this.rootNote_, this.scale_, this.progression_);
		// apply desired inversion to the first chord
		chordSequence[0].notes = invertChord(chordSequence[0].notes,this.inversion_);
		// apply voicing
		rectify_progression(chordSequence, this.rectificationMethod_);
		console.log("should send chord seaquence")
		this.chordSequencer_.setContent(chordSequence);
	}
}

Application.prototype.currentSequenceString = function()
{
	var chordnameList = "Chord sequence: ";
	var chordSequence = this.chordSequence_;
	chordSequence.forEach(function (chord)
	{
		chordnameList += chordname(chord.notes) + ",";
	})
	return chordnameList;
}

Application.prototype.parse = function(command)
{
	var result = parser.parse(command); // returns something like a function call: method, arg1, arg2, arg3
	console.log("executing: " + JSON.stringify(result));
	return this[result.method](result.arguments);
};

Application.prototype.exit = function(arguments)
{
	process.exit();
	return "Bye, dave";
}

Application.prototype.rebuild = function()
{
	var chordSequence = this.harmony_.rebuild();
	if (chordSequence)
	{
		this.engine_.setChordSequence(chordSequence);
	}
	this.chordSequence_ = chordSequence;
}

Application.prototype.setScale = function(arguments)
{
	var scale = arguments.scale;
	var rootNote = arguments.root;
	this.harmony_.setScale(scale, rootNote);

	this.rebuild();

	var scaleChords = makeChordProgression(rootNote+"4", scale, [1,2,3,4,5,6,7]);
	scaleChordsNameList = "";
	scaleChords.forEach(function (chord)
	{
		scaleChordsNameList += chordname(chord.notes) + ",";
	})

	return "Scale chords: " + scaleChordsNameList;
}

Application.prototype.setRectification = function(argument)
{
	this.harmony_.setRectification(parseInt(argument));
	this.rebuild();
	return "";
}

Application.prototype.setInversion = function(argument)
{
	this.harmony.setInversion(parseInt(argument));
	this.rebuild();
	return "";
}

Application.prototype.setProgression = function(arguments)
{
	var chords = [];
	 arguments.forEach(function(element) {
	 	chords.push(element)
	 });

	this.harmony_.setProgression(chords);
	this.rebuild();

	return this.currentSequenceString();
}

Application.prototype.analyseNotes = function(argument)
{
	var result = scalesFromNotes(argument);
	return "score: " + result.score_ + "\n" + result.scaleList_;
	return this.currentSequenceString();
}

Application.prototype.analyseChords = function(argument)
{
	var result = scalesFromChords(argument);
	return "score: " + result.score_ + "\n" + result.scaleList_;
	return this.currentSequenceString();
}

Application.prototype.setSignature = function(arguments)
{
	this.signature_.numerator = arguments.numerator;
	this.signature_.denominator =  arguments.denominator;
	return "";
}

Application.prototype.debug = function(arguments)
{
	console.log(this);
}
module.exports = new Application();
<|endoftext|>


<commit_before>var assert = require("assert");
var sinon = require('sinon');
var userFetch = require('../src/FBUserFetch');
var communicatorModule = require('../src/FaceBookGraphAPICommunicator');

describe('UserFetch', function() {

	var fetcher = new userFetch.FBUserFetch('dummy');

	describe('User Fetcher', function() {
		it('should set token correctly', function() {
			assert.equal(fetcher.token, "dummy");
		});

		it('should call fetch correctly', function() {
			var commStub = sinon.createStubInstance(
					communicatorModule.FaceBookGraphAPICommunicator);
			//pass this stub to UserFetch
		});

	});
});<commit_msg>Stubing Success<commit_after>var assert = require("assert");
var sinon = require('sinon');
var Q = require("Q");
var userFetch = require('../src/FBUserFetch');
var communicatorModule = require('../src/FaceBookGraphAPICommunicator');

describe('UserFetch', function() {

	var fetcher = new userFetch.FBUserFetch('dummy');

	describe('User Fetcher', function() {
		it('should set token correctly', function() {
			assert.equal(fetcher.token, "dummy");
		});

		it('should call fetch correctly on sucess', function() {
			var defer = Q.defer;
			sinon.stub(
					communicatorModule.FaceBookGraphAPICommunicator.prototype,
					"send").returns(defer.resolve);

			// pass this stub to UserFetch
			//call fetch method
			//verify it calls onSuccess and OnError
			defer.resolve;
		});

	});
});<|endoftext|>


<commit_before>/**
 * Copyright 2013-2019 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const constants = require('./generator-constants');

const ANGULAR_DIR = constants.ANGULAR_DIR;
const CLIENT_MAIN_SRC_DIR = constants.CLIENT_MAIN_SRC_DIR;
const CLIENT_TEST_SRC_DIR = constants.CLIENT_TEST_SRC_DIR;
const SERVER_MAIN_RES_DIR = constants.SERVER_MAIN_RES_DIR;

module.exports = {
    cleanupOldFiles,
    cleanupOldServerFiles,
    upgradeFiles
};

/**
 * Removes files that where generated in previous JHipster versions and therefore
 * need to be removed.
 *
 * WARNING this only removes files created by the main generator. Each sub-generator
 * should clean-up its own files: see the `cleanup` method in entity/index.js for cleaning
 * up entities.
 *
 * @param {any} generator - reference to generator
 */
function cleanupOldFiles(generator) {
    if (generator.isJhipsterVersionLessThan('3.2.0')) {
        // removeFile and removeFolder methods should be called here for files and folders to cleanup
        generator.removeFile(`${ANGULAR_DIR}components/form/uib-pager.config.js`);
        generator.removeFile(`${ANGULAR_DIR}components/form/uib-pagination.config.js`);
    }
    if (generator.isJhipsterVersionLessThan('5.0.0')) {
        generator.removeFile(`${ANGULAR_DIR}/app.route.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/account.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-jwt.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-session.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/csrf.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/state-storage.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/user-route-access-service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/language/language.constants.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/language/language.helper.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/login/login-modal.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/login/login.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/model/base-entity.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/model/request-util.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/account.model.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/user.model.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/user.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-management-dialog.component.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-modal.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-modal.service.ts`);

        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/shared/user/user.service.spec.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/admin/user-management/user-management-dialog.component.spec.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/entry.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}karma.conf.js`);
    }
    if (generator.isJhipsterVersionLessThan('5.8.0')) {
        generator.removeFile(`${ANGULAR_DIR}admin/metrics/metrics-modal.component.html`);
        generator.removeFile(`${ANGULAR_DIR}admin/metrics/metrics-modal.component.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/admin/metrics/metrics-modal.component.spec.ts`);
    }
    if (generator.isJhipsterVersionLessThan('6.3.0') && generator.configOptions && generator.configOptions.clientFramework === 'angularX') {
        generator.removeFile(`${ANGULAR_DIR}account/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}core/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}home/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}layouts/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/shared-common.module.ts`);
    }

    if (generator.isJhipsterVersionLessThan('6.3.0') && generator.configOptions && generator.configOptions.clientFramework === 'react') {
        generator.removeFile('tslint.json');
    }

    if (generator.isJhipsterVersionLessThan('6.4.0') && generator.configOptions && generator.configOptions.clientFramework === 'angularX') {
        generator.removeFile(`${ANGULAR_DIR}admin/admin.route.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/admin.module.ts`);
    }
}

/**
 * Removes server files that where generated in previous JHipster versions and therefore
 * need to be removed.
 *
 * @param {any} generator - reference to generator
 * @param {string} javaDir - Java directory
 * @param {string} testDir - Java tests directory
 * @param {string} mainResourceDir - Main resources directory
 * @param {string} testResourceDir - Test resources directory
 */
function cleanupOldServerFiles(generator, javaDir, testDir, mainResourceDir, testResourceDir) {
    if (generator.isJhipsterVersionLessThan('3.5.0')) {
        generator.removeFile(`${javaDir}domain/util/JSR310DateTimeSerializer.java`);
        generator.removeFile(`${javaDir}domain/util/JSR310LocalDateDeserializer.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.6.0')) {
        generator.removeFile(`${javaDir}config/HerokuDatabaseConfiguration.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.10.0')) {
        generator.removeFile(`${javaDir}config/CloudMongoDbConfiguration.java`);
        generator.removeFile(`${javaDir}security/CustomAccessDeniedHandler.java`);
        generator.removeFile(`${javaDir}web/filter/CsrfCookieGeneratorFilter.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.11.0')) {
        generator.removeFile(`${CLIENT_MAIN_SRC_DIR}app/layouts/navbar/active-link.directive.js`);
    }
    if (generator.isJhipsterVersionLessThan('3.12.0')) {
        generator.removeFile(`${javaDir}config/hazelcast/HazelcastCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/hazelcast/package-info.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.0.0')) {
        generator.removeFile(`${javaDir}async/ExceptionHandlingAsyncTaskExecutor.java`);
        generator.removeFile(`${javaDir}async/package-info.java`);
        generator.removeFile(`${javaDir}config/jHipsterProperties.java`);
        generator.removeFile(`${javaDir}config/LoadBalancedResourceDetails.java`);
        generator.removeFile(`${javaDir}config/ElasticSearchConfiguration.java`);
        generator.removeFile(`${javaDir}config/apidoc/package-info.java`);
        generator.removeFile(`${javaDir}config/apidoc/PageableParameterBuilderPlugin.java`);
        generator.removeFile(`${javaDir}config/apidoc/SwaggerConfiguration.java`);
        generator.removeFile(`${javaDir}config/jcache/SpringCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/jcache/SpringCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/liquibase/AsyncSpringLiquibase.java`);
        generator.removeFile(`${javaDir}config/liquibase/package-info.java`);
        generator.removeFile(`${javaDir}config/locale/AngularCookieLocaleResolver.java`);
        generator.removeFile(`${javaDir}config/locale/package-info.java`);
        generator.removeFile(`${javaDir}domain/util/FixedH2Dialect.java`);
        generator.removeFile(`${javaDir}domain/util/FixedPostgreSQL82Dialect`);
        generator.removeFile(`${javaDir}domain/util/JSR310DateConverters.java`);
        generator.removeFile(`${javaDir}domain/util/JSR310PersistenceConverters.java`);
        generator.removeFile(`${javaDir}security/AjaxAuthenticationFailureHandler.java`);
        generator.removeFile(`${javaDir}security/AjaxAuthenticationSuccessHandler.java`);
        generator.removeFile(`${javaDir}security/AjaxLogoutSuccessHandler.java`);
        generator.removeFile(`${javaDir}security/CustomPersistentRememberMeServices.java`);
        generator.removeFile(`${javaDir}security/Http401UnauthorizedEntryPoint.java`);
        generator.removeFile(`${javaDir}security/UserDetailsService.java`);
        generator.removeFile(`${javaDir}web/filter/CachingHttpHeadersFilter.java`);
        generator.removeFile(`${javaDir}web/filter/package-info.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.3.0')) {
        generator.removeFile(`${javaDir}gateway/ratelimiting/RateLimitingRepository.java`);
        generator.removeFile(`${javaDir}config/cassandra/CustomZonedDateTimeCodec.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.7.1')) {
        generator.removeFile(`${javaDir}web/rest/errors/ErrorVM.java`);
        generator.removeFile(`${javaDir}web/rest/errors/ParameterizedErrorVM.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.11.1')) {
        generator.removeFile(`${CLIENT_MAIN_SRC_DIR}app/app.main-aot.ts`);
    }
    if (generator.isJhipsterVersionLessThan('4.13.1')) {
        generator.config.delete('hibernateCache');
    }
    if (generator.isJhipsterVersionLessThan('5.0.0')) {
        generator.removeFile(`${javaDir}config/ThymeleafConfiguration.java`);
        generator.removeFile(`${javaDir}web/rest/ProfileInfoResource.java`);
        generator.removeFile(`${mainResourceDir}mails/activationEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/creationEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/passwordResetEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/socialRegistrationValidationEmail.html`);
        generator.removeFile(`${testResourceDir}mail/testEmail.html`);
        generator.removeFile(`${testDir}web/rest/ProfileInfoResourceIT.java`);
        generator.removeFile('gradle/mapstruct.gradle');
    }
    if (generator.isJhipsterVersionLessThan('5.2.2')) {
        generator.removeFile(`${javaDir}config/ElasticsearchConfiguration.java`);
        generator.removeFile('gradle/liquibase.gradle');

        if (generator.authenticationType === 'oauth2' && generator.applicationType === 'microservice') {
            generator.removeFolder(`${constants.DOCKER_DIR}realm-config`);
            generator.removeFile(`${constants.DOCKER_DIR}keycloak.yml`);
        }
    }
    if (generator.isJhipsterVersionLessThan('5.8.0')) {
        generator.removeFile(`${javaDir}config/MetricsConfiguration.java`);
        if (generator.databaseType === 'cassandra') {
            generator.removeFile(`${testResourceDir}cassandra-random-port.yml`);
        }
    }
    if (generator.isJhipsterVersionLessThan('6.0.0')) {
        generator.removeFile(`${javaDir}web/rest/errors/CustomParameterizedException.java`);
        generator.removeFile(`${javaDir}web/rest/errors/InternalServerErrorException.java`);
        generator.removeFile(`${javaDir}web/rest/util/PaginationUtil.java`);
        generator.removeFile(`${javaDir}web/rest/util/HeaderUtil.java`);
        generator.removeFile(`${testDir}web/rest/util/PaginationUtilUnitTest.java`);
        generator.removeFile(`${javaDir}web/rest/vm/LoggerVM.java`);
        generator.removeFile(`${javaDir}web/rest/LogsResource.java`);
        generator.removeFile(`${testDir}web/rest/LogsResourceIT.java`);
        generator.removeFile(`${javaDir}config/OAuth2Configuration.java`);
        generator.removeFile(`${javaDir}security/OAuth2AuthenticationSuccessHandler.java`);

        generator.removeFolder(`${CLIENT_MAIN_SRC_DIR}app/shared/layout/header/menus`);
        generator.removeFolder(`${CLIENT_TEST_SRC_DIR}spec/app/shared/layout/header/menus`);
    }
    if (generator.isJhipsterVersionLessThan('6.1.0')) {
        generator.config.delete('blueprint');
        generator.config.delete('blueprintVersion');
    }
    if (generator.isJhipsterVersionLessThan('6.5.2')) {
        generator.removeFile(`${testDir}service/mapper/UserMapperIT.java`);
        generator.removeFile(`${javaDir}service/${generator.upperFirstCamelCase(generator.baseName)}KafkaConsumer.java`);
        generator.removeFile(`${javaDir}service/${generator.upperFirstCamelCase(generator.baseName)}KafkaProducer.java`);
        generator.removeFile(`${testDir}web/rest/ClientForwardControllerIT.java`);
    }
}

/**
 * Upgrade files.
 *
 * @param {any} generator - reference to generator
 */
function upgradeFiles(generator) {
    let atLeastOneSuccess = false;
    if (generator.isJhipsterVersionLessThan('6.1.0')) {
        const langNameDiffer = function(lang) {
            const langProp = lang.replace(/-/g, '_');
            // Target file : change xx_yyyy_zz to xx_yyyy_ZZ to match java locales
            const langJavaProp = langProp.replace(/_[a-z]+$/g, lang => lang.toUpperCase());
            return langProp !== langJavaProp ? [langProp, langJavaProp] : undefined;
        };
        const languages = generator.config.get('languages');
        languages
            .map(langNameDiffer)
            .filter(props => props)
            .forEach(props => {
                const code = generator.renameFile(
                    `${SERVER_MAIN_RES_DIR}i18n/messages_${props[0]}.properties`,
                    `${SERVER_MAIN_RES_DIR}i18n/messages_${props[1]}.properties`
                );
                atLeastOneSuccess = atLeastOneSuccess || code;
            });
    }
    return atLeastOneSuccess;
}
<commit_msg>remove RandomUtil containing folder for jhipster upgrade<commit_after>/**
 * Copyright 2013-2019 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const constants = require('./generator-constants');

const ANGULAR_DIR = constants.ANGULAR_DIR;
const CLIENT_MAIN_SRC_DIR = constants.CLIENT_MAIN_SRC_DIR;
const CLIENT_TEST_SRC_DIR = constants.CLIENT_TEST_SRC_DIR;
const SERVER_MAIN_RES_DIR = constants.SERVER_MAIN_RES_DIR;

module.exports = {
    cleanupOldFiles,
    cleanupOldServerFiles,
    upgradeFiles
};

/**
 * Removes files that where generated in previous JHipster versions and therefore
 * need to be removed.
 *
 * WARNING this only removes files created by the main generator. Each sub-generator
 * should clean-up its own files: see the `cleanup` method in entity/index.js for cleaning
 * up entities.
 *
 * @param {any} generator - reference to generator
 */
function cleanupOldFiles(generator) {
    if (generator.isJhipsterVersionLessThan('3.2.0')) {
        // removeFile and removeFolder methods should be called here for files and folders to cleanup
        generator.removeFile(`${ANGULAR_DIR}components/form/uib-pager.config.js`);
        generator.removeFile(`${ANGULAR_DIR}components/form/uib-pagination.config.js`);
    }
    if (generator.isJhipsterVersionLessThan('5.0.0')) {
        generator.removeFile(`${ANGULAR_DIR}/app.route.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/account.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-jwt.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/auth-session.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/csrf.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/state-storage.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/auth/user-route-access-service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/language/language.constants.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/language/language.helper.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/login/login-modal.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/login/login.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/model/base-entity.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/model/request-util.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/account.model.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/user.model.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/user/user.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-management-dialog.component.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-modal.service.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/user-management/user-modal.service.ts`);

        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/shared/user/user.service.spec.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/admin/user-management/user-management-dialog.component.spec.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/entry.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}karma.conf.js`);
    }
    if (generator.isJhipsterVersionLessThan('5.8.0')) {
        generator.removeFile(`${ANGULAR_DIR}admin/metrics/metrics-modal.component.html`);
        generator.removeFile(`${ANGULAR_DIR}admin/metrics/metrics-modal.component.ts`);
        generator.removeFile(`${CLIENT_TEST_SRC_DIR}spec/app/admin/metrics/metrics-modal.component.spec.ts`);
    }
    if (generator.isJhipsterVersionLessThan('6.3.0') && generator.configOptions && generator.configOptions.clientFramework === 'angularX') {
        generator.removeFile(`${ANGULAR_DIR}account/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}core/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}home/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}layouts/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/index.ts`);
        generator.removeFile(`${ANGULAR_DIR}shared/shared-common.module.ts`);
    }

    if (generator.isJhipsterVersionLessThan('6.3.0') && generator.configOptions && generator.configOptions.clientFramework === 'react') {
        generator.removeFile('tslint.json');
    }

    if (generator.isJhipsterVersionLessThan('6.4.0') && generator.configOptions && generator.configOptions.clientFramework === 'angularX') {
        generator.removeFile(`${ANGULAR_DIR}admin/admin.route.ts`);
        generator.removeFile(`${ANGULAR_DIR}admin/admin.module.ts`);
    }
}

/**
 * Removes server files that where generated in previous JHipster versions and therefore
 * need to be removed.
 *
 * @param {any} generator - reference to generator
 * @param {string} javaDir - Java directory
 * @param {string} testDir - Java tests directory
 * @param {string} mainResourceDir - Main resources directory
 * @param {string} testResourceDir - Test resources directory
 */
function cleanupOldServerFiles(generator, javaDir, testDir, mainResourceDir, testResourceDir) {
    if (generator.isJhipsterVersionLessThan('3.5.0')) {
        generator.removeFile(`${javaDir}domain/util/JSR310DateTimeSerializer.java`);
        generator.removeFile(`${javaDir}domain/util/JSR310LocalDateDeserializer.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.6.0')) {
        generator.removeFile(`${javaDir}config/HerokuDatabaseConfiguration.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.10.0')) {
        generator.removeFile(`${javaDir}config/CloudMongoDbConfiguration.java`);
        generator.removeFile(`${javaDir}security/CustomAccessDeniedHandler.java`);
        generator.removeFile(`${javaDir}web/filter/CsrfCookieGeneratorFilter.java`);
    }
    if (generator.isJhipsterVersionLessThan('3.11.0')) {
        generator.removeFile(`${CLIENT_MAIN_SRC_DIR}app/layouts/navbar/active-link.directive.js`);
    }
    if (generator.isJhipsterVersionLessThan('3.12.0')) {
        generator.removeFile(`${javaDir}config/hazelcast/HazelcastCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/hazelcast/package-info.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.0.0')) {
        generator.removeFile(`${javaDir}async/ExceptionHandlingAsyncTaskExecutor.java`);
        generator.removeFile(`${javaDir}async/package-info.java`);
        generator.removeFile(`${javaDir}config/jHipsterProperties.java`);
        generator.removeFile(`${javaDir}config/LoadBalancedResourceDetails.java`);
        generator.removeFile(`${javaDir}config/ElasticSearchConfiguration.java`);
        generator.removeFile(`${javaDir}config/apidoc/package-info.java`);
        generator.removeFile(`${javaDir}config/apidoc/PageableParameterBuilderPlugin.java`);
        generator.removeFile(`${javaDir}config/apidoc/SwaggerConfiguration.java`);
        generator.removeFile(`${javaDir}config/jcache/SpringCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/jcache/SpringCacheRegionFactory.java`);
        generator.removeFile(`${javaDir}config/liquibase/AsyncSpringLiquibase.java`);
        generator.removeFile(`${javaDir}config/liquibase/package-info.java`);
        generator.removeFile(`${javaDir}config/locale/AngularCookieLocaleResolver.java`);
        generator.removeFile(`${javaDir}config/locale/package-info.java`);
        generator.removeFile(`${javaDir}domain/util/FixedH2Dialect.java`);
        generator.removeFile(`${javaDir}domain/util/FixedPostgreSQL82Dialect`);
        generator.removeFile(`${javaDir}domain/util/JSR310DateConverters.java`);
        generator.removeFile(`${javaDir}domain/util/JSR310PersistenceConverters.java`);
        generator.removeFile(`${javaDir}security/AjaxAuthenticationFailureHandler.java`);
        generator.removeFile(`${javaDir}security/AjaxAuthenticationSuccessHandler.java`);
        generator.removeFile(`${javaDir}security/AjaxLogoutSuccessHandler.java`);
        generator.removeFile(`${javaDir}security/CustomPersistentRememberMeServices.java`);
        generator.removeFile(`${javaDir}security/Http401UnauthorizedEntryPoint.java`);
        generator.removeFile(`${javaDir}security/UserDetailsService.java`);
        generator.removeFile(`${javaDir}web/filter/CachingHttpHeadersFilter.java`);
        generator.removeFile(`${javaDir}web/filter/package-info.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.3.0')) {
        generator.removeFile(`${javaDir}gateway/ratelimiting/RateLimitingRepository.java`);
        generator.removeFile(`${javaDir}config/cassandra/CustomZonedDateTimeCodec.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.7.1')) {
        generator.removeFile(`${javaDir}web/rest/errors/ErrorVM.java`);
        generator.removeFile(`${javaDir}web/rest/errors/ParameterizedErrorVM.java`);
    }
    if (generator.isJhipsterVersionLessThan('4.11.1')) {
        generator.removeFile(`${CLIENT_MAIN_SRC_DIR}app/app.main-aot.ts`);
    }
    if (generator.isJhipsterVersionLessThan('4.13.1')) {
        generator.config.delete('hibernateCache');
    }
    if (generator.isJhipsterVersionLessThan('5.0.0')) {
        generator.removeFile(`${javaDir}config/ThymeleafConfiguration.java`);
        generator.removeFile(`${javaDir}web/rest/ProfileInfoResource.java`);
        generator.removeFile(`${mainResourceDir}mails/activationEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/creationEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/passwordResetEmail.html`);
        generator.removeFile(`${mainResourceDir}mails/socialRegistrationValidationEmail.html`);
        generator.removeFile(`${testResourceDir}mail/testEmail.html`);
        generator.removeFile(`${testDir}web/rest/ProfileInfoResourceIT.java`);
        generator.removeFile('gradle/mapstruct.gradle');
    }
    if (generator.isJhipsterVersionLessThan('5.2.2')) {
        generator.removeFile(`${javaDir}config/ElasticsearchConfiguration.java`);
        generator.removeFile('gradle/liquibase.gradle');

        if (generator.authenticationType === 'oauth2' && generator.applicationType === 'microservice') {
            generator.removeFolder(`${constants.DOCKER_DIR}realm-config`);
            generator.removeFile(`${constants.DOCKER_DIR}keycloak.yml`);
        }
    }
    if (generator.isJhipsterVersionLessThan('5.8.0')) {
        generator.removeFile(`${javaDir}config/MetricsConfiguration.java`);
        if (generator.databaseType === 'cassandra') {
            generator.removeFile(`${testResourceDir}cassandra-random-port.yml`);
        }
    }
    if (generator.isJhipsterVersionLessThan('6.0.0')) {
        generator.removeFile(`${javaDir}web/rest/errors/CustomParameterizedException.java`);
        generator.removeFile(`${javaDir}web/rest/errors/InternalServerErrorException.java`);
        generator.removeFile(`${javaDir}web/rest/util/PaginationUtil.java`);
        generator.removeFile(`${javaDir}web/rest/util/HeaderUtil.java`);
        generator.removeFile(`${testDir}web/rest/util/PaginationUtilUnitTest.java`);
        generator.removeFile(`${javaDir}web/rest/vm/LoggerVM.java`);
        generator.removeFile(`${javaDir}web/rest/LogsResource.java`);
        generator.removeFile(`${testDir}web/rest/LogsResourceIT.java`);
        generator.removeFile(`${javaDir}config/OAuth2Configuration.java`);
        generator.removeFile(`${javaDir}security/OAuth2AuthenticationSuccessHandler.java`);

        generator.removeFolder(`${CLIENT_MAIN_SRC_DIR}app/shared/layout/header/menus`);
        generator.removeFolder(`${CLIENT_TEST_SRC_DIR}spec/app/shared/layout/header/menus`);
    }
    if (generator.isJhipsterVersionLessThan('6.1.0')) {
        generator.config.delete('blueprint');
        generator.config.delete('blueprintVersion');
    }
    if (generator.isJhipsterVersionLessThan('6.5.2')) {
        generator.removeFile(`${testDir}service/mapper/UserMapperIT.java`);
        generator.removeFile(`${javaDir}service/${generator.upperFirstCamelCase(generator.baseName)}KafkaConsumer.java`);
        generator.removeFile(`${javaDir}service/${generator.upperFirstCamelCase(generator.baseName)}KafkaProducer.java`);
        generator.removeFile(`${testDir}web/rest/ClientForwardControllerIT.java`);
        generator.removeFolder(`${javaDir}package/service/util`);
    }
}

/**
 * Upgrade files.
 *
 * @param {any} generator - reference to generator
 */
function upgradeFiles(generator) {
    let atLeastOneSuccess = false;
    if (generator.isJhipsterVersionLessThan('6.1.0')) {
        const langNameDiffer = function(lang) {
            const langProp = lang.replace(/-/g, '_');
            // Target file : change xx_yyyy_zz to xx_yyyy_ZZ to match java locales
            const langJavaProp = langProp.replace(/_[a-z]+$/g, lang => lang.toUpperCase());
            return langProp !== langJavaProp ? [langProp, langJavaProp] : undefined;
        };
        const languages = generator.config.get('languages');
        languages
            .map(langNameDiffer)
            .filter(props => props)
            .forEach(props => {
                const code = generator.renameFile(
                    `${SERVER_MAIN_RES_DIR}i18n/messages_${props[0]}.properties`,
                    `${SERVER_MAIN_RES_DIR}i18n/messages_${props[1]}.properties`
                );
                atLeastOneSuccess = atLeastOneSuccess || code;
            });
    }
    return atLeastOneSuccess;
}
<|endoftext|>


<commit_before>import style from '../functions/style'
import initialize from '../functions/initialize'

import { getNode, getNodes, logger } from '../../utils/core'
import { deepAssign, each, nextUniqueId } from '../../utils/generic'
import { isMobile } from '../../utils/browser'

export default function reveal (target, options, interval, sync) {

	/**
	 * The reveal method has an optional 2nd parameter,
	 * so here we just shuffle things around to accept
	 * the interval being passed as the 2nd argument.
	 */
	if (typeof options === 'number') {
		interval = parseInt(options)
		options = {}
	} else {
		interval = parseInt(interval)
		options = options || {}
	}

	const config = deepAssign({}, this.defaults, options)
	const containers = this.store.containers

	let container
	let targets
	try {
		container = getNode(config.container)
		if (!container) {
			throw new Error('Invalid container.')
		}
		targets = getNodes(target, container)
		if (!targets) {
			throw new Error('Nothing to animate.')
		}
	} catch (e) {
		return logger.call(this, 'Reveal failed.', e.message)
	}

	/**
	 * Verify our platform matches our platform configuration.
	 */
	if (!config.mobile && isMobile() || !config.desktop && !isMobile()) {
		return logger.call(this, 'Reveal aborted.', 'This platform has been disabled.')
	}

	/**
	 * Sequence intervals must be at least 16ms (60fps).
	 */
	let sequence
	if (interval) {
		if (interval >= 16) {
			const sequenceId = nextUniqueId()
			sequence = {
				elementIds: [],
				nose: { blocked: false, index: null, pointer: null },
				tail: { blocked: false, index: null, pointer: null },
				id: sequenceId,
				interval: Math.abs(interval),
			}
		} else {
			return logger.call(this, 'Reveal failed.', 'Sequence interval must be at least 16ms.')
		}
	}

	let containerId
	each(containers, storedContainer => {
		if (!containerId && storedContainer.node === container) {
			containerId = storedContainer.id
		}
	})

	if (isNaN(containerId)) {
		containerId = nextUniqueId()
	}

	try {
		const elements = targets.map(node => {
			const element = {}
			const existingId = node.getAttribute('data-sr-id')

			if (existingId) {
				deepAssign(element, this.store.elements[existingId])

				/**
				 * In order to prevent previously generated styles
				 * from throwing off the new styles, the style tag
				 * has to be reverted to it's pre-reveal state.
				 */
				element.node.setAttribute('style', element.styles.inline)

			} else {
				element.id = nextUniqueId()
				element.node = node
				element.seen = false
				element.revealed = false
				element.visible = false
			}

			element.config = config
			element.containerId = containerId
			element.styles = style(element)

			if (sequence) {
				element.sequence = {
					id: sequence.id,
					index: sequence.elementIds.length,
				}
				sequence.elementIds.push(element.id)
			}

			return element
		})

		/**
		* Modifying the DOM via setAttribute needs to be handled
		* separately from reading computed styles in the map above
		* for the browser to batch DOM changes (limiting reflows)
		*/
		each(elements, element => {
			this.store.elements[element.id] = element
			element.node.setAttribute('data-sr-id', element.id)
		})

	} catch (e) {
		return logger.call(this, 'Reveal failed.', e.message)
	}

	containers[containerId] = containers[containerId] || {
		id: containerId,
		node: container,
	}

	if (sequence) {
		this.store.sequences[sequence.id] = sequence
	}

	/**
	* If reveal wasn't invoked by sync, we want to
	* make sure to add this call to the history.
	*/
	if (!sync) {
		this.store.history.push({ target, options, interval })

		/**
		* Push initialization to the event queue, giving
		* multiple reveal calls time to be interpretted.
		*/
		if (this.initTimeout) {
			window.clearTimeout(this.initTimeout)
		}
		this.initTimeout = window.setTimeout(initialize.bind(this), 0)
	}
}
<commit_msg>move reveal config assignment into try block<commit_after>import style from '../functions/style'
import initialize from '../functions/initialize'

import { getNode, getNodes, logger } from '../../utils/core'
import { deepAssign, each, nextUniqueId } from '../../utils/generic'
import { isMobile } from '../../utils/browser'

export default function reveal (target, options, interval, sync) {

	/**
	 * The reveal method has an optional 2nd parameter,
	 * so here we just shuffle things around to accept
	 * the interval being passed as the 2nd argument.
	 */
	if (typeof options === 'number') {
		interval = parseInt(options)
		options = {}
	} else {
		interval = parseInt(interval)
		options = options || {}
	}

	const containers = this.store.containers

	let config
	let container
	let targets
	try {
		config = deepAssign({}, this.defaults, options)
		container = getNode(config.container)
		if (!container) {
			throw new Error('Invalid container.')
		}
		targets = getNodes(target, container)
		if (!targets) {
			throw new Error('Nothing to animate.')
		}
	} catch (e) {
		return logger.call(this, 'Reveal failed.', e.message)
	}

	/**
	 * Verify our platform matches our platform configuration.
	 */
	if (!config.mobile && isMobile() || !config.desktop && !isMobile()) {
		return logger.call(this, 'Reveal aborted.', 'This platform has been disabled.')
	}

	/**
	 * Sequence intervals must be at least 16ms (60fps).
	 */
	let sequence
	if (interval) {
		if (interval >= 16) {
			const sequenceId = nextUniqueId()
			sequence = {
				elementIds: [],
				nose: { blocked: false, index: null, pointer: null },
				tail: { blocked: false, index: null, pointer: null },
				id: sequenceId,
				interval: Math.abs(interval),
			}
		} else {
			return logger.call(this, 'Reveal failed.', 'Sequence interval must be at least 16ms.')
		}
	}

	let containerId
	each(containers, storedContainer => {
		if (!containerId && storedContainer.node === container) {
			containerId = storedContainer.id
		}
	})

	if (isNaN(containerId)) {
		containerId = nextUniqueId()
	}

	try {
		const elements = targets.map(node => {
			const element = {}
			const existingId = node.getAttribute('data-sr-id')

			if (existingId) {
				deepAssign(element, this.store.elements[existingId])

				/**
				 * In order to prevent previously generated styles
				 * from throwing off the new styles, the style tag
				 * has to be reverted to it's pre-reveal state.
				 */
				element.node.setAttribute('style', element.styles.inline)

			} else {
				element.id = nextUniqueId()
				element.node = node
				element.seen = false
				element.revealed = false
				element.visible = false
			}

			element.config = config
			element.containerId = containerId
			element.styles = style(element)

			if (sequence) {
				element.sequence = {
					id: sequence.id,
					index: sequence.elementIds.length,
				}
				sequence.elementIds.push(element.id)
			}

			return element
		})

		/**
		* Modifying the DOM via setAttribute needs to be handled
		* separately from reading computed styles in the map above
		* for the browser to batch DOM changes (limiting reflows)
		*/
		each(elements, element => {
			this.store.elements[element.id] = element
			element.node.setAttribute('data-sr-id', element.id)
		})

	} catch (e) {
		return logger.call(this, 'Reveal failed.', e.message)
	}

	containers[containerId] = containers[containerId] || {
		id: containerId,
		node: container,
	}

	if (sequence) {
		this.store.sequences[sequence.id] = sequence
	}

	/**
	* If reveal wasn't invoked by sync, we want to
	* make sure to add this call to the history.
	*/
	if (!sync) {
		this.store.history.push({ target, options, interval })

		/**
		* Push initialization to the event queue, giving
		* multiple reveal calls time to be interpretted.
		*/
		if (this.initTimeout) {
			window.clearTimeout(this.initTimeout)
		}
		this.initTimeout = window.setTimeout(initialize.bind(this), 0)
	}
}
<|endoftext|>


<commit_before>var FaeNavigation = {
  current_items: [],

  init: function() {
    this.select_current_nav_item();
    this.update_nav_classes();
    if($('.sticky-table-header').length) {
      this.sticky_table_header();
    }
  },

  select_current_nav_item: function() {
    var self = this;
    var current_base_url = window.location.pathname;
    var url_without_edit_new = current_base_url.replace(/\/new|\/edit/, '');
    $('#main_nav a').each(function(){
      var $this = $(this);
      var link = $this.attr('href');
      if (link === url_without_edit_new || link === current_base_url) {
        $this.addClass('current');
        self.current_items.push($this);
        return false;
      }
    });
  },

  update_nav_classes: function() {
    var self = this;
    $.each(self.current_items, function(index, $el){
      if ($el.hasClass('main_nav-link')) {
        self.update_first_level($el);
      } else if ($el.hasClass('main_nav-sub-link')) {
        self.update_second_level($el);
      } else if ($el.hasClass('main_nav-third-link')) {
        self.update_third_level($el);
      }
    });
  },

  update_first_level: function($el) {
    $el.closest('li').addClass('main_nav-active-single');
  },

  update_second_level: function($el) {
    $el
      .closest('li').addClass('main_nav-sub-active')
      .closest('.main_nav-accordion').removeClass('main_nav-accordion').addClass('main_nav-active');
  },

  update_third_level: function($el) {
    $el
      .closest('li').addClass('main_nav-third-active')
      .closest('.sub_nav-accordion').removeClass('sub_nav-accordion').addClass('main_nav-sub-active--no_highlight')
      .closest('.main_nav-accordion').removeClass('main_nav-accordion').addClass('main_nav-active');
  },

  // If you want to try this in CSS be my guest but it's done near impossible to make a sticky <thead>
  sticky_table_header: function() {
    var headerHeight = $('.main_content-header').outerHeight();
    var sticky_table_selector = '.sticky-table-header';
    var sticky_table_header_selector = '.sticky-table-header--hidden';

    // Cache offset and height values to spare expensive calculations on scroll
    var sizeFixedHeader = function($el, headerHeight) {
      var $this = $el;
      var tableOffset = $this.offset().top - headerHeight;
      var bottomOffset = $this.height() + tableOffset - $this.find('thead').height();
      var $fixedHeader = $this.next(sticky_table_header_selector);

      $fixedHeader.data({
        'table-offset' : tableOffset,
        'table-bottom' : bottomOffset
      });

      $fixedHeader.css({
        width: $this.width(),
        top: headerHeight
      });

      $.each($this.find('thead tr th'), function(ind,val){
        var original_width = $(val).width();
        $($fixedHeader.find('tr > th')[ind]).width(original_width);
      });
    };

    // Add sticky psuedo tables after our main table to hold the fixed header
    $(sticky_table_selector).each(function() {
      var $this = $(this);
      var $header = $this.find('thead').clone();
      var new_classes = $this.attr('class').replace(sticky_table_selector.substr(1), sticky_table_header_selector.substr(1));

      var $fixedHeader = $('<table />', {
        class: new_classes
      });

      $fixedHeader.append( $header );
      $this.after($fixedHeader);

      sizeFixedHeader($this, headerHeight);
    });

    // If the table header is in range, show it, otherwise hide it
    $(window).on('scroll', function() {
      var offset = $(this).scrollTop();

      $(sticky_table_header_selector).each(function() {
        var $this = $(this);
        var tableOffset = $this.data('table-offset');
        var tableBottom = $this.data('table-bottom');

        if (offset >= tableOffset && offset <= tableBottom) {
          $this.show();
        } else {
          $this.hide();
        }
      });
    });

    // Get all values squared away again if the viewport gets smaller
    $(window).on('resize', function() {

      var headerHeight = $('.main_content-header').outerHeight();
      $(sticky_table_selector).each(function() {
        sizeFixedHeader($(this), headerHeight);
      });

    });

  }
}<commit_msg>refs #47202 - remove comment on potential CSS implementation<commit_after>var FaeNavigation = {
  current_items: [],

  init: function() {
    this.select_current_nav_item();
    this.update_nav_classes();
    if($('.sticky-table-header').length) {
      this.sticky_table_header();
    }
  },

  select_current_nav_item: function() {
    var self = this;
    var current_base_url = window.location.pathname;
    var url_without_edit_new = current_base_url.replace(/\/new|\/edit/, '');
    $('#main_nav a').each(function(){
      var $this = $(this);
      var link = $this.attr('href');
      if (link === url_without_edit_new || link === current_base_url) {
        $this.addClass('current');
        self.current_items.push($this);
        return false;
      }
    });
  },

  update_nav_classes: function() {
    var self = this;
    $.each(self.current_items, function(index, $el){
      if ($el.hasClass('main_nav-link')) {
        self.update_first_level($el);
      } else if ($el.hasClass('main_nav-sub-link')) {
        self.update_second_level($el);
      } else if ($el.hasClass('main_nav-third-link')) {
        self.update_third_level($el);
      }
    });
  },

  update_first_level: function($el) {
    $el.closest('li').addClass('main_nav-active-single');
  },

  update_second_level: function($el) {
    $el
      .closest('li').addClass('main_nav-sub-active')
      .closest('.main_nav-accordion').removeClass('main_nav-accordion').addClass('main_nav-active');
  },

  update_third_level: function($el) {
    $el
      .closest('li').addClass('main_nav-third-active')
      .closest('.sub_nav-accordion').removeClass('sub_nav-accordion').addClass('main_nav-sub-active--no_highlight')
      .closest('.main_nav-accordion').removeClass('main_nav-accordion').addClass('main_nav-active');
  },

  // Fix a table header to the top of the view on scroll
  sticky_table_header: function() {
    var headerHeight = $('.main_content-header').outerHeight();
    var sticky_table_selector = '.sticky-table-header';
    var sticky_table_header_selector = '.sticky-table-header--hidden';

    // Cache offset and height values to spare expensive calculations on scroll
    var sizeFixedHeader = function($el, headerHeight) {
      var $this = $el;
      var tableOffset = $this.offset().top - headerHeight;
      var bottomOffset = $this.height() + tableOffset - $this.find('thead').height();
      var $fixedHeader = $this.next(sticky_table_header_selector);

      $fixedHeader.data({
        'table-offset' : tableOffset,
        'table-bottom' : bottomOffset
      });

      $fixedHeader.css({
        width: $this.width(),
        top: headerHeight
      });

      $.each($this.find('thead tr th'), function(ind,val){
        var original_width = $(val).width();
        $($fixedHeader.find('tr > th')[ind]).width(original_width);
      });
    };

    // Add sticky psuedo tables after our main table to hold the fixed header
    $(sticky_table_selector).each(function() {
      var $this = $(this);
      var $header = $this.find('thead').clone();
      var new_classes = $this.attr('class').replace(sticky_table_selector.substr(1), sticky_table_header_selector.substr(1));

      var $fixedHeader = $('<table />', {
        class: new_classes
      });

      $fixedHeader.append( $header );
      $this.after($fixedHeader);

      sizeFixedHeader($this, headerHeight);
    });

    // If the table header is in range, show it, otherwise hide it
    $(window).on('scroll', function() {
      var offset = $(this).scrollTop();

      $(sticky_table_header_selector).each(function() {
        var $this = $(this);
        var tableOffset = $this.data('table-offset');
        var tableBottom = $this.data('table-bottom');

        if (offset >= tableOffset && offset <= tableBottom) {
          $this.show();
        } else {
          $this.hide();
        }
      });
    });

    // Get all values squared away again if the viewport gets smaller
    $(window).on('resize', function() {

      var headerHeight = $('.main_content-header').outerHeight();
      $(sticky_table_selector).each(function() {
        sizeFixedHeader($(this), headerHeight);
      });

    });

  }
}<|endoftext|>


<commit_before>var isPlaying = false;
var playlistIndex = 0;
var fileData = null;

$(document).ready(function () {
	// get root browser contents
	browser_bootstrap();
	// hookup progress bar
	$('audio.player').on('timeupdate', function () {
		var currentTime = $('audio.player').get(0).currentTime;
		//var fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
		//var duration = fileData.duration;
		var duration = $('audio.player').get(0).duration;
		$('div.progress').stop(true, true).animate({ 'width': (currentTime + .25) / duration * 100 + '%' }, 250, 'linear');
		// update time display
		$('span.time').html(fileData.format + '     ' + stringifyTime(currentTime) + ' / ' + stringifyTime(duration));
	});
	$('div.progress_range').click(function (e) {
		//var fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
		//var duration = fileData.duration;
		var duration = $('audio.player').get(0).duration;
		if (duration > 0) {
			var selectedX = e.pageX - $(this).offset().left;
			var maxX = $(this).width();
			var targetTimeFraction = selectedX / maxX;
			var targetTime = duration * targetTimeFraction;
			$('audio.player').get(0).currentTime = targetTime;
		}
		return false;
	});
	// automatic track change at end of current song
	$('audio.player').on('ended', function () {
		audioNext();
	});
	// hookup audio player buttons
	$('img.previous').click(audioPrevious);
	$('img.play').click(audioPlay);
	$('img.pause').click(audioPause);
	$('img.stop').click(audioStop);
	$('img.next').click(audioNext);
	// keyboard shortcuts
	$(document).keypress(function (e) {
		var key = String.fromCharCode(e.charCode);
		if (key == 'z') {
			$('img.previous').click();
		} else if (key == 'x') {
			$('img.play').click();
		} else if (key == 'c') {
			$('img.pause').click();
		} else if (key == 'v') {
			$('img.stop').click();
		} else if (key == 'b') {
			$('img.next').click();
		}
	});
});

function stringifyTime(time) {
	var minutes = Math.floor(time / 60);
	var seconds = Math.floor(time % 60);
	if (seconds < 10) {
		seconds = '0' + seconds;
	}
	return minutes + ':' + seconds;
}

function browser_bootstrap() {
	$.get('/dir?path=', function (data, status) {
		if (status == 'success') {
			handleDirContents('div.browser', data);
		}
	});
}

function handleDirContents(parent, dirEntries) {
	var dirs = [];
	var files = [];
	for (var dirEntry of dirEntries) {
		if (dirEntry.type == 'dir') {
			dirs.push(dirEntry);
		} else if (dirEntry.type == 'file') {
			files.push(dirEntry);
		}
	}
	handleDirs(parent, dirs);
	handleFiles(files);
}

function handleDirs(parent, dirs) {
	$(parent).append('

');
	for (var dir of dirs) {
		$(parent + ' ul').append('
' + dir.name + '
');
		$(parent + ' ul li').last().data('dirUrl', dir.dirUrl);
		$(parent + ' ul li').last().click(function () {
			var element = this;
			if ($(element).children().length > 0) {
				$(element).children().remove();
			} else {
				var dirUrl = $(element).data('dirUrl');
				$.get(dirUrl, function (data, status) {
					if (status == 'success') {
						handleDirContents(OptimalSelect.select(element), data);
					}
				});
			}
			return false;
		});
	}
}

function handleFiles(files) {
	// reset playlistIndex
	playlistIndex = 0;

	$('table.playlist tr.data').remove();
	for (var file of files) {
		for (var track of file.tracks) {
			//console.log(JSON.stringify(file, null, 4));
			$('table.playlist').append('

');
			$('table.playlist tr.data').last().append('' + track.track + '	');
			$('table.playlist tr.data').last().append('' + track.title + '	');
			$('table.playlist tr.data').last().append('' + track.artist + '	');
			$('table.playlist tr.data').last().append('' + track.album + '	');
			$('table.playlist tr.data').last().append('' + stringifyTime(track.duration) + '	');
			$('table.playlist tr.data').last().data('file', track);
		}
	}
	$('table.playlist tr.data').dblclick(function () {
		// stop current song
		audioStop();
		// update playlistIndex
		playlistIndex = $(this).index() - 1;
		// play song
		audioPlay();
		return false;
	});
}

function audioStop() {
	$('audio.player').get(0).pause();
	$('audio.player').get(0).currentTime = 0;
	$('div.progress').stop(true, true);
	$('div.progress').width('0px');
	isPlaying = false;
}

function audioPlay() {
	audioStop();
	fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
	// highlight in playlist
	$('table.playlist tr.data').removeClass('selected');
	$('table.playlist tr.data').eq(playlistIndex).addClass('selected');
	$('table.playlist tr.data').eq(playlistIndex).scrollintoview();
	// change current song label
	$('span.currentSong').html('     ' + fileData.title);
	// load selected song
	$('audio.player').children().remove();
	$('audio.player').append('<source src="' + fileData.playUrl + '" type="audio/mpeg" />');
	$('audio.player').get(0).load();
	// start playback
	$('audio.player').get(0).play();
	isPlaying = true;
}

function audioPause() {
	if (isPlaying) {
		$('audio.player').get(0).pause();
		isPlaying = false;
	} else {
		$('audio.player').get(0).play();
		isPlaying = true;
	}
}

function audioPrevious() {
	audioStop();
	if ($('table.playlist tr.data').length == 0) {
		playlistIndex = 0;
		return;
	}
	playlistIndex--;
	if (playlistIndex < 0) {
		playlistIndex = $('table.playlist tr.data').length - 1;
	}
	audioPlay();
}

function audioNext() {
	audioStop();
	if ($('table.playlist tr.data').length == 0) {
		playlistIndex = 0;
		return;
	}
	playlistIndex++;
	if (playlistIndex > ($('table.playlist tr.data').length - 1)) {
		playlistIndex = 0;
	}
	audioPlay();
}
<commit_msg>fix NaN time<commit_after>var isPlaying = false;
var playlistIndex = 0;
var fileData = null;

$(document).ready(function () {
	// get root browser contents
	browser_bootstrap();
	// hookup progress bar
	$('audio.player').on('timeupdate', function () {
		var currentTime = $('audio.player').get(0).currentTime;
		//var fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
		//var duration = fileData.duration;
		var duration = $('audio.player').get(0).duration;
		$('div.progress').stop(true, true).animate({ 'width': (currentTime + .25) / duration * 100 + '%' }, 250, 'linear');
		// update time display
		$('span.time').html(fileData.format + '     ' + stringifyTime(currentTime) + ' / ' + stringifyTime(duration));
	});
	$('div.progress_range').click(function (e) {
		//var fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
		//var duration = fileData.duration;
		var duration = $('audio.player').get(0).duration;
		if (duration > 0) {
			var selectedX = e.pageX - $(this).offset().left;
			var maxX = $(this).width();
			var targetTimeFraction = selectedX / maxX;
			var targetTime = duration * targetTimeFraction;
			$('audio.player').get(0).currentTime = targetTime;
		}
		return false;
	});
	// automatic track change at end of current song
	$('audio.player').on('ended', function () {
		audioNext();
	});
	// hookup audio player buttons
	$('img.previous').click(audioPrevious);
	$('img.play').click(audioPlay);
	$('img.pause').click(audioPause);
	$('img.stop').click(audioStop);
	$('img.next').click(audioNext);
	// keyboard shortcuts
	$(document).keypress(function (e) {
		var key = String.fromCharCode(e.charCode);
		if (key == 'z') {
			$('img.previous').click();
		} else if (key == 'x') {
			$('img.play').click();
		} else if (key == 'c') {
			$('img.pause').click();
		} else if (key == 'v') {
			$('img.stop').click();
		} else if (key == 'b') {
			$('img.next').click();
		}
	});
});

function stringifyTime(time) {
	var minutes = Math.floor(time / 60);
	var seconds = Math.floor(time % 60);
	if (seconds < 10) {
		seconds = '0' + seconds;
	}

	if (isNaN(minutes) || isNaN(seconds)) {
		return '0:00';
	} else {
		return minutes + ':' + seconds;
	}
}

function browser_bootstrap() {
	$.get('/dir?path=', function (data, status) {
		if (status == 'success') {
			handleDirContents('div.browser', data);
		}
	});
}

function handleDirContents(parent, dirEntries) {
	var dirs = [];
	var files = [];
	for (var dirEntry of dirEntries) {
		if (dirEntry.type == 'dir') {
			dirs.push(dirEntry);
		} else if (dirEntry.type == 'file') {
			files.push(dirEntry);
		}
	}
	handleDirs(parent, dirs);
	handleFiles(files);
}

function handleDirs(parent, dirs) {
	$(parent).append('

');
	for (var dir of dirs) {
		$(parent + ' ul').append('
' + dir.name + '
');
		$(parent + ' ul li').last().data('dirUrl', dir.dirUrl);
		$(parent + ' ul li').last().click(function () {
			var element = this;
			if ($(element).children().length > 0) {
				$(element).children().remove();
			} else {
				var dirUrl = $(element).data('dirUrl');
				$.get(dirUrl, function (data, status) {
					if (status == 'success') {
						handleDirContents(OptimalSelect.select(element), data);
					}
				});
			}
			return false;
		});
	}
}

function handleFiles(files) {
	// reset playlistIndex
	playlistIndex = 0;

	$('table.playlist tr.data').remove();
	for (var file of files) {
		for (var track of file.tracks) {
			//console.log(JSON.stringify(file, null, 4));
			$('table.playlist').append('

');
			$('table.playlist tr.data').last().append('' + track.track + '	');
			$('table.playlist tr.data').last().append('' + track.title + '	');
			$('table.playlist tr.data').last().append('' + track.artist + '	');
			$('table.playlist tr.data').last().append('' + track.album + '	');
			$('table.playlist tr.data').last().append('' + stringifyTime(track.duration) + '	');
			$('table.playlist tr.data').last().data('file', track);
		}
	}
	$('table.playlist tr.data').dblclick(function () {
		// stop current song
		audioStop();
		// update playlistIndex
		playlistIndex = $(this).index() - 1;
		// play song
		audioPlay();
		return false;
	});
}

function audioStop() {
	$('audio.player').get(0).pause();
	$('audio.player').get(0).currentTime = 0;
	$('div.progress').stop(true, true);
	$('div.progress').width('0px');
	isPlaying = false;
}

function audioPlay() {
	audioStop();
	fileData = $('table.playlist tr.data').eq(playlistIndex).data('file');
	// highlight in playlist
	$('table.playlist tr.data').removeClass('selected');
	$('table.playlist tr.data').eq(playlistIndex).addClass('selected');
	$('table.playlist tr.data').eq(playlistIndex).scrollintoview();
	// change current song label
	$('span.currentSong').html('     ' + fileData.title);
	// load selected song
	$('audio.player').children().remove();
	$('audio.player').append('<source src="' + fileData.playUrl + '" type="audio/mpeg" />');
	$('audio.player').get(0).load();
	// start playback
	$('audio.player').get(0).play();
	isPlaying = true;
}

function audioPause() {
	if (isPlaying) {
		$('audio.player').get(0).pause();
		isPlaying = false;
	} else {
		$('audio.player').get(0).play();
		isPlaying = true;
	}
}

function audioPrevious() {
	audioStop();
	if ($('table.playlist tr.data').length == 0) {
		playlistIndex = 0;
		return;
	}
	playlistIndex--;
	if (playlistIndex < 0) {
		playlistIndex = $('table.playlist tr.data').length - 1;
	}
	audioPlay();
}

function audioNext() {
	audioStop();
	if ($('table.playlist tr.data').length == 0) {
		playlistIndex = 0;
		return;
	}
	playlistIndex++;
	if (playlistIndex > ($('table.playlist tr.data').length - 1)) {
		playlistIndex = 0;
	}
	audioPlay();
}
<|endoftext|>


<commit_before>'use strict'

const chai = require('chai')
const Programme = require('../Programme').Programme
const expect = chai.expect // we are using the "expect" style of Chai

describe('Programme', function () {
    it('should return programmeData that it was init with', function () {
        const programmeData = {
            frostProtectTemp: 1,
            setbackTemp: 15,
            comfortTemp: 25,
            heatingOn: false
        }
        const programme = new Programme(programmeData)

        const returnedProgramme = programme.getProgrammeData()

        expect(returnedProgramme).to.deep.equal(programmeData)
    })

    it('should return default setpoint', function () {
        const programme = new Programme({
            comfortTemp: 20
        })

        expect(programme.getComfortSetPoint()).to.equal(20)
    })

    it('should allow programme setpoint to change', function () {
        const programme = new Programme({
            comfortTemp: 20
        })

        programme.setComfortSetPoint(30)

        expect(programme.getComfortSetPoint()).to.equal(30)
    })

    it('should return comfort periods for Saturday', function (done) {
        const date = new Date('January 9, 2016 00:00:00') // a saturday

        const expected = [
            {
                startTime: '06:30',
                endTime: '10:30'
            },
            {
                startTime: '17:30',
                endTime: '23:30'
            }
        ]
        const programme = new Programme({
            schedule: {
                Monday: {},
                Tuesday: {},
                Wednesday: {},
                Thursday: {},
                Friday: {},
                Saturday: {
                    comfortPeriods: expected
                },
                Sunday: {}
            }
        })

        expect(programme.getComfortPeriodsForDate(date)).to.deep.have.same.members(expected)
        done()
    })
})
<commit_msg>Add test for obtaining comfort periods<commit_after>'use strict'

const chai = require('chai')
const Programme = require('../Programme').Programme
const expect = chai.expect // we are using the "expect" style of Chai

describe('Programme', function () {
    it('should return programmeData that it was init with', function () {
        const programmeData = {
            frostProtectTemp: 1,
            setbackTemp: 15,
            comfortTemp: 25,
            heatingOn: false
        }
        const programme = new Programme(programmeData)

        const returnedProgramme = programme.getProgrammeData()

        expect(returnedProgramme).to.deep.equal(programmeData)
    })

    it('should return default setpoint', function () {
        const programme = new Programme({
            comfortTemp: 20
        })

        expect(programme.getComfortSetPoint()).to.equal(20)
    })

    it('should allow programme setpoint to change', function () {
        const programme = new Programme({
            comfortTemp: 20
        })

        programme.setComfortSetPoint(30)

        expect(programme.getComfortSetPoint()).to.equal(30)
    })

    it('should return comfort periods for a date in the future', function (done) {
        const date = new Date()
        date.setTime(new Date().getTime() + 7 * 86400000)

        const day = new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(date)

        assertReturnsComfortPeriodsForDay(day, date)
        done()
    })

    function assertReturnsComfortPeriodsForDay (day, date) {
        const expected = [
            {
                startTime: '06:30',
                endTime: '10:30'
            },
            {
                startTime: '17:30',
                endTime: '23:30'
            }
        ]
        const programme = programmeWithComfortPeriodsForDay(day, expected)

        expect(programme.getComfortPeriodsForDate(date)).to.deep.have.same.members(expected)
    }

    function programmeWithComfortPeriodsForDay (day, comfortPeriodsForDay) {
        const programmeData = skeletonProgrammeData()
        programmeData.schedule[day].comfortPeriods = comfortPeriodsForDay
        return new Programme(programmeData)
    }

    function skeletonProgrammeData () {
        return {
            schedule: {
                Monday: {},
                Tuesday: {},
                Wednesday: {},
                Thursday: {},
                Friday: {},
                Saturday: {},
                Sunday: {}
            }
        }
    }

    describe('should return comfort periods for days of week', function () {
        const tests = [
            { day: 'Monday', date: new Date('December 7, 2020 00:00:00') },
            { day: 'Tuesday', date: new Date('July 3, 2018 00:00:00') },
            { day: 'Wednesday', date: new Date('August 15, 2018 00:00:00') },
            { day: 'Thursday', date: new Date('September 12, 2019 00:00:00') },
            { day: 'Friday', date: new Date('November 13, 2020 00:00:00') },
            { day: 'Saturday', date: new Date('December 12, 2020 00:00:00') },
            { day: 'Sunday', date: new Date('March 7, 2021 00:00:00') }
        ]

        tests.forEach(({ day, date }) => {
            it(`should return comfort periods for ${day}`, function (done) {
                const expected = [
                    {
                        startTime: '06:30',
                        endTime: '10:30'
                    },
                    {
                        startTime: '17:30',
                        endTime: '23:30'
                    }
                ]
                const programme = programmeWithComfortPeriodsForDay(day, expected)

                expect(programme.getComfortPeriodsForDate(date)).to.deep.have.same.members(expected)
                done()
            })
        })
    })
})
<|endoftext|>


<commit_before>$(function() {

    (function() {
        $('[data-confirm]').click(function(e) {
            var q = $(this).attr('data-confirm');
            var a = window.confirm(q);
            if (a === false) {
                e.preventDefault();
            }
        });
    })();

    $.nette.ext({
        load: function() {
            $('.flash, .form-error').find('.close').click(function() {
                $(this).parent().remove();
            });
        }
    });

    $.nette.init();

});
<commit_msg>Script to select all CKEDITOR targeted elements<commit_after>$(function() {

    (function() {
        $('[data-confirm]').click(function(e) {
            var q = $(this).attr('data-confirm');
            var a = window.confirm(q);
            if (a === false) {
                e.preventDefault();
            }
        });
    })();

    (function() {
        CKEDITOR.replaceAll('editor');
    })();

    $.nette.ext({
        load: function() {
            $('.flash, .form-error').find('.close').click(function() {
                $(this).parent().remove();
            });
        }
    });

    $.nette.init();

});
<|endoftext|>


<commit_before>var Project = Backbone.Model.extend({
  name: 'project',

  initialize: function(args) {

    this.maybeUnwrap(args);

    this.bind('change:last_changeset_id', this.updateChangesets);

    this.stories = new StoryCollection();
    this.stories.url = this.url() + '/stories';
    this.stories.project = this;

    this.users = new UserCollection();
    this.users.url = this.url() + '/users';
    this.users.project = this;

    this.iterations = [];
  },

  defaults: {
    default_velocity: 10
  },

  url: function() {
    return '/projects/' + this.id;
  },

  // The ids of the columns, in the order that they appear by story weight
  columnIds: ['#done', '#in_progress', '#backlog', '#chilly_bin'],

  // Return an array of the columns that appear after column, or an empty
  // array if the column is the last
  columnsAfter: function(column) {
    var index = _.indexOf(this.columnIds, column);
    if (index === -1) {
      // column was not found in the array
      throw column.toString() + ' is not a valid column';
    }
    return this.columnIds.slice(index + 1);
  },

  // Return an array of the columns that appear before column, or an empty
  // array if the column is the first
  columnsBefore: function(column) {
    var index = _.indexOf(this.columnIds, column);
    if (index === -1) {
      // column was not found in the array
      throw column.toString() + ' is not a valid column';
    }
    return this.columnIds.slice(0, index);
  },

  // This method is triggered when the last_changeset_id attribute is changed,
  // which indicates there are changed or new stories on the server which need
  // to be loaded.
  updateChangesets: function() {
    var from = this.previous('last_changeset_id');
    if (from === null) {
      from = 0;
    }
    var to = this.get('last_changeset_id');

    var model = this;
    var options = {
      type: 'GET',
      dataType: 'json',
      success: function(resp, status, xhr) {
        model.handleChangesets(resp);
      },
      data: {from: from, to: to},
      url: this.url() + '/changesets'
    };

    $.ajax(options);
  },

  // (Re)load each of the stories described in the provided changesets.
  handleChangesets: function(changesets) {
    var that = this;

    var story_ids = _.map(changesets, function(changeset) {
      return changeset.changeset.story_id;
    });
    story_ids = _.uniq(story_ids);

    _.each(story_ids, function(story_id) {
      // FIXME - Feature envy on stories collection
      var story = that.stories.get(story_id);
      if (story) {
        // This is an existing story on the collection, just reload it
        story.fetch();
      } else {
        // This is a new story, which is present on the server but we don't
        // have it locally yet.
        that.stories.add({id: story_id});
        story = that.stories.get(story_id);
        story.fetch();
      }
    });
  },

  milliseconds_in_a_day: 1000 * 60 * 60 * 24,

  // Return the correct iteration number for a given date.
  getIterationNumberForDate: function(compare_date) {
    //var start_date = new Date(this.get('start_date'));
    var start_date = this.startDate();
    var difference = Math.abs(compare_date.getTime() - start_date.getTime());
    var days_apart = Math.round(difference / this.milliseconds_in_a_day);
    return Math.floor((days_apart / (this.get('iteration_length') * 7)) + 1);
  },

  getDateForIterationNumber: function(iteration_number) {
    // The difference betweeen the start date in days.  Iteration length is
    // in weeks.
    var difference = (7 * this.get('iteration_length')) * (iteration_number - 1);
    var start_date = this.startDate();
    var iteration_date = new Date(start_date);

    iteration_date.setDate(start_date.getDate() + difference);
    return iteration_date;
  },

  currentIterationNumber: function() {
    return this.getIterationNumberForDate(new Date());
  },

  startDate: function() {

    var start_date;
    if (this.get('start_date')) {
      // Parse the date string into an array of [YYYY, MM, DD] to
      // ensure identical date behaviour across browsers.
      var dateArray = this.get('start_date').split('/');
      var year = parseInt(dateArray[0], 10);
      // Month is zero indexed
      var month = parseInt(dateArray[1], 10) - 1;
      var day = parseInt(dateArray[2], 10);

      start_date = new Date(year, month, day);
    } else {
      start_date = new Date();
    }

    // Is the specified project start date the same week day as the iteration
    // start day?
    if (start_date.getDay() === this.get('iteration_start_day')) {
      return start_date;
    } else {
      // Calculate the date of the nearest prior iteration start day to the
      // specified project start date.  So if the iteration start day is
      // set to Monday, but the project start date is set to a specific
      // Thursday, return the Monday before the Thursday.  A greater
      // mathemtician than I could probably do this with the modulo.
      var day_difference = start_date.getDay() - this.get('iteration_start_day');

      // The iteration start day is after the project start date, in terms of
      // day number
      if (day_difference < 0) {
        day_difference = day_difference + 7;
      }
      return new Date(start_date - day_difference * this.milliseconds_in_a_day);
    }
  },

  // Override the calculated velocity with a user defined value.  If this
  // value is different to the calculated velocity, the velocityIsFake
  // attribute will be set to true.
  velocity: function(userVelocity) {
    if(userVelocity !== undefined) {

      if(userVelocity < 1) {
        userVelocity = 1;
      }

      if(userVelocity === this.calculateVelocity()) {
        this.unset('userVelocity');
      } else {
        this.set({userVelocity: userVelocity});
      }
    }
    if(this.get('userVelocity')) {
      return this.get('userVelocity');
    } else {
      return this.calculateVelocity();
    }
  },

  velocityIsFake: function() {
    return (this.get('userVelocity') !== undefined);
  },

  calculateVelocity: function() {
    if (this.doneIterations().length === 0) {
      return this.get('default_velocity');
    } else {
      // TODO Make number of iterations configurable
      var numIterations = 3;
      var iterations = this.doneIterations();

      // Take a maximum of numIterations from the end of the array
      if (iterations.length > numIterations) {
        iterations = iterations.slice(iterations.length - numIterations);
      }

      var pointsArray = _.invoke(iterations, 'points');
      var sum = _.reduce(pointsArray, function(memo, points) {
        return memo + points;
      }, 0);
      var velocity = Math.floor(sum / pointsArray.length);
      return velocity < 1 ? 1 : velocity;
    }
  },

  revertVelocity: function() {
    this.unset('userVelocity');
  },

  doneIterations: function() {
    return _.select(this.iterations, function(iteration) {
      return iteration.get('column') === "#done";
    });
  },

  rebuildIterations: function() {

    //
    // Done column
    //
    var that = this;

    // Clear the project iterations
    this.iterations = [];

    var doneIterations = _.groupBy(this.stories.column('#done'),
                                    function(story) {
                                      return story.iterationNumber();
                                    });

    // groupBy() returns an object with keys of the iteration number
    // and values of the stories array.  Ensure the keys are sorted
    // in numeric order.
    var doneNumbers = _.keys(doneIterations).sort(function(left, right) {
      return (left - right);
    });

    _.each(doneNumbers, function(iterationNumber) {
      var stories = doneIterations[iterationNumber];
      var iteration = new Iteration({
        'number': iterationNumber, 'stories': stories, column: '#done'
      });

      that.appendIteration(iteration, '#done');

    });

    var currentIteration = new Iteration({
      'number': this.currentIterationNumber(),
      'stories': this.stories.column('#in_progress'),
      'maximum_points': this.velocity(), 'column': '#in_progress'
    });

    this.appendIteration(currentIteration, '#done');

    //
    // Backlog column
    //
    var backlogIteration = new Iteration({
      'number': currentIteration.get('number') + 1,
      'column': '#backlog', 'maximum_points': this.velocity()
    });
    this.appendIteration(backlogIteration, '#backlog');

    _.each(this.stories.column('#backlog'), function(story) {

      // The in progress iteration usually needs to be filled with the first
      // few stories from the backlog, unless the points total of the stories
      // in progress already equal or exceed the project velocity
      if (currentIteration.canTakeStory(story)) {

        // On initialisation, a stories column is determined based on the
        // story state.  For unstarted stories this defaults to #backlog.
        // Stories matched here need this value overridden to #in_progress
        story.column = '#in_progress';

        currentIteration.get('stories').push(story);
        return;
      }

      if (!backlogIteration.canTakeStory(story)) {

        // Iterations sometimes 'overflow', i.e. an iteration may contain a
        // 5 point story but the project velocity is 1.  In this case, the
        // next iteration that can have a story added is the current + 4.
        var nextNumber = backlogIteration.get('number') + 1 + Math.ceil(backlogIteration.overflowsBy() / that.velocity());

        backlogIteration = new Iteration({
          'number': nextNumber, 'column': '#backlog',
          'maximum_points': that.velocity()
        });

        that.appendIteration(backlogIteration, '#backlog');
      }

      backlogIteration.get('stories').push(story);
    });

    _.each(this.iterations, function(iteration) {
      iteration.project = that;
    });
  },

  // Adds an iteration to the project.  Creates empty iterations to fill any
  // gaps between the iteration number and the last iteration number added.
  appendIteration: function(iteration, columnForMissingIterations) {

    var lastIteration = _.last(this.iterations);

    // If there is a gap between the last iteration and this one, fill
    // the gap with empty iterations
    this.iterations = this.iterations.concat(
      Iteration.createMissingIterations(columnForMissingIterations, lastIteration, iteration)
    );

    this.iterations.push(iteration);
  }
});
<commit_msg>Fix bug with cached story.column value<commit_after>var Project = Backbone.Model.extend({
  name: 'project',

  initialize: function(args) {

    this.maybeUnwrap(args);

    this.bind('change:last_changeset_id', this.updateChangesets);

    this.stories = new StoryCollection();
    this.stories.url = this.url() + '/stories';
    this.stories.project = this;

    this.users = new UserCollection();
    this.users.url = this.url() + '/users';
    this.users.project = this;

    this.iterations = [];
  },

  defaults: {
    default_velocity: 10
  },

  url: function() {
    return '/projects/' + this.id;
  },

  // The ids of the columns, in the order that they appear by story weight
  columnIds: ['#done', '#in_progress', '#backlog', '#chilly_bin'],

  // Return an array of the columns that appear after column, or an empty
  // array if the column is the last
  columnsAfter: function(column) {
    var index = _.indexOf(this.columnIds, column);
    if (index === -1) {
      // column was not found in the array
      throw column.toString() + ' is not a valid column';
    }
    return this.columnIds.slice(index + 1);
  },

  // Return an array of the columns that appear before column, or an empty
  // array if the column is the first
  columnsBefore: function(column) {
    var index = _.indexOf(this.columnIds, column);
    if (index === -1) {
      // column was not found in the array
      throw column.toString() + ' is not a valid column';
    }
    return this.columnIds.slice(0, index);
  },

  // This method is triggered when the last_changeset_id attribute is changed,
  // which indicates there are changed or new stories on the server which need
  // to be loaded.
  updateChangesets: function() {
    var from = this.previous('last_changeset_id');
    if (from === null) {
      from = 0;
    }
    var to = this.get('last_changeset_id');

    var model = this;
    var options = {
      type: 'GET',
      dataType: 'json',
      success: function(resp, status, xhr) {
        model.handleChangesets(resp);
      },
      data: {from: from, to: to},
      url: this.url() + '/changesets'
    };

    $.ajax(options);
  },

  // (Re)load each of the stories described in the provided changesets.
  handleChangesets: function(changesets) {
    var that = this;

    var story_ids = _.map(changesets, function(changeset) {
      return changeset.changeset.story_id;
    });
    story_ids = _.uniq(story_ids);

    _.each(story_ids, function(story_id) {
      // FIXME - Feature envy on stories collection
      var story = that.stories.get(story_id);
      if (story) {
        // This is an existing story on the collection, just reload it
        story.fetch();
      } else {
        // This is a new story, which is present on the server but we don't
        // have it locally yet.
        that.stories.add({id: story_id});
        story = that.stories.get(story_id);
        story.fetch();
      }
    });
  },

  milliseconds_in_a_day: 1000 * 60 * 60 * 24,

  // Return the correct iteration number for a given date.
  getIterationNumberForDate: function(compare_date) {
    //var start_date = new Date(this.get('start_date'));
    var start_date = this.startDate();
    var difference = Math.abs(compare_date.getTime() - start_date.getTime());
    var days_apart = Math.round(difference / this.milliseconds_in_a_day);
    return Math.floor((days_apart / (this.get('iteration_length') * 7)) + 1);
  },

  getDateForIterationNumber: function(iteration_number) {
    // The difference betweeen the start date in days.  Iteration length is
    // in weeks.
    var difference = (7 * this.get('iteration_length')) * (iteration_number - 1);
    var start_date = this.startDate();
    var iteration_date = new Date(start_date);

    iteration_date.setDate(start_date.getDate() + difference);
    return iteration_date;
  },

  currentIterationNumber: function() {
    return this.getIterationNumberForDate(new Date());
  },

  startDate: function() {

    var start_date;
    if (this.get('start_date')) {
      // Parse the date string into an array of [YYYY, MM, DD] to
      // ensure identical date behaviour across browsers.
      var dateArray = this.get('start_date').split('/');
      var year = parseInt(dateArray[0], 10);
      // Month is zero indexed
      var month = parseInt(dateArray[1], 10) - 1;
      var day = parseInt(dateArray[2], 10);

      start_date = new Date(year, month, day);
    } else {
      start_date = new Date();
    }

    // Is the specified project start date the same week day as the iteration
    // start day?
    if (start_date.getDay() === this.get('iteration_start_day')) {
      return start_date;
    } else {
      // Calculate the date of the nearest prior iteration start day to the
      // specified project start date.  So if the iteration start day is
      // set to Monday, but the project start date is set to a specific
      // Thursday, return the Monday before the Thursday.  A greater
      // mathemtician than I could probably do this with the modulo.
      var day_difference = start_date.getDay() - this.get('iteration_start_day');

      // The iteration start day is after the project start date, in terms of
      // day number
      if (day_difference < 0) {
        day_difference = day_difference + 7;
      }
      return new Date(start_date - day_difference * this.milliseconds_in_a_day);
    }
  },

  // Override the calculated velocity with a user defined value.  If this
  // value is different to the calculated velocity, the velocityIsFake
  // attribute will be set to true.
  velocity: function(userVelocity) {
    if(userVelocity !== undefined) {

      if(userVelocity < 1) {
        userVelocity = 1;
      }

      if(userVelocity === this.calculateVelocity()) {
        this.unset('userVelocity');
      } else {
        this.set({userVelocity: userVelocity});
      }
    }
    if(this.get('userVelocity')) {
      return this.get('userVelocity');
    } else {
      return this.calculateVelocity();
    }
  },

  velocityIsFake: function() {
    return (this.get('userVelocity') !== undefined);
  },

  calculateVelocity: function() {
    if (this.doneIterations().length === 0) {
      return this.get('default_velocity');
    } else {
      // TODO Make number of iterations configurable
      var numIterations = 3;
      var iterations = this.doneIterations();

      // Take a maximum of numIterations from the end of the array
      if (iterations.length > numIterations) {
        iterations = iterations.slice(iterations.length - numIterations);
      }

      var pointsArray = _.invoke(iterations, 'points');
      var sum = _.reduce(pointsArray, function(memo, points) {
        return memo + points;
      }, 0);
      var velocity = Math.floor(sum / pointsArray.length);
      return velocity < 1 ? 1 : velocity;
    }
  },

  revertVelocity: function() {
    this.unset('userVelocity');
  },

  doneIterations: function() {
    return _.select(this.iterations, function(iteration) {
      return iteration.get('column') === "#done";
    });
  },

  rebuildIterations: function() {

    //
    // Done column
    //
    var that = this;

    // Clear the project iterations
    this.iterations = [];

    // Reset all story column values.  Required as the story.column values
    // may have been changed from their default values by a prior run of
    // this method.
    this.stories.invoke('setColumn');

    var doneIterations = _.groupBy(this.stories.column('#done'),
                                    function(story) {
                                      return story.iterationNumber();
                                    });

    // groupBy() returns an object with keys of the iteration number
    // and values of the stories array.  Ensure the keys are sorted
    // in numeric order.
    var doneNumbers = _.keys(doneIterations).sort(function(left, right) {
      return (left - right);
    });

    _.each(doneNumbers, function(iterationNumber) {
      var stories = doneIterations[iterationNumber];
      var iteration = new Iteration({
        'number': iterationNumber, 'stories': stories, column: '#done'
      });

      that.appendIteration(iteration, '#done');

    });

    var currentIteration = new Iteration({
      'number': this.currentIterationNumber(),
      'stories': this.stories.column('#in_progress'),
      'maximum_points': this.velocity(), 'column': '#in_progress'
    });

    this.appendIteration(currentIteration, '#done');

    //
    // Backlog column
    //
    var backlogIteration = new Iteration({
      'number': currentIteration.get('number') + 1,
      'column': '#backlog', 'maximum_points': this.velocity()
    });
    this.appendIteration(backlogIteration, '#backlog');

    _.each(this.stories.column('#backlog'), function(story) {

      // The in progress iteration usually needs to be filled with the first
      // few stories from the backlog, unless the points total of the stories
      // in progress already equal or exceed the project velocity
      if (currentIteration.canTakeStory(story)) {

        // On initialisation, a stories column is determined based on the
        // story state.  For unstarted stories this defaults to #backlog.
        // Stories matched here need this value overridden to #in_progress
        story.column = '#in_progress';

        currentIteration.get('stories').push(story);
        return;
      }

      if (!backlogIteration.canTakeStory(story)) {

        // Iterations sometimes 'overflow', i.e. an iteration may contain a
        // 5 point story but the project velocity is 1.  In this case, the
        // next iteration that can have a story added is the current + 4.
        var nextNumber = backlogIteration.get('number') + 1 + Math.ceil(backlogIteration.overflowsBy() / that.velocity());

        backlogIteration = new Iteration({
          'number': nextNumber, 'column': '#backlog',
          'maximum_points': that.velocity()
        });

        that.appendIteration(backlogIteration, '#backlog');
      }

      backlogIteration.get('stories').push(story);
    });

    _.each(this.iterations, function(iteration) {
      iteration.project = that;
    });
  },

  // Adds an iteration to the project.  Creates empty iterations to fill any
  // gaps between the iteration number and the last iteration number added.
  appendIteration: function(iteration, columnForMissingIterations) {

    var lastIteration = _.last(this.iterations);

    // If there is a gap between the last iteration and this one, fill
    // the gap with empty iterations
    this.iterations = this.iterations.concat(
      Iteration.createMissingIterations(columnForMissingIterations, lastIteration, iteration)
    );

    this.iterations.push(iteration);
  }
});
<|endoftext|>


<commit_before>var _arity = require('./_arity');
var _slice = require('./_slice');
var max = require('../max');
var pluck = require('../pluck');
var reduce = require('../reduce');

/**
 * Create a predicate wrapper which will call a pick function (all/any) for each predicate
 *
 * @private
 * @see R.all
 * @see R.any
 */
module.exports = function _predicateWrap(predPicker) {
  return function(preds) {
    var predIterator = function() {
      var args = arguments;
      return predPicker(function(predicate) {
        return predicate.apply(null, args);
      }, preds);
    };

    var longest = reduce(max, 0, pluck('length', preds));

    return arguments.length > 1 ?
      // Call function immediately if given arguments
      predIterator.apply(null, _slice(arguments, 1)) :
      // Return a function which will call the predicates with the provided arguments
      _arity(longest, predIterator);
  };
};
<commit_msg>calculate arity in _predicateWrap only when necessary<commit_after>var _arity = require('./_arity');
var _slice = require('./_slice');
var max = require('../max');
var pluck = require('../pluck');
var reduce = require('../reduce');

/**
 * Create a predicate wrapper which will call a pick function (all/any) for each predicate
 *
 * @private
 * @see R.all
 * @see R.any
 */
module.exports = function _predicateWrap(predPicker) {
  return function(preds) {
    var predIterator = function() {
      var args = arguments;
      return predPicker(function(predicate) {
        return predicate.apply(null, args);
      }, preds);
    };
    return arguments.length > 1 ?
      // Call function immediately if given arguments
      predIterator.apply(null, _slice(arguments, 1)) :
      // Return a function which will call the predicates with the provided arguments
      _arity(reduce(max, 0, pluck('length', preds)), predIterator);
  };
};
<|endoftext|>