<commit_before>/**
 * Create a notification
 * @constructor
 */
function Notification () {
	this.encoding = 'utf8';

	this.payload = {};
	this.expiry = 0;
	this.identifier = 0;
	this.device;

	this.alert = undefined;
	this.badge = undefined;
	this.sound = undefined;
	/** @since v1.2.0 */
	this.newsstandAvailable = undefined;
};

/**
 * Clone a notification to send to multiple devices
 * @param {Device} [device] Device the notification will be sent to
 * @returns {Notification} A notification containing the same properties as the receiver
 * @since v1.2.0
 */
Notification.prototype.clone = function (device) {
	var notification = new Notification();

	notification.encoding = this.encoding;
	notification.payload = this.payload;
	notification.expiry = this.expiry;
	notification.identifier = this.identifier;
	notification.device = device;

	notification.alert = this.alert;
	notification.badge = this.badge;
	notification.sound = this.sound;
	notification.newsstandAvailable = this.newsstandAvailable;

	return notification
}

/**
 * Set the alert text for the notification
 * @param {String} alertText The text of the alert message.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setAlertText = function (text) {
	if(typeof this.alert != "object") {
		this.alert = text;
	}
	else {
		this.prepareAlert();
		this.alert['body'] = text;
	}
}

/**
 * Set the action-loc-key property on the alert object
 * @param {String} [key] If a string is specified, displays an alert with two buttons, whose behavior is described in Table 3-1. However, iOS uses the string as a key to get a localized string in the current localization to use for the right button’s title instead of “View”. If the value is null, the system displays an alert with a single OK button that simply dismisses the alert when tapped.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setActionLocKey = function (key) {
	this.prepareAlert();
	this.alert['action-loc-key'] = key;
}

/**
 * Set the loc-key parameter on the alert object
 * @param {String} [key] A key to an alert-message string in a Localizable.strings file for the current localization (which is set by the user’s language preference).
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLocKey = function (key) {
	this.prepareAlert();
	if(!key) {
		delete this.alert["loc-key"];
		return
	}
	this.alert['loc-key'] = key;
}

/**
 * Set the loc-args parameter on the alert object
 * @param {String[]} [args] Variable string values to appear in place of the format specifiers in loc-key.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLocArgs = function (args) {
	this.prepareAlert();
	if(!args) {
		delete this.alert["loc-args"];
		return
	}
	this.alert['loc-args'] = args;
}

/**
 * Set the launch-image parameter on the alert object
 * @param {String} [image] The filename of an image file in the application bundle; it may include the extension or omit it.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLaunchImage = function (image) {
	this.prepareAlert();
	if(!image) {
		delete this.alert["launch-image"];
		return
	}
	this.alert["launch-image"] = image;
}

/**
 * If an alert object doesn't already exist create it and transfer any existing message into the .body property
 * @private
 * @since v1.2.0
 */
Notification.prototype.prepareAlert = function () {
	var existingValue = this.alert;
	if(typeof existingValue != "object") {
		this.alert = {};
		if(typeof existingValue == "string") {
			this.alert.body = existingValue;
		}
	}
}

/**
 * @returns {Number} Byte length of the notification payload
 * @private
 * @since v1.2.0
 */
Notification.prototype.length = function () {
	return Buffer.byteLength(JSON.stringify(this), this.encoding || 'utf8');
}

/**
 * If the notification payload is too long to send this method will attempt to trim the alert body text.
 * @returns {Number} The number of characters removed from the body text. If a negative value is returned, the text is too short to be trimmed enough.
 * @since v1.2.0
 */
Notification.prototype.trim = function() {
	var tooLong = this.length() - 255;
	if(tooLong <= 0) {
		return 0;
	}
	if(typeof this.alert == "string") {
		var length = Buffer.byteLength(this.alert.length, this.encoding || 'utf8');
		if (length < tooLong) {
			return length - tooLong;
		}
		this.alert = this.alert.substring(0, length - tooLong);
		return tooLong;
	}
	else if(typeof this.alert == "object" && typeof this.alert.body == "string") {
		var length = Buffer.byteLength(this.alert.body.length, this.encoding || 'utf8');
		if (length < tooLong) {
			return length - tooLong;
		}
		this.alert.body = this.alert.body.substring(0, length - tooLong);
		return tooLong;
	}
	return -tooLong;
}

/**
 * @private
 */
Notification.prototype.toJSON = function () {
	if (this.payload === undefined) {
		this.payload = {};
	}
	if (this.payload.aps === undefined) {
		this.payload.aps = {};
	}
	if (typeof this.badge == 'number') {
		this.payload.aps.badge = this.badge;
	}
	if (typeof this.sound == 'string') {
		this.payload.aps.sound = this.sound;
	}
	if (typeof this.alert == 'string' || typeof this.alert == 'object') {
		this.payload.aps.alert = this.alert;
	}
	if (this.newsstandAvailable) {
		this.payload.aps['content-available'] = 1;
	}
	return this.payload;
};

module.exports = Notification;<commit_msg>Fixed error in trim() of notification<commit_after>/**
 * Create a notification
 * @constructor
 */
function Notification () {
	this.encoding = 'utf8';

	this.payload = {};
	this.expiry = 0;
	this.identifier = 0;
	this.device;

	this.alert = undefined;
	this.badge = undefined;
	this.sound = undefined;
	/** @since v1.2.0 */
	this.newsstandAvailable = undefined;
};

/**
 * Clone a notification to send to multiple devices
 * @param {Device} [device] Device the notification will be sent to
 * @returns {Notification} A notification containing the same properties as the receiver
 * @since v1.2.0
 */
Notification.prototype.clone = function (device) {
	var notification = new Notification();

	notification.encoding = this.encoding;
	notification.payload = this.payload;
	notification.expiry = this.expiry;
	notification.identifier = this.identifier;
	notification.device = device;

	notification.alert = this.alert;
	notification.badge = this.badge;
	notification.sound = this.sound;
	notification.newsstandAvailable = this.newsstandAvailable;

	return notification
}

/**
 * Set the alert text for the notification
 * @param {String} alertText The text of the alert message.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setAlertText = function (text) {
	if(typeof this.alert != "object") {
		this.alert = text;
	}
	else {
		this.prepareAlert();
		this.alert['body'] = text;
	}
}

/**
 * Set the action-loc-key property on the alert object
 * @param {String} [key] If a string is specified, displays an alert with two buttons, whose behavior is described in Table 3-1. However, iOS uses the string as a key to get a localized string in the current localization to use for the right button’s title instead of “View”. If the value is null, the system displays an alert with a single OK button that simply dismisses the alert when tapped.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setActionLocKey = function (key) {
	this.prepareAlert();
	this.alert['action-loc-key'] = key;
}

/**
 * Set the loc-key parameter on the alert object
 * @param {String} [key] A key to an alert-message string in a Localizable.strings file for the current localization (which is set by the user’s language preference).
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLocKey = function (key) {
	this.prepareAlert();
	if(!key) {
		delete this.alert["loc-key"];
		return
	}
	this.alert['loc-key'] = key;
}

/**
 * Set the loc-args parameter on the alert object
 * @param {String[]} [args] Variable string values to appear in place of the format specifiers in loc-key.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLocArgs = function (args) {
	this.prepareAlert();
	if(!args) {
		delete this.alert["loc-args"];
		return
	}
	this.alert['loc-args'] = args;
}

/**
 * Set the launch-image parameter on the alert object
 * @param {String} [image] The filename of an image file in the application bundle; it may include the extension or omit it.
 * @see The Payload Documentation
 * @since v1.2.0
 */
Notification.prototype.setLaunchImage = function (image) {
	this.prepareAlert();
	if(!image) {
		delete this.alert["launch-image"];
		return
	}
	this.alert["launch-image"] = image;
}

/**
 * If an alert object doesn't already exist create it and transfer any existing message into the .body property
 * @private
 * @since v1.2.0
 */
Notification.prototype.prepareAlert = function () {
	var existingValue = this.alert;
	if(typeof existingValue != "object") {
		this.alert = {};
		if(typeof existingValue == "string") {
			this.alert.body = existingValue;
		}
	}
}

/**
 * @returns {Number} Byte length of the notification payload
 * @private
 * @since v1.2.0
 */
Notification.prototype.length = function () {
	return Buffer.byteLength(JSON.stringify(this), this.encoding || 'utf8');
}

/**
 * If the notification payload is too long to send this method will attempt to trim the alert body text.
 * @returns {Number} The number of characters removed from the body text. If a negative value is returned, the text is too short to be trimmed enough.
 * @since v1.2.0
 */
Notification.prototype.trim = function() {
	var tooLong = this.length() - 255;
	if(tooLong <= 0) {
		return 0;
	}
	if(typeof this.alert == "string") {
		var length = Buffer.byteLength(this.alert, this.encoding || 'utf8');
		if (length < tooLong) {
			return length - tooLong;
		}
		this.alert = this.alert.substring(0, length - tooLong);
		return tooLong;
	}
	else if(typeof this.alert == "object" && typeof this.alert.body == "string") {
		var length = Buffer.byteLength(this.alert.body, this.encoding || 'utf8');
		if (length < tooLong) {
			return length - tooLong;
		}
		this.alert.body = this.alert.body.substring(0, length - tooLong);
		return tooLong;
	}
	return -tooLong;
}

/**
 * @private
 */
Notification.prototype.toJSON = function () {
	if (this.payload === undefined) {
		this.payload = {};
	}
	if (this.payload.aps === undefined) {
		this.payload.aps = {};
	}
	if (typeof this.badge == 'number') {
		this.payload.aps.badge = this.badge;
	}
	if (typeof this.sound == 'string') {
		this.payload.aps.sound = this.sound;
	}
	if (typeof this.alert == 'string' || typeof this.alert == 'object') {
		this.payload.aps.alert = this.alert;
	}
	if (this.newsstandAvailable) {
		this.payload.aps['content-available'] = 1;
	}
	return this.payload;
};

module.exports = Notification;<|endoftext|>


<commit_before>
(function() {
	var app = angular.module('SportScheduler', []);

 	app.controller('UserController', ['$scope', '$http', function($scope, $http){
 		$scope.user = {
 		firstName: '',
 		lastName: '',
 		email: '',
 		phone: '',
 		fbUserId: '',
 		accessToken: '',
 		image: ''
		};

		$scope.userGetPath = '/users/' + $scope.user.fbUserId;
		$scope.userPutPath = '/users/' + $scope.user.firstName + '/' + $scope.user.lastName + '/' + $scope.user.email + '/' + $scope.user.phone + '/' + $scope.user.image;

		$scope.submit = function(phone) {
		 	$scope.user.phone = phone;
		 	localStorage.phone = phone;
		};

		$scope.log = function() {
		 	console.log($scope.user.firstName);
		 	console.log($scope.user.lastName);
		 	console.log($scope.user.email);
		 	console.log($scope.user.fbUserId);
		};

		$scope.setUser = function(){
			if(localStorage.getItem("loggedIn") === "true"){
				$scope.user.firstName = localStorage.getItem("first_name");
				$scope.user.lastName = localStorage.getItem("last_name");
				$scope.user.email = localStorage.getItem("email");
				$scope.user.fbUserId = localStorage.getItem("id");
				$scope.user.image = localStorage.getItem("image");
				$scope.user.phone = localStorage.getItem("phone");
			}
		};

		$scope.logout = function() {
			localStorage.setItem("loggedIn", "false");
			window.location = "../index.html";
		}

		$scope.get = function() {
			$http({method: 'GET', url: $scope.userGetPath}).
				success(function(data, status) {
					if(data.length) {
						var userVals = JSON.parse(data);
						$scope.user.firstName = userVals.firstName;
						$scope.user.lastName = userVals.lastName;
						$scope.user.email = userVals.email;
						$scope.user.phone = userVals.phone;
						$scope.user.image = userVals.picture;
					}
				});
		};

		$scope.put = function() {
			$http({method: 'PUT', url: $scope.userPutPath}).
				success(function(data, status) {
					if(status = '200'){
						console.log(data);
					}
				});
		};

	}]);

	app.controller('FacilityController', ['$scope', function($scope){
 		$scope.facilities = [
 			{
				name: 'Richards Building - BYU',
				hours: '6:00 am - 9:45 pm Mon-Sat',
				phone: '(801) 422-3644',
				images: "../assets/rb.jpg"

			},
			{
				name: '24 Hour Fitness',
				hours: '6:00 am - 12:00 pm Mon-Sat',
				phone: '(801) 224-2096',
				images: "../assets/24Hour.jpg"

			},
			{
					name: 'Orem Recreation Center',
					hours: '5:00 am - 10:00 pm Mon-Fri 7:00 am - 7:00 pm Sat',
					phone: '(801) 852-6600',
					images: "../assets/OremRec.jpg"

				},
				{
					name: 'Provo Recreation Center',
					hours: '5:00 am - 10:00 pm Mon-Fri 7:00 am - 8:00 pm Sat',
					phone: '(801) 229-7154',
					images: "../assets/ProvoRec.jpg"

				}

		];

	}]);

	app.controller('CourtController', ['$scope', function($scope){
	 		$scope.courts = [
				{
					name: 'Bulldog',
					image: "../assets/rb.jpg",
					hours: ['7 am','8 am','9 am','10 am','11 am','12 pm','1 pm','2 pm','3 pm','4 pm','5 pm','6 pm','7 pm'],
					hoursOfOp: [
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0]
						],
				}

			];
		}]);

})();

// var myApp = angular.module('SportScheduler',[])
//    .config(function($routeProvider) {
//        $routeProvider
//                .when('/homePage', {templateUrl: "views/homePage.html", controller: "homeCtrl"})
//                .when('/login', {templateUrl: "views/login.html", controller: "loginCtrl"})
//                .when('/project/:projectId', {templateUrl: "views/project.html", controller: "projectCtrl"})
//                .when('/editproject/:projectId', {templateUrl: "views/editproject.html", controller: "editProjectCtrl"})
//                .otherwise({redirectTo: '/home'});
//    });<commit_msg>updated redirect url in logout function<commit_after>
(function() {
	var app = angular.module('SportScheduler', []);

 	app.controller('UserController', ['$scope', '$http', function($scope, $http){
 		$scope.user = {
 		firstName: '',
 		lastName: '',
 		email: '',
 		phone: '',
 		fbUserId: '',
 		accessToken: '',
 		image: ''
		};

		$scope.userGetPath = '/users/' + $scope.user.fbUserId;
		$scope.userPutPath = '/users/' + $scope.user.firstName + '/' + $scope.user.lastName + '/' + $scope.user.email + '/' + $scope.user.phone + '/' + $scope.user.image;

		$scope.submit = function(phone) {
		 	$scope.user.phone = phone;
		 	localStorage.phone = phone;
		};

		$scope.log = function() {
		 	console.log($scope.user.firstName);
		 	console.log($scope.user.lastName);
		 	console.log($scope.user.email);
		 	console.log($scope.user.fbUserId);
		};

		$scope.setUser = function(){
			if(localStorage.getItem("loggedIn") === "true"){
				$scope.user.firstName = localStorage.getItem("first_name");
				$scope.user.lastName = localStorage.getItem("last_name");
				$scope.user.email = localStorage.getItem("email");
				$scope.user.fbUserId = localStorage.getItem("id");
				$scope.user.image = localStorage.getItem("image");
				$scope.user.phone = localStorage.getItem("phone");
			}
		};

		$scope.logout = function() {
			localStorage.setItem("loggedIn", "false");
			window.location = "../";
		}

		$scope.get = function() {
			$http({method: 'GET', url: $scope.userGetPath}).
				success(function(data, status) {
					if(data.length) {
						var userVals = JSON.parse(data);
						$scope.user.firstName = userVals.firstName;
						$scope.user.lastName = userVals.lastName;
						$scope.user.email = userVals.email;
						$scope.user.phone = userVals.phone;
						$scope.user.image = userVals.picture;
					}
				});
		};

		$scope.put = function() {
			$http({method: 'PUT', url: $scope.userPutPath}).
				success(function(data, status) {
					if(status = '200'){
						console.log(data);
					}
				});
		};

	}]);

	app.controller('FacilityController', ['$scope', function($scope){
 		$scope.facilities = [
 			{
				name: 'Richards Building - BYU',
				hours: '6:00 am - 9:45 pm Mon-Sat',
				phone: '(801) 422-3644',
				images: "../assets/rb.jpg"

			},
			{
				name: '24 Hour Fitness',
				hours: '6:00 am - 12:00 pm Mon-Sat',
				phone: '(801) 224-2096',
				images: "../assets/24Hour.jpg"

			},
			{
					name: 'Orem Recreation Center',
					hours: '5:00 am - 10:00 pm Mon-Fri 7:00 am - 7:00 pm Sat',
					phone: '(801) 852-6600',
					images: "../assets/OremRec.jpg"

				},
				{
					name: 'Provo Recreation Center',
					hours: '5:00 am - 10:00 pm Mon-Fri 7:00 am - 8:00 pm Sat',
					phone: '(801) 229-7154',
					images: "../assets/ProvoRec.jpg"

				}

		];

	}]);

	app.controller('CourtController', ['$scope', function($scope){
	 		$scope.courts = [
				{
					name: 'Bulldog',
					image: "../assets/rb.jpg",
					hours: ['7 am','8 am','9 am','10 am','11 am','12 pm','1 pm','2 pm','3 pm','4 pm','5 pm','6 pm','7 pm'],
					hoursOfOp: [
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0],
							[0, 0, 0, 0, 0, 0, 0]
						],
				}

			];
		}]);

})();

// var myApp = angular.module('SportScheduler',[])
//    .config(function($routeProvider) {
//        $routeProvider
//                .when('/homePage', {templateUrl: "views/homePage.html", controller: "homeCtrl"})
//                .when('/login', {templateUrl: "views/login.html", controller: "loginCtrl"})
//                .when('/project/:projectId', {templateUrl: "views/project.html", controller: "projectCtrl"})
//                .when('/editproject/:projectId', {templateUrl: "views/editproject.html", controller: "editProjectCtrl"})
//                .otherwise({redirectTo: '/home'});
//    });<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var util = require('util');
var _ = require('lodash');
var markdown = require('marked');

var app = {};

function PackageInfo(_app) {
    // global variables
    app = _app;

    // marked (markdown) Settings.
    markdown.setOptions(app.options.marked);
}

/**
 * Inherit
 */
util.inherits(PackageInfo, Object);

/**
 * Exports
 */
module.exports = PackageInfo;

/**
 * Read package.json Data and optinal descriptions
 */
PackageInfo.prototype.get = function() {
    var result = {};

    // Read package.json
    var packageJson = this._readPackageData('package.json');

    if(packageJson.apidoc)
        result = packageJson.apidoc;

    _.defaults(result, {
        name       : packageJson.name || '',
        version    : packageJson.version || '0.0.0',
        description: packageJson.description || '',
    });

    // Read apidoc.json (and overwrite package.json information)
    var apidocJson = this._readPackageData('apidoc.json');

    // apidoc.json has higher priority
    _.extend(result, apidocJson);

    // Replace header footer with file contents
    _.extend(result, this._getHeaderFooter(result));

    if (Object.keys(apidocJson).length === 0)
        app.log.warning('Please create an apidoc.json.');

    // Generator Information
    try {
        var apidocPath = path.join(__dirname, '../');
        var json = JSON.parse( fs.readFileSync(apidocPath + 'package.json', 'utf8') );
        result.generator = {
            version: json.version,
            time: new Date()
        };
    } catch(e) {}

    return result;
};

/**
 * Read json data from source dir, or if it not exists from current dir.
 * Return the data merged with the default values.
 *
 * @param {String} filename
 * @param {Object} defaults
 * @returns {Object}
 */
PackageInfo.prototype._readPackageData = function(filename) {
    var result = {};
    var jsonFilename = path.join(app.options.src, filename);

    // read from source dir
    if ( ! fs.existsSync(jsonFilename)) {
        // read vom current dir
        jsonFilename = './' + filename;
    }
    if ( ! fs.existsSync(jsonFilename)) {
        app.log.debug(filename + ' not found!');
    } else {
        try {
            result = JSON.parse( fs.readFileSync(jsonFilename, 'utf8') );
            app.log.debug('read: ' + jsonFilename);
        } catch (e) {
            throw new Error('Can not read: ' + filename + ', please check the format (e.g. missing comma).');
        }
    }
    return result;
};

/**
 * Get json.header / json.footer title and markdown content (from file)
 *
 * @param {Object} json
 * @returns {Object}
 */
PackageInfo.prototype._getHeaderFooter = function(json) {
    var result = {};

    ['header', 'footer'].forEach(function(key) {
        if (json[key] && json[key].filename) {
            console.log(key);
            var filename = path.join(app.options.src, json[key].filename);
            if ( ! fs.existsSync(filename))
                filename = path.join('./', json[key].filename);

            try {
                app.log.debug('read header file: ' + filename);
                result[key] = {
                    title  : json[key].title,
                    content: markdown( fs.readFileSync(filename, 'utf8') )
                };
            } catch (e) {
                throw new Error('Can not read: ' + filename + '.');
            }
        }
    });

    return result;
};
<commit_msg>Parser: Allow overwrite of packageInfo e.g. from grun task #177.<commit_after>var fs = require('fs');
var path = require('path');
var util = require('util');
var _ = require('lodash');
var markdown = require('marked');

var app = {};

function PackageInfo(_app) {
    // global variables
    app = _app;

    // marked (markdown) Settings.
    markdown.setOptions(app.options.marked);
}

/**
 * Inherit
 */
util.inherits(PackageInfo, Object);

/**
 * Exports
 */
module.exports = PackageInfo;

/**
 * Read package.json Data and optinal descriptions
 */
PackageInfo.prototype.get = function() {
    var result = {};

    // Read package.json
    var packageJson = this._readPackageData('package.json');

    if(packageJson.apidoc)
        result = packageJson.apidoc;

    _.defaults(result, {
        name       : packageJson.name || '',
        version    : packageJson.version || '0.0.0',
        description: packageJson.description || '',
    });

    // Read apidoc.json (and overwrite package.json information)
    var apidocJson = this._readPackageData('apidoc.json');

    // apidoc.json has higher priority
    _.extend(result, apidocJson);

    // options.packageInfo overwrites packageInfo
    _.extend(result, app.options.packageInfo);

    // Replace header footer with file contents
    _.extend(result, this._getHeaderFooter(result));

    if (Object.keys(apidocJson).length === 0)
        app.log.warning('Please create an apidoc.json.');

    // Generator Information
    try {
        var apidocPath = path.join(__dirname, '../');
        var json = JSON.parse( fs.readFileSync(apidocPath + 'package.json', 'utf8') );
        result.generator = {
            version: json.version,
            time: new Date()
        };
    } catch(e) {}

    return result;
};

/**
 * Read json data from source dir, or if it not exists from current dir.
 * Return the data merged with the default values.
 *
 * @param {String} filename
 * @param {Object} defaults
 * @returns {Object}
 */
PackageInfo.prototype._readPackageData = function(filename) {
    var result = {};
    var jsonFilename = path.join(app.options.src, filename);

    // read from source dir
    if ( ! fs.existsSync(jsonFilename)) {
        // read vom current dir
        jsonFilename = './' + filename;
    }
    if ( ! fs.existsSync(jsonFilename)) {
        app.log.debug(filename + ' not found!');
    } else {
        try {
            result = JSON.parse( fs.readFileSync(jsonFilename, 'utf8') );
            app.log.debug('read: ' + jsonFilename);
        } catch (e) {
            throw new Error('Can not read: ' + filename + ', please check the format (e.g. missing comma).');
        }
    }
    return result;
};

/**
 * Get json.header / json.footer title and markdown content (from file)
 *
 * @param {Object} json
 * @returns {Object}
 */
PackageInfo.prototype._getHeaderFooter = function(json) {
    var result = {};

    ['header', 'footer'].forEach(function(key) {
        if (json[key] && json[key].filename) {
            console.log(key);
            var filename = path.join(app.options.src, json[key].filename);
            if ( ! fs.existsSync(filename))
                filename = path.join('./', json[key].filename);

            try {
                app.log.debug('read header file: ' + filename);
                result[key] = {
                    title  : json[key].title,
                    content: markdown( fs.readFileSync(filename, 'utf8') )
                };
            } catch (e) {
                throw new Error('Can not read: ' + filename + '.');
            }
        }
    });

    return result;
};
<|endoftext|>


<commit_before>NEWSBLUR.ReaderFeedchooser = function(options) {
    var defaults = {};

    this.options = $.extend({}, defaults, options);
    this.model = NEWSBLUR.AssetModel.reader();
    this.google_favicon_url = 'http://www.google.com/s2/favicons?domain_url=';
    this.runner();
};

NEWSBLUR.ReaderFeedchooser.prototype = {

    runner: function() {
        this.MAX_FEEDS = 40;
        this.approve_list = [];
        this.make_modal();
        this.open_modal();
        this.initial_load_feeds();

        this.$modal.bind('mousedown', $.rescope(this.handle_click, this));
    },

    make_modal: function() {
        var self = this;

        this.$modal = $.make('div', { className: 'NB-modal-feedchooser NB-modal' }, [
            $.make('h2', { className: 'NB-modal-title' }, 'Choose Your '+this.MAX_FEEDS),
            $.make('h2', { className: 'NB-modal-subtitle' }, [
                $.make('b', [
                    'You have a ',
                    $.make('span', { style: 'color: #303060;' }, 'Standard Account'),
                    ', which can follow up to '+this.MAX_FEEDS+' sites at a time.'
                ]),
                'Choose which '+this.MAX_FEEDS+' you would like to follow. You can always change these.'
            ]),
            $.make('div', { className: 'NB-feedchooser-info'}, [
                $.make('div', { className: 'NB-feedchooser-info-counts'})
            ]),
            this.make_feeds(),
            $.make('form', { className: 'NB-feedchooser-form' }, [
                $.make('div', { className: 'NB-modal-submit' }, [
                    $.make('input', { type: 'submit', disabled: 'true', className: 'NB-disabled NB-modal-submit-save NB-modal-submit-green', value: 'Check what you like above...' })
                ])
            ])
        ]);
    },

    make_feeds: function() {
        var feeds = this.model.feeds;

        var $feeds = $('#feed_list').clone(true).attr({
            'id': 'NB-feedchooser-feeds',
            'class': 'NB-feedlist NB-feedchooser unread_view_positive',
            'style': ''
        });

        // Expand collapsed folders
        $('ul.folder', $feeds).css({
            'display': 'block',
            'opacity': 1
        });

        $('.unread_count_positive', $feeds).text('On');
        $('.unread_count_negative', $feeds).text('Off');

        return $feeds;
    },

    open_modal: function() {
        var self = this;

        this.$modal.modal({
            'minWidth': 600,
            'maxWidth': 600,
            'overlayClose': true,
            'onOpen': function (dialog) {
                dialog.overlay.fadeIn(200, function () {
                    dialog.container.fadeIn(200);
                    dialog.data.fadeIn(200);
                });
            },
            'onShow': function(dialog) {
                $('#simplemodal-container').corner('6px');
            },
            'onClose': function(dialog) {
                dialog.data.hide().empty().remove();
                dialog.container.hide().empty().remove();
                dialog.overlay.fadeOut(200, function() {
                    dialog.overlay.empty().remove();
                    $.modal.close();
                });
                $('.NB-modal-holder').empty().remove();
            }
        });
    },

    add_feed_to_decline: function(feed_id) {
        this.approve_list = _.without(this.approve_list, feed_id);
        var $feed = this.find_feed_in_feed_list(feed_id);

        $feed.removeClass('NB-feedchooser-approve');
        $feed.addClass('NB-feedchooser-decline');
        this.update_counts();
    },

    add_feed_to_approve: function(feed_id) {
        if (!_.contains(this.approve_list, feed_id)) {
            this.approve_list.push(feed_id);
            var $feed = this.find_feed_in_feed_list(feed_id);

            $feed.removeClass('NB-feedchooser-decline');
            $feed.addClass('NB-feedchooser-approve');
        }
        this.update_counts();
    },

    find_feed_in_feed_list: function(feed_id) {
        var $feed_list = $('.NB-feedchooser', this.$modal);
        var $feeds = $([]);

        $('.feed', $feed_list).each(function() {
            if ($(this).data('feed_id') == feed_id) {
                $feeds.push($(this).get(0));
            }
        });

        return $feeds;
    },

    update_counts: function() {
        var $count = $('.NB-feedchooser-info-counts');
        var approved = this.approve_list.length;
        var $submit = $('.NB-modal-submit-save', this.$modal);
        var difference = approved - this.MAX_FEEDS;

        $count.text(approved + '/' + this.MAX_FEEDS);
        $count.toggleClass('NB-full', approved == this.MAX_FEEDS);
        $count.toggleClass('NB-error', approved > this.MAX_FEEDS);

        if (approved > this.MAX_FEEDS) {
          $submit.addClass('NB-disabled').attr('disabled', true).val('Too many sites! Deselect ' + (
            difference == 1 ?
            '1 site...' :
            difference + ' sites...'
          ));
        } else {
          $submit.removeClass('NB-disabled').attr('disabled', false).val('OK, These are my ' + approved + '. Save them, please!');
        }
    },

    initial_load_feeds: function() {
        var self = this;
        var $feeds = $('.feed', this.$modal);
        var feeds = this.model.get_feeds();

        var active_feeds = _.any(_.pluck(feeds, 'active'));

        if (!active_feeds) {
            // Get feed subscribers
            var min_subscribers = _.last(
              _.first(
                _.pluck(this.model.get_feeds(), 'subs').sort(function(a,b) {
                  return b-a;
                }),
                this.MAX_FEEDS
              )
            );

            // Decline everything
            var feeds = [];
            $feeds.each(function() {
                var feed_id = $(this).data('feed_id');

                self.add_feed_to_decline(feed_id);

                if (self.model.get_feed(feed_id)['subs'] >= min_subscribers) {
                    feeds.push(feed_id);
                }
            });

            // Approve feeds in subs
            _.each(feeds, function(feed_id) {
                if (self.model.get_feed(feed_id)['subs'] > min_subscribers &&
                    self.approve_list.length < self.MAX_FEEDS) {
                    self.add_feed_to_approve(feed_id);
                }
            });
            _.each(feeds, function(feed_id) {
                if (self.model.get_feed(feed_id)['subs'] == min_subscribers &&
                    self.approve_list.length < self.MAX_FEEDS) {
                    self.add_feed_to_approve(feed_id);
                }
            });
        } else {
            // Get active feeds
            var active_feeds = _.pluck(_.select(feeds, function(feed) {
                if (feed.active) return true;
            }), 'id');

            // Approve or decline
            var feeds = [];
            $feeds.each(function() {
                var feed_id = $(this).data('feed_id');

                if (_.contains(active_feeds, feed_id)) {
                    self.add_feed_to_approve(feed_id);
                } else {
                    self.add_feed_to_decline(feed_id);
                }
            });
        }
    },

    save: function() {
        var $submit = $('.NB-modal-submit-save', this.$modal);
        $submit.addClass('NB-disabled').val('Saving...');

        this.model.save_feed_chooser(this.approve_list, function() {
            NEWSBLUR.reader.load_feeds();
            $.modal.close();
        });
    },

    // ===========
    // = Actions =
    // ===========

    handle_click: function(elem, e) {
        var self = this;

        $.targetIs(e, { tagSelector: '.feed' }, _.bind(function($t, $p) {
            e.preventDefault();

            var feed_id = $t.data('feed_id');
            if (_.contains(this.approve_list, feed_id)) {
                this.add_feed_to_decline(feed_id);
            } else {
                this.add_feed_to_approve(feed_id);
            }
        }, this));

        $.targetIs(e, { tagSelector: '.NB-modal-submit-save' }, _.bind(function($t, $p) {
            e.preventDefault();
            this.save();
        }, this));
    },

    handle_cancel: function() {
        var $cancel = $('.NB-modal-cancel', this.$modal);

        $cancel.click(function(e) {
            e.preventDefault();
            $.modal.close();
        });
    }

};<commit_msg>Greatly improving performance of loading the feed chooser modal. Almost 1600ms -> 260ms. That's 6x as fast now.<commit_after>NEWSBLUR.ReaderFeedchooser = function(options) {
    var defaults = {};

    this.options = $.extend({}, defaults, options);
    this.model = NEWSBLUR.AssetModel.reader();
    this.google_favicon_url = 'http://www.google.com/s2/favicons?domain_url=';
    this.runner();
};

NEWSBLUR.ReaderFeedchooser.prototype = {

    runner: function() {
        this.start = new Date();
        this.MAX_FEEDS = 40;
        this.approve_list = [];
        this.make_modal();
        this.open_modal();
        this.find_feeds_in_feed_list();
        this.initial_load_feeds();

        this.$modal.bind('mousedown', $.rescope(this.handle_click, this));
    },

    make_modal: function() {
        var self = this;

        this.$modal = $.make('div', { className: 'NB-modal-feedchooser NB-modal' }, [
            $.make('h2', { className: 'NB-modal-title' }, 'Choose Your '+this.MAX_FEEDS),
            $.make('h2', { className: 'NB-modal-subtitle' }, [
                $.make('b', [
                    'You have a ',
                    $.make('span', { style: 'color: #303060;' }, 'Standard Account'),
                    ', which can follow up to '+this.MAX_FEEDS+' sites at a time.'
                ]),
                'Choose which '+this.MAX_FEEDS+' you would like to follow. You can always change these.'
            ]),
            $.make('div', { className: 'NB-feedchooser-info'}, [
                $.make('div', { className: 'NB-feedchooser-info-counts'})
            ]),
            this.make_feeds(),
            $.make('form', { className: 'NB-feedchooser-form' }, [
                $.make('div', { className: 'NB-modal-submit' }, [
                    $.make('input', { type: 'submit', disabled: 'true', className: 'NB-disabled NB-modal-submit-save NB-modal-submit-green', value: 'Check what you like above...' })
                ])
            ])
        ]);
    },

    make_feeds: function() {
        var feeds = this.model.feeds;

        var $feeds = $('#feed_list').clone(true).attr({
            'id': 'NB-feedchooser-feeds',
            'class': 'NB-feedlist NB-feedchooser unread_view_positive',
            'style': ''
        });

        // Expand collapsed folders
        $('ul.folder', $feeds).css({
            'display': 'block',
            'opacity': 1
        });

        $('.unread_count_positive', $feeds).text('On');
        $('.unread_count_negative', $feeds).text('Off');

        return $feeds;
    },

    open_modal: function() {
        var self = this;

        this.$modal.modal({
            'minWidth': 600,
            'maxWidth': 600,
            'overlayClose': true,
            'onOpen': function (dialog) {
                dialog.overlay.fadeIn(200, function () {
                    dialog.container.fadeIn(200);
                    dialog.data.fadeIn(200);
                });
            },
            'onShow': function(dialog) {
                $('#simplemodal-container').corner('6px');
            },
            'onClose': function(dialog) {
                dialog.data.hide().empty().remove();
                dialog.container.hide().empty().remove();
                dialog.overlay.fadeOut(200, function() {
                    dialog.overlay.empty().remove();
                    $.modal.close();
                });
                $('.NB-modal-holder').empty().remove();
            }
        });
    },

    add_feed_to_decline: function(feed_id, update) {
        this.approve_list = _.without(this.approve_list, feed_id);
        var $feed = this.$feeds[feed_id];

        $feed.removeClass('NB-feedchooser-approve');
        $feed.addClass('NB-feedchooser-decline');
        if (update) {
            this.update_counts();
        }
    },

    add_feed_to_approve: function(feed_id, update) {
        if (!_.contains(this.approve_list, feed_id)) {
            this.approve_list.push(feed_id);
            var $feed = this.$feeds[feed_id];
            $feed.removeClass('NB-feedchooser-decline');
            $feed.addClass('NB-feedchooser-approve');
            if (update) {
                this.update_counts();
            }
        }
    },

    find_feeds_in_feed_list: function() {
        var $feed_list = $('.NB-feedchooser', this.$modal);
        var $feeds = {};

        $('.feed', $feed_list).each(function() {
            var feed_id = $(this).data('feed_id');
            if (!_.contains(_.keys($feeds), feed_id)) {
                $feeds[feed_id] = $([]);
            }
            $feeds[feed_id].push($(this).get(0));
        });

        this.$feeds = $feeds;
    },

    update_counts: function() {
        var $count = $('.NB-feedchooser-info-counts');
        var approved = this.approve_list.length;
        var $submit = $('.NB-modal-submit-save', this.$modal);
        var difference = approved - this.MAX_FEEDS;

        $count.text(approved + '/' + this.MAX_FEEDS);
        $count.toggleClass('NB-full', approved == this.MAX_FEEDS);
        $count.toggleClass('NB-error', approved > this.MAX_FEEDS);

        if (approved > this.MAX_FEEDS) {
          $submit.addClass('NB-disabled').attr('disabled', true).val('Too many sites! Deselect ' + (
            difference == 1 ?
            '1 site...' :
            difference + ' sites...'
          ));
        } else {
          $submit.removeClass('NB-disabled').attr('disabled', false).val('OK, These are my ' + approved + '. Save them, please!');
        }
    },

    initial_load_feeds: function() {
        var start = new Date();
        var self = this;
        var $feeds = $('.feed', this.$modal);
        var feeds = this.model.get_feeds();

        var active_feeds = _.any(_.pluck(feeds, 'active'));
        if (!active_feeds) {
            // Get feed subscribers
            var min_subscribers = _.last(
              _.first(
                _.pluck(this.model.get_feeds(), 'subs').sort(function(a,b) {
                  return b-a;
                }),
                this.MAX_FEEDS
              )
            );

            // Decline everything
            var approve_feeds = [];
            _.each(feeds, function(feed, feed_id) {
                self.add_feed_to_decline(parseInt(feed_id, 10));

                if (feed['subs'] >= min_subscribers) {
                    approve_feeds.push(parseInt(feed_id, 10));
                }
            });

            // Approve feeds in subs
            _.each(approve_feeds, function(feed_id) {
                if (self.model.get_feed(feed_id)['subs'] > min_subscribers &&
                    self.approve_list.length < self.MAX_FEEDS) {
                    self.add_feed_to_approve(feed_id);
                }
            });
            _.each(approve_feeds, function(feed_id) {
                if (self.model.get_feed(feed_id)['subs'] == min_subscribers &&
                    self.approve_list.length < self.MAX_FEEDS) {
                    self.add_feed_to_approve(feed_id);
                }
            });
        } else {
            // Get active feeds
            var active_feeds = _.pluck(_.select(feeds, function(feed) {
                if (feed.active) return true;
            }), 'id');
            this.approve_list = active_feeds;

            // Approve or decline
            var feeds = [];
            $feeds.each(function() {
                var feed_id = $(this).data('feed_id');

                if (_.contains(active_feeds, feed_id)) {
                    self.add_feed_to_approve(feed_id);
                } else {
                    self.add_feed_to_decline(feed_id);
                }
            });
        }
        this.update_counts();
    },

    save: function() {
        var $submit = $('.NB-modal-submit-save', this.$modal);
        $submit.addClass('NB-disabled').val('Saving...');

        this.model.save_feed_chooser(this.approve_list, function() {
            NEWSBLUR.reader.load_feeds();
            $.modal.close();
        });
    },

    // ===========
    // = Actions =
    // ===========

    handle_click: function(elem, e) {
        var self = this;

        $.targetIs(e, { tagSelector: '.feed' }, _.bind(function($t, $p) {
            e.preventDefault();

            var feed_id = $t.data('feed_id');
            if (_.contains(this.approve_list, feed_id)) {
                this.add_feed_to_decline(feed_id, true);
            } else {
                this.add_feed_to_approve(feed_id, true);
            }
        }, this));

        $.targetIs(e, { tagSelector: '.NB-modal-submit-save' }, _.bind(function($t, $p) {
            e.preventDefault();
            this.save();
        }, this));
    },

    handle_cancel: function() {
        var $cancel = $('.NB-modal-cancel', this.$modal);

        $cancel.click(function(e) {
            e.preventDefault();
            $.modal.close();
        });
    }

};<|endoftext|>


<commit_before>/*
 *
 * DXFExport.js -- part of QGIS Web Client
 *
 * Copyright (2010-2015), The QGIS Project All rights reserved.
 * Quantum GIS Web Client is released under a BSD license. Please see
 * https://github.com/qgis/qgis-web-client/blob/master/README
 * for the full text of the license and the list of contributors.
 *
*/

//note that DXF Export depends on whether a layer is exposed as WFS. Layers that are not exposes as WFS are not exported as DXF
function DXFExporter(parentPanel) {
		// disclaimer window for dxf export
		this.parentPanel = parentPanel;
		myExp = this;
		this.DXFExportDisclaimerWindow = new Ext.Window({
			title: DXFExportDisclaimerWindowTitle[lang],
			height: 350,
			width: 500,
			layout: {
				type:'vbox',
				align: 'stretch'
			},
			padding: 5,
			buttonAlign: 'center',
			renderTo: this.parentPanel,
			resizable: true,
			closable: false,
			x: 50,
			y: 10,
			items: [{
				xtype: 'container',
				id: 'DXFExportDisclaimerHTMLContainer',
				flex: 0.8,
				html: ''
			},
			{
				xtype: 'container',
				id: 'DXFExportDisclaimerButtons',
				flex: 0.2,
				layout: {
					type:'hbox',
					align: 'stretch'
				},
				items: [
					{
						xtype: 'button',
						id: 'acceptDXFDisclaimer',
						text: acceptDXFDisclaimerButtonText[lang],
						listeners: {
							'click': function () {
								myExp.DXFExportDisclaimerWindow.hide();
								myExp.DXFExportWindow.show();
							}
						},
						flex: 0.5
					},
					{
						xtype: 'button',
						id: 'declineDXFDisclaimer',
						text: declineDXFDisclaimerButtonText[lang],
						listeners: {
							'click': function () {
								myExp.DXFExportDisclaimerWindow.hide();
								Ext.getCmp('ExportDXF').toggle(false,false);
							}
					},
					flex: 0.5
				}]
			}]
		});
		this.DXFExportWindow = new Ext.Window({
			title: DXFExportWindowTitleString[lang],
			height: 67,
			width: 800,
			layout: "fit",
			renderTo: this.parentPanel,
			resizable: false,
			closable: false,
			x: 50,
			y: 10,
			items: [{
				tbar: {
					xtype: 'toolbar',
					autoHeight: true,
					id: 'myDXFExportToolbar',
					items: [
					{
						xtype: 'label',
						text: DXFExportSymbologyScaleLabel[lang]
					}, {
						xtype: 'tbspacer'
					},
					{
						xtype: 'combo',
						id: 'DXFExportScaleCombobox',
						width: 95,
						mode: 'local',
						forceSelection: true,
						triggerAction: 'all',
						lastQuery: '',
						store: new Ext.data.JsonStore({
							// store configs
							data: exportCapabilities,
							storeId: 'DXFExportScalesStore',
							// reader configs
							root: 'scales',
							fields: [{
								name: 'name',
								type: 'string'
							}, {
								name: 'value',
								type: 'int'
							}]
						}),
						listeners: {
							change: function(combo, record, index) {
								//combo.lastQuery = '';
							}
						},
						valueField: 'value',
						displayField: 'name'
					},
					{
						xtype: 'tbspacer'
					}, {
						xtype: 'tbseparator',
					}, {
						xtype: 'tbspacer'
					}, {
						xtype: 'label',
						id: 'DXFExportAreaLimitLabel',
						text: DXFExportAreaLimitLabel[lang]
					}, {
						xtype: 'label',
						id: 'DXFExportCurrentAreaLabel',
						text: ", "+DXFExportCurrentAreaLabel[lang] + "xxx m2"
					}, {
						xtype: 'tbseparator',
					}, {
						xtype: 'tbspacer'
					}, {
						xtype: 'button',
						tooltip: exportButtonTooltipString[lang],
						text: exportButtonTextString[lang],
						tooltipType: 'qtip',
						iconCls: '',
						scale: 'medium',
						id: 'DXFStartExporting',
						listeners: {
							'click': function () {
								Ext.getCmp('ExportDXF').toggle(false);
								//now need to build the correct URL
								var today = new Date().toJSON().split('T')[0];
								var getDXFURL = wmsURI + "SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMAP&FORMAT=application/dxf&FORMAT_OPTIONS=SCALE:"+Ext.getCmp('DXFExportScaleCombobox').getValue()+";MODE:SYMBOLLAYERSYMBOLOGY&FILE_NAME=";
								//add prefix to file_name
								if (gis_projects) {
									if (gis_projects.DXFExportPrefix) {
										getDXFURL += gis_projects.DXFExportPrefix;
									}
								}
								//add projectname to filename
								if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
									getDXFURL += mapThemeSwitcher.activeProjectData.projectfile + "_";
								}
								//add date to filename
								getDXFURL += today+".dxf&CRS=EPSG:"+authid+"&BBOX="+geoExtMap.map.getExtent().toString()+"&WIDTH="+geoExtMap.map.getSize().w+"&HEIGHT="+geoExtMap.map.getSize().h+"&LAYERS=";
								//check if we need to enable additional layers
								var DXFExportLayers = thematicLayer.params.LAYERS;
								if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
									if (mapThemeSwitcher.activeProjectData.DXFExportForcedLayers) {
										var DXFExportForcedLayers = mapThemeSwitcher.activeProjectData.DXFExportForcedLayers.split(",");
										for (var i=0; i < DXFExportForcedLayers.length; i++) {
											if (!DXFExportLayers.match(/DXFExportForcedLayers[i]/)) {
												//add layer before other layers
												DXFExportLayers = DXFExportForcedLayers[i]+","+DXFExportLayers;
											}
										}
									}
								}
								getDXFURL += encodeURIComponent(DXFExportLayers);
								//console.log(getDXFURL);
								window.location.href = getDXFURL;
							}
						}
					}, {
						xtype: 'button',
						tooltip: exportCancelButtonTooltipString[lang],
						text: printCancelButtonTextString[lang],
						tooltipType: 'qtip',
						iconCls: '',
						scale: 'medium',
						id: 'DXFCancelExporting',
						listeners: {
							'click': function () {
								Ext.getCmp('ExportDXF').toggle(false);
							}
						}
					}]
				}
			}]
		});
}

//test if DXF export should be enabled/disabled
DXFExporter.prototype.checkEnabled = function() {
	if (typeof(enableDXFExport) !== 'undefined') {
		if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher) !== 'undefined') {
			if (mapThemeSwitcher.activeProjectData !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
				if (mapThemeSwitcher.activeProjectData.enableDXFExport === undefined) {
					//if not defined on project level use the global option
					if (enableDXFExport == true) {
						Ext.getCmp('ExportDXF').show();
					}
					else {
						Ext.getCmp('ExportDXF').hide();
					}
				}
				else {
					if (mapThemeSwitcher.activeProjectData.enableDXFExport == true) {
						Ext.getCmp('ExportDXF').show();
					}
					if (mapThemeSwitcher.activeProjectData.enableDXFExport == false) {
						Ext.getCmp('ExportDXF').hide();
					}
				}
			}
			//global setting overrides everything if it is disabled, also project level can't override it
			if (enableDXFExport == false) {
				Ext.getCmp('ExportDXF').hide();
			}
		}
	}
	else {
		Ext.getCmp('ExportDXF').hide();
	}
}

//start the export process
DXFExporter.prototype.startDXFExport = function () {
	//test if we first need to start with a disclaimer
	var showDXFExportDisclaimer = false;
	if (gis_projects) {
		if (gis_projects.DXFExportDownloadDisclaimer) {
			Ext.getCmp('DXFExportDisclaimerHTMLContainer').update(gis_projects.DXFExportDownloadDisclaimer);
			showDXFExportDisclaimer = true;
		}
	}
	if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
		if (mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer) {
			if (mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer.length > 1) {
				Ext.getCmp('DXFExportDisclaimerHTMLContainer').update(mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer);
				showDXFExportDisclaimer = true;
			}
		}
		if (mapThemeSwitcher.activeProjectData.DXFExportMaxArea) {
			Ext.getCmp('DXFExportAreaLimitLabel').update(DXFExportAreaLimitLabel[lang] + parseInt(mapThemeSwitcher.activeProjectData.DXFExportMaxArea).toLocaleString() + " m2");
		}
		else {
			Ext.getCmp('DXFExportAreaLimitLabel').update(DXFExportAreaLimitLabel[lang] + DXFExportNoAreaLimitLabel[lang]);
		}
		//need to register navigate events to keep current DXF export size up-to-date
		geoExtMap.map.events.register("moveend",geoExtMap.map,this.updateCurrentArea);
		this.updateCurrentArea();
	}
	//deal with dxf export scale limits
	var scaleCombobox = Ext.getCmp('DXFExportScaleCombobox');
	var scaleDataStore = scaleCombobox.getStore();
	if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
		if (mapThemeSwitcher.activeProjectData.DXFExportDefaultScale) {
			scaleCombobox.setValue(mapThemeSwitcher.activeProjectData.DXFExportDefaultScale);
		}
		else {
			scaleCombobox.setValue(scaleDataStore.getAt(0).data.value);
		}
		if (mapThemeSwitcher.activeProjectData.DXFExportMaxScale) {
			scaleDataStore.clearFilter(false);
			scaleDataStore.filter([{
				fn: function(record) {
					if (record.get("value") <= mapThemeSwitcher.activeProjectData.DXFExportMaxScale)
						return true;
					else
						return false;
					}
			}]);
		}
		else {
			scaleDataStore.clearFilter(false);
		}
	}
	else {
		//scaleDataStore.clearFilter(false);
		scaleCombobox.setValue(scaleDataStore.getAt(0).data.value);
	}
	//deal with or without disclaimer
	if (showDXFExportDisclaimer === true) {
		this.DXFExportDisclaimerWindow.show();
	}
	else {
		//else we can display the dxf export settings without the disclaimer
		this.DXFExportWindow.show();
	}
}
//cancel the dxf export process
DXFExporter.prototype.cancelDXFExport = function () {
	//need to unregister navigate events that updates screen area
	geoExtMap.map.events.unregister("moveend",geoExtMap.map,this.updateCurrentArea);
	this.DXFExportDisclaimerWindow.hide();
	this.DXFExportWindow.hide();
}

//updates current map area if there is a size limit
DXFExporter.prototype.updateCurrentArea = function () {
	var myDXFExportCurrentAreaLabel = Ext.getCmp("DXFExportCurrentAreaLabel");
	var DXFStartExportingButton = Ext.getCmp("DXFStartExporting");
	myDXFExportCurrentAreaLabel.update(", "+DXFExportCurrentAreaLabel[lang] + Math.round(geoExtMap.map.getExtent().getWidth() * geoExtMap.map.getExtent().getHeight()).toLocaleString() + " m2");
	if ((geoExtMap.map.getExtent().getWidth() * geoExtMap.map.getExtent().getHeight()) > mapThemeSwitcher.activeProjectData.DXFExportMaxArea) {
		myDXFExportCurrentAreaLabel.addClass("DXFExportCurrentAreaLabel");
		DXFStartExportingButton.disable();
	}
	else {
		myDXFExportCurrentAreaLabel.removeClass("DXFExportCurrentAreaLabel");
		DXFStartExportingButton.enable("DXFStartExportingButton");
	}
}
<commit_msg>Update DXFExport.js<commit_after>/*
 *
 * DXFExport.js -- part of QGIS Web Client
 *
 * Copyright (2010-2015), The QGIS Project All rights reserved.
 * Quantum GIS Web Client is released under a BSD license. Please see
 * https://github.com/qgis/qgis-web-client/blob/master/README
 * for the full text of the license and the list of contributors.
 *
*/

//note that DXF Export depends on whether a layer is exposed as WFS. Layers that are not exposes as WFS are not exported as DXF
function DXFExporter(parentPanel) {
		// disclaimer window for dxf export
		this.parentPanel = parentPanel;
		myExp = this;
		this.DXFExportDisclaimerWindow = new Ext.Window({
			title: DXFExportDisclaimerWindowTitle[lang],
			height: 350,
			width: 500,
			layout: {
				type:'vbox',
				align: 'stretch'
			},
			padding: 5,
			buttonAlign: 'center',
			renderTo: this.parentPanel,
			resizable: true,
			closable: false,
			x: 50,
			y: 10,
			items: [{
				xtype: 'container',
				id: 'DXFExportDisclaimerHTMLContainer',
				flex: 0.8,
				html: ''
			},
			{
				xtype: 'container',
				id: 'DXFExportDisclaimerButtons',
				flex: 0.2,
				layout: {
					type:'hbox',
					align: 'stretch'
				},
				items: [
					{
						xtype: 'button',
						id: 'acceptDXFDisclaimer',
						text: acceptDXFDisclaimerButtonText[lang],
						listeners: {
							'click': function () {
								myExp.DXFExportDisclaimerWindow.hide();
								myExp.DXFExportWindow.show();
							}
						},
						flex: 0.5
					},
					{
						xtype: 'button',
						id: 'declineDXFDisclaimer',
						text: declineDXFDisclaimerButtonText[lang],
						listeners: {
							'click': function () {
								myExp.DXFExportDisclaimerWindow.hide();
								Ext.getCmp('ExportDXF').toggle(false,false);
							}
					},
					flex: 0.5
				}]
			}]
		});
		this.DXFExportWindow = new Ext.Window({
			title: DXFExportWindowTitleString[lang],
			height: 67,
			width: 800,
			layout: "fit",
			renderTo: this.parentPanel,
			resizable: false,
			closable: false,
			x: 50,
			y: 10,
			items: [{
				tbar: {
					xtype: 'toolbar',
					autoHeight: true,
					id: 'myDXFExportToolbar',
					items: [
					{
						xtype: 'label',
						text: DXFExportSymbologyScaleLabel[lang]
					}, {
						xtype: 'tbspacer'
					},
					{
						xtype: 'combo',
						id: 'DXFExportScaleCombobox',
						width: 95,
						mode: 'local',
						forceSelection: true,
						triggerAction: 'all',
						lastQuery: '',
						store: new Ext.data.JsonStore({
							// store configs
							data: exportCapabilities,
							storeId: 'DXFExportScalesStore',
							// reader configs
							root: 'scales',
							fields: [{
								name: 'name',
								type: 'string'
							}, {
								name: 'value',
								type: 'int'
							}]
						}),
						listeners: {
							change: function(combo, record, index) {
								//combo.lastQuery = '';
							}
						},
						valueField: 'value',
						displayField: 'name'
					},
					{
						xtype: 'tbspacer'
					}, {
						xtype: 'tbseparator',
					}, {
						xtype: 'tbspacer'
					}, {
						xtype: 'label',
						id: 'DXFExportAreaLimitLabel',
						text: DXFExportAreaLimitLabel[lang]
					}, {
						xtype: 'label',
						id: 'DXFExportCurrentAreaLabel',
						text: ", "+DXFExportCurrentAreaLabel[lang] + "xxx m2"
					}, {
						xtype: 'tbseparator',
					}, {
						xtype: 'tbspacer'
					}, {
						xtype: 'button',
						tooltip: exportButtonTooltipString[lang],
						text: exportButtonTextString[lang],
						tooltipType: 'qtip',
						iconCls: '',
						scale: 'medium',
						id: 'DXFStartExporting',
						listeners: {
							'click': function () {
								Ext.getCmp('ExportDXF').toggle(false);
								//now need to build the correct URL
								var today = new Date().toJSON().split('T')[0];
								var getDXFURL = wmsURI + "SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMAP&FORMAT=application/dxf&FORMAT_OPTIONS=SCALE:"+Ext.getCmp('DXFExportScaleCombobox').getValue()+";MODE:SYMBOLLAYERSYMBOLOGY&FILE_NAME=";
								//add prefix to file_name
								if (gis_projects) {
									if (gis_projects.DXFExportPrefix) {
										getDXFURL += gis_projects.DXFExportPrefix;
									}
								}
								//add projectname to filename
								if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
									getDXFURL += mapThemeSwitcher.activeProjectData.projectfile + "_";
								}
								//add date to filename
								getDXFURL += today+".dxf&CRS=EPSG:"+authid+"&BBOX="+geoExtMap.map.getExtent().toString()+"&WIDTH="+geoExtMap.map.getSize().w+"&HEIGHT="+geoExtMap.map.getSize().h+"&LAYERS=";
								//check if we need to enable additional layers
								var DXFExportLayers = thematicLayer.params.LAYERS;
								if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
									if (mapThemeSwitcher.activeProjectData.DXFExportForcedLayers) {
										var DXFExportForcedLayers = mapThemeSwitcher.activeProjectData.DXFExportForcedLayers.split(",");
										for (var i=0; i < DXFExportForcedLayers.length; i++) {
											if (!DXFExportLayers.match(/DXFExportForcedLayers[i]/)) {
												//add layer before other layers
												DXFExportLayers = DXFExportForcedLayers[i]+","+DXFExportLayers;
											}
										}
									}
								}
								getDXFURL += encodeURIComponent(DXFExportLayers);
								//console.log(getDXFURL);
								window.location.href = getDXFURL;
							}
						}
					}, {
						xtype: 'button',
						tooltip: exportCancelButtonTooltipString[lang],
						text: printCancelButtonTextString[lang],
						tooltipType: 'qtip',
						iconCls: '',
						scale: 'medium',
						id: 'DXFCancelExporting',
						listeners: {
							'click': function () {
								Ext.getCmp('ExportDXF').toggle(false);
							}
						}
					}]
				}
			}]
		});
}

//test if DXF export should be enabled/disabled
DXFExporter.prototype.checkEnabled = function() {
	if (typeof(enableDXFExport) !== 'undefined') {
		if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher) !== 'undefined') {
			if (mapThemeSwitcher.activeProjectData !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
				if (mapThemeSwitcher.activeProjectData.enableDXFExport === 'undefined') {
					//if not defined on project level use the global option
					if (enableDXFExport == true) {
						Ext.getCmp('ExportDXF').show();
					}
					else {
						Ext.getCmp('ExportDXF').hide();
					}
				}
				else {
					if (mapThemeSwitcher.activeProjectData.enableDXFExport == true) {
						Ext.getCmp('ExportDXF').show();
					}
					if (mapThemeSwitcher.activeProjectData.enableDXFExport == false) {
						Ext.getCmp('ExportDXF').hide();
					}
				}
			}
			//global setting overrides everything if it is disabled, also project level can't override it
			if (enableDXFExport == false) {
				Ext.getCmp('ExportDXF').hide();
			}
		}
	}
	else {
		Ext.getCmp('ExportDXF').hide();
	}
}

//start the export process
DXFExporter.prototype.startDXFExport = function () {
	//test if we first need to start with a disclaimer
	var showDXFExportDisclaimer = false;
	if (gis_projects) {
		if (gis_projects.DXFExportDownloadDisclaimer) {
			Ext.getCmp('DXFExportDisclaimerHTMLContainer').update(gis_projects.DXFExportDownloadDisclaimer);
			showDXFExportDisclaimer = true;
		}
	}
	if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
		if (mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer) {
			if (mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer.length > 1) {
				Ext.getCmp('DXFExportDisclaimerHTMLContainer').update(mapThemeSwitcher.activeProjectData.DXFExportDownloadDisclaimer);
				showDXFExportDisclaimer = true;
			}
		}
		if (mapThemeSwitcher.activeProjectData.DXFExportMaxArea) {
			Ext.getCmp('DXFExportAreaLimitLabel').update(DXFExportAreaLimitLabel[lang] + parseInt(mapThemeSwitcher.activeProjectData.DXFExportMaxArea).toLocaleString() + " m2");
		}
		else {
			Ext.getCmp('DXFExportAreaLimitLabel').update(DXFExportAreaLimitLabel[lang] + DXFExportNoAreaLimitLabel[lang]);
		}
		//need to register navigate events to keep current DXF export size up-to-date
		geoExtMap.map.events.register("moveend",geoExtMap.map,this.updateCurrentArea);
		this.updateCurrentArea();
	}
	//deal with dxf export scale limits
	var scaleCombobox = Ext.getCmp('DXFExportScaleCombobox');
	var scaleDataStore = scaleCombobox.getStore();
	if (mapThemeSwitcher !== null && typeof(mapThemeSwitcher.activeProjectData) !== 'undefined') {
		if (mapThemeSwitcher.activeProjectData.DXFExportDefaultScale) {
			scaleCombobox.setValue(mapThemeSwitcher.activeProjectData.DXFExportDefaultScale);
		}
		else {
			scaleCombobox.setValue(scaleDataStore.getAt(0).data.value);
		}
		if (mapThemeSwitcher.activeProjectData.DXFExportMaxScale) {
			scaleDataStore.clearFilter(false);
			scaleDataStore.filter([{
				fn: function(record) {
					if (record.get("value") <= mapThemeSwitcher.activeProjectData.DXFExportMaxScale)
						return true;
					else
						return false;
					}
			}]);
		}
		else {
			scaleDataStore.clearFilter(false);
		}
	}
	else {
		//scaleDataStore.clearFilter(false);
		scaleCombobox.setValue(scaleDataStore.getAt(0).data.value);
	}
	//deal with or without disclaimer
	if (showDXFExportDisclaimer === true) {
		this.DXFExportDisclaimerWindow.show();
	}
	else {
		//else we can display the dxf export settings without the disclaimer
		this.DXFExportWindow.show();
	}
}
//cancel the dxf export process
DXFExporter.prototype.cancelDXFExport = function () {
	//need to unregister navigate events that updates screen area
	geoExtMap.map.events.unregister("moveend",geoExtMap.map,this.updateCurrentArea);
	this.DXFExportDisclaimerWindow.hide();
	this.DXFExportWindow.hide();
}

//updates current map area if there is a size limit
DXFExporter.prototype.updateCurrentArea = function () {
	var myDXFExportCurrentAreaLabel = Ext.getCmp("DXFExportCurrentAreaLabel");
	var DXFStartExportingButton = Ext.getCmp("DXFStartExporting");
	myDXFExportCurrentAreaLabel.update(", "+DXFExportCurrentAreaLabel[lang] + Math.round(geoExtMap.map.getExtent().getWidth() * geoExtMap.map.getExtent().getHeight()).toLocaleString() + " m2");
	if ((geoExtMap.map.getExtent().getWidth() * geoExtMap.map.getExtent().getHeight()) > mapThemeSwitcher.activeProjectData.DXFExportMaxArea) {
		myDXFExportCurrentAreaLabel.addClass("DXFExportCurrentAreaLabel");
		DXFStartExportingButton.disable();
	}
	else {
		myDXFExportCurrentAreaLabel.removeClass("DXFExportCurrentAreaLabel");
		DXFStartExportingButton.enable("DXFStartExportingButton");
	}
}
<|endoftext|>


<commit_before>import React, {useState, useEffect} from 'react';
import {Button, Modal, Tabs, Tab} from 'react-bootstrap';
import PropTypes from 'prop-types';
import './CodeModal.css';
import Prism from 'prismjs';
import '../../vendor/prism.css';

CodeModal.propTypes = {
  popupId: PropTypes.string,
  ourCode: PropTypes.string,
  gtagCode: PropTypes.string,
};
/**
 * A popup to display the google analytics code that fires on
 * a button click.
 * @param {string} popupId The ID of this popup.
 * @param {string} ourCode The code for this open source library
 * @param {string} gtagCode The code for gtag
 * @return {!JSX} This component
 */
export function CodeModal({popupId, ourCode, gtagCode}) {
  const [showing, setShowing] = useState(false);
  useEffect(()=> {
    Prism.highlightAll();
  });

  const modal = <Modal show={showing} onHide={()=>setShowing(false)}>
    <Tabs defaultActiveKey='internJunk' id={popupId}>
      <Tab eventKey='internJunk' title='What we are making'>

            {ourCode}

      </Tab>
      <Tab eventKey='gtag' title='gtag.js'>

            {gtagCode}

      </Tab>
    </Tabs>
  </Modal>;

  return (<>
    <Button onClick={()=>setShowing(true)}>Display Modal</Button>
    {modal}
  </>);
}
<commit_msg>Add whitespace and comments<commit_after>import React, {useState, useEffect} from 'react';
import {Button, Modal, Tabs, Tab} from 'react-bootstrap';
import PropTypes from 'prop-types';
import './CodeModal.css';
import Prism from 'prismjs';
import '../../vendor/prism.css';

CodeModal.propTypes = {
  popupId: PropTypes.string,
  ourCode: PropTypes.string,
  gtagCode: PropTypes.string,
};

/**
 * A popup to display the google analytics code that fires on
 * a button click.
 * @param {string} popupId The ID of this popup.
 * @param {string} ourCode The code for this open source library.
 * @param {string} gtagCode The code for gtag.
 * @return {!JSX} The component.
 */
export function CodeModal({popupId, ourCode, gtagCode}) {
  const [showing, setShowing] = useState(false);

  // Highlight the code in the modal after the page renders
  useEffect(()=> {
    Prism.highlightAll();
  });

  const modal = <Modal show={showing} onHide={()=>setShowing(false)}>
    <Tabs defaultActiveKey='internJunk' id={popupId}>
      <Tab eventKey='internJunk' title='What we are making'>

            {ourCode}

      </Tab>
      <Tab eventKey='gtag' title='gtag.js'>

            {gtagCode}

      </Tab>
    </Tabs>
  </Modal>;

  return (<>
    <Button onClick={()=>setShowing(true)}>Display Modal</Button>
    {modal}
  </>);
}
<|endoftext|>


<commit_before>function WeightedMean() {
    WeightedMean.DEFAULT_REJECTION_RANGE = 0;
    WeightedMean.MAX_CONV_ATTEMPS = 100;
    WeightedMean.DISPERSION = {
        UNDER_DISPERSION : "under dispersion",
        OVER_DISPERSION  : "over dispersion",
        SINGLE_POPULATION: "single population"
    };

    WeightedMean.weightedMean = function(values, uncertainties) {
        if (values.length !== uncertainties.length)
            throw "The length of values and uncertainties must be equal!";
        if (values.length === 0)
            throw "The length of values cannot be zero for weighted uncertainty calculation!";

        var A, B;
        A = B = 0;

        for (var i = 0; i < values.length; ++i) {
            var p = Math.pow(uncertainties[i], 2);
            A += values[i] / p;
            B += 1 / p;
        }//for

        return A / B;
    };

    WeightedMean.weightedUncertainty = function(uncertainties) {
        if (uncertainties.length === 0)
            throw "The length of uncertainties cannot be zero for weighted uncertainty calculation!";

        var result = 0;
        for (var i = 0; i < uncertainties.length; ++i)
            result += 1 / Math.pow(uncertainties[i], 2);

        result = Math.sqrt(1 / result);
        return result;
    };

    WeightedMean.meanSquareWeightedDeviation = function(values, uncertainties) {
        if (values.length !== uncertainties.length)
            throw "The number of values and uncertainties must be equal!";
        if (values.length < 2)
            throw "The number of not rejected values must be greater than 1. " +
            "The weighted mean value cannot be calculated!";

        var mean = WeightedMean.weightedMean(values, uncertainties);
        var A = 0;
        var B = values.length - 1;

        for (var i = 0; i < values.length; ++i) {
            A += Math.pow(values[i] - mean, 2) / Math.pow(uncertainties[i], 2);
        }//for

        return A / B;
    };

    WeightedMean.intersect = function(value, uncertainty, weightedMean, weightedUncertainty, rejectionRange) {
        rejectionRange = (isNaN(rejectionRange)) ? WeightedMean.DEFAULT_REJECTION_RANGE : rejectionRange;

        var b0 = Math.min(
            value - rejectionRange * uncertainty,
            value + rejectionRange * uncertainty);

        var b1 = Math.max(
            value - rejectionRange * uncertainty,
            value + rejectionRange * uncertainty);

        var lower = Math.min(
            weightedMean - 2 * weightedUncertainty,
            weightedMean + 2 * weightedUncertainty);

        var upper = Math.max(
            weightedMean - 2 * weightedUncertainty,
            weightedMean + 2 * weightedUncertainty);

        var result = (b0 <= upper) && (lower <= b1);

        return result;
    };

    WeightedMean.rejectedIndices = function(values, uncertainties, weightedMean, weightedUncertainty) {
        var indices = [];

        for (var i = 0; i < values.length; ++i) {
            if (!WeightedMean.intersect(values[i], uncertainties[i], weightedMean, weightedUncertainty, 2)) {
                indices.push(i);
            }//if
        }//for

        return indices;
    };

    WeightedMean.rejected = function(values, uncertainties, weightedMean, weightedUncertainty) {
        return WeightedMean.rejectedIndices(values, uncertainties, weightedMean, weightedUncertainty).length;
    };

    WeightedMean.removeRejected = function(values, uncertainties, weightedMean, weightedUncertainty, rejectionRange) {
        for (var i = 0; i < values.length; ++i) {
            if (!WeightedMean.intersect(values[i], uncertainties[i], weightedMean, weightedUncertainty, rejectionRange)) {
                values.splice(i, 1);
                uncertainties.splice(i, 1);
                --i;
            }//if
        }//for
    };

    WeightedMean.dispersion = function(n, mswd) {
        var result = WeightedMean.DISPERSION.SINGLE_POPULATION;

        if (mswd < (1 - 2 * Math.sqrt(2 / (n - 1)))) {
            result = WeightedMean.DISPERSION.UNDER_DISPERSION;
        }//if
        else if (mswd > (1 + 2 * Math.sqrt(2 / (n - 1)))) {
            result = WeightedMean.DISPERSION.OVER_DISPERSION;
        }//else if

        return result;
    };

    WeightedMean.converge = function(values, uncertainties, rejectionRange, wm, wu, attempts, converged) {
        if (converged || attempts === 0) {
            var mswd = WeightedMean.meanSquareWeightedDeviation(values, uncertainties);
            return {
                converged: converged,
                weightedMean: wm,
                weightedUncertainty: wu,
                mswd: mswd,
                rejected: WeightedMean.rejected(values, uncertainties, wm, wu),
                rejectedIndices: WeightedMean.rejectedIndices(values, uncertainties, wm, wu),
                dispersion: WeightedMean.dispersion(values.length, mswd)
            };
        }//if

        var vl2 = values.slice();
        var un2 = uncertainties.slice();
        WeightedMean.removeRejected(vl2, un2, wm, wu, rejectionRange);
        var wm2 = WeightedMean.weightedMean(vl2, un2);
        var wu2 = WeightedMean.weightedUncertainty(un2);

        var ri1 = WeightedMean.rejectedIndices(values, uncertainties, wm, wu);
        var ri2 = WeightedMean.rejectedIndices(values, uncertainties, wm2, wu2);

        converged = Util.areArraysSame(ri1, ri2);

        return WeightedMean.converge(values, uncertainties, rejectionRange, wm2, wu2, attempts - 1, converged);
    };

    WeightedMean.calculate = function(values, uncertainties, rejectionRange) {
        rejectionRange = (isNaN(rejectionRange)) ? WeightedMean.DEFAULT_REJECTION_RANGE : rejectionRange;

        var result = {};
        if(rejectionRange === 0) {
            var mswd = WeightedMean.meanSquareWeightedDeviation(values, uncertainties);
            result = {
                converged: true,
                weightedMean: WeightedMean.weightedMean(values, uncertainties),
                weightedUncertainty: WeightedMean.weightedUncertainty(uncertainties),
                mswd: mswd,
                rejected: 0,
                rejectedIndices: [],
                dispersion: WeightedMean.dispersion(values.length, mswd)
            }
        }//if
        else {
            var wm = WeightedMean.weightedMean(values, uncertainties);
            var wu = WeightedMean.weightedUncertainty(uncertainties);

            result = WeightedMean.converge(
                values, uncertainties, rejectionRange,
                wm,
                wu,
                WeightedMean.MAX_CONV_ATTEMPS, false);
        }//else

        return result;
    };
}

WeightedMean();<commit_msg>MSWD is calculated correctly when there is rejection.<commit_after>function WeightedMean() {
    WeightedMean.DEFAULT_REJECTION_RANGE = 0;
    WeightedMean.MAX_CONV_ATTEMPS = 100;
    WeightedMean.DISPERSION = {
        UNDER_DISPERSION : "under dispersion",
        OVER_DISPERSION  : "over dispersion",
        SINGLE_POPULATION: "single population"
    };

    WeightedMean.weightedMean = function(values, uncertainties) {
        if (values.length !== uncertainties.length)
            throw "The length of values and uncertainties must be equal!";
        if (values.length === 0)
            throw "The length of values cannot be zero for weighted uncertainty calculation!";

        var A, B;
        A = B = 0;

        for (var i = 0; i < values.length; ++i) {
            var p = Math.pow(uncertainties[i], 2);
            A += values[i] / p;
            B += 1 / p;
        }//for

        return A / B;
    };

    WeightedMean.weightedUncertainty = function(uncertainties) {
        if (uncertainties.length === 0)
            throw "The length of uncertainties cannot be zero for weighted uncertainty calculation!";

        var result = 0;
        for (var i = 0; i < uncertainties.length; ++i)
            result += 1 / Math.pow(uncertainties[i], 2);

        result = Math.sqrt(1 / result);
        return result;
    };

    WeightedMean.meanSquareWeightedDeviation = function(values, uncertainties) {
        if (values.length !== uncertainties.length)
            throw "The number of values and uncertainties must be equal!";
        if (values.length < 2)
            throw "The number of not rejected values must be greater than 1. " +
            "The weighted mean value cannot be calculated!";

        var mean = WeightedMean.weightedMean(values, uncertainties);
        var A = 0;
        var B = values.length - 1;

        for (var i = 0; i < values.length; ++i) {
            A += Math.pow(values[i] - mean, 2) / Math.pow(uncertainties[i], 2);
        }//for

        return A / B;
    };

    WeightedMean.intersect = function(value, uncertainty, weightedMean, weightedUncertainty, rejectionRange) {
        rejectionRange = (isNaN(rejectionRange)) ? WeightedMean.DEFAULT_REJECTION_RANGE : rejectionRange;

        var b0 = Math.min(
            value - rejectionRange * uncertainty,
            value + rejectionRange * uncertainty);

        var b1 = Math.max(
            value - rejectionRange * uncertainty,
            value + rejectionRange * uncertainty);

        var lower = Math.min(
            weightedMean - 2 * weightedUncertainty,
            weightedMean + 2 * weightedUncertainty);

        var upper = Math.max(
            weightedMean - 2 * weightedUncertainty,
            weightedMean + 2 * weightedUncertainty);

        return (b0 <= upper) && (lower <= b1);;
    };

    WeightedMean.rejectedIndices = function(values, uncertainties, weightedMean, weightedUncertainty) {
        var indices = [];

        for (var i = 0; i < values.length; ++i) {
            if (!WeightedMean.intersect(values[i], uncertainties[i], weightedMean, weightedUncertainty, 2)) {
                indices.push(i);
            }//if
        }//for

        return indices;
    };

    WeightedMean.rejected = function(values, uncertainties, weightedMean, weightedUncertainty) {
        return WeightedMean.rejectedIndices(values, uncertainties, weightedMean, weightedUncertainty).length;
    };

    WeightedMean.removeRejected = function(values, uncertainties, weightedMean, weightedUncertainty, rejectionRange) {
        for (var i = 0; i < values.length; ++i) {
            if (!WeightedMean.intersect(values[i], uncertainties[i], weightedMean, weightedUncertainty, rejectionRange)) {
                values.splice(i, 1);
                uncertainties.splice(i, 1);
                --i;
            }//if
        }//for
    };

    WeightedMean.dispersion = function(n, mswd) {
        var result = WeightedMean.DISPERSION.SINGLE_POPULATION;

        if (mswd < (1 - 2 * Math.sqrt(2 / (n - 1)))) {
            result = WeightedMean.DISPERSION.UNDER_DISPERSION;
        }//if
        else if (mswd > (1 + 2 * Math.sqrt(2 / (n - 1)))) {
            result = WeightedMean.DISPERSION.OVER_DISPERSION;
        }//else if

        return result;
    };

    WeightedMean.converge = function(values, uncertainties, rejectionRange, wm, wu, attempts, converged) {
        if (converged || attempts === 0) {
            var vls = values.slice();
            var unc = uncertainties.slice();
            WeightedMean.removeRejected(vls, unc, wm, wu, rejectionRange);
            var mswd = WeightedMean.meanSquareWeightedDeviation(vls, unc);

            return {
                converged: converged,
                weightedMean: wm,
                weightedUncertainty: wu,
                mswd: mswd,
                rejected: WeightedMean.rejected(values, uncertainties, wm, wu),
                rejectedIndices: WeightedMean.rejectedIndices(values, uncertainties, wm, wu),
                dispersion: WeightedMean.dispersion(values.length, mswd)
            };
        }//if

        var vl2 = values.slice();
        var un2 = uncertainties.slice();
        WeightedMean.removeRejected(vl2, un2, wm, wu, rejectionRange);
        var wm2 = WeightedMean.weightedMean(vl2, un2);
        var wu2 = WeightedMean.weightedUncertainty(un2);

        var ri1 = WeightedMean.rejectedIndices(values, uncertainties, wm, wu);
        var ri2 = WeightedMean.rejectedIndices(values, uncertainties, wm2, wu2);

        converged = Util.areArraysSame(ri1, ri2);

        return WeightedMean.converge(values, uncertainties, rejectionRange, wm2, wu2, attempts - 1, converged);
    };

    WeightedMean.calculate = function(values, uncertainties, rejectionRange) {
        rejectionRange = (isNaN(rejectionRange)) ? WeightedMean.DEFAULT_REJECTION_RANGE : rejectionRange;

        var result = {};
        if(rejectionRange === 0) {
            var mswd = WeightedMean.meanSquareWeightedDeviation(values, uncertainties);
            result = {
                converged: true,
                weightedMean: WeightedMean.weightedMean(values, uncertainties),
                weightedUncertainty: WeightedMean.weightedUncertainty(uncertainties),
                mswd: mswd,
                rejected: 0,
                rejectedIndices: [],
                dispersion: WeightedMean.dispersion(values.length, mswd)
            }
        }//if
        else {
            var wm = WeightedMean.weightedMean(values, uncertainties);
            var wu = WeightedMean.weightedUncertainty(uncertainties);

            result = WeightedMean.converge(
                values, uncertainties, rejectionRange,
                wm,
                wu,
                WeightedMean.MAX_CONV_ATTEMPS, false);
        }//else

        return result;
    };
}

WeightedMean();<|endoftext|>