<commit_before>import React from 'react';
import {without, includes, union, isNull, find} from 'lodash';

function DefaultItemComponent(props) {
	const item = props.item;
	const getItemTitle = props.getItemTitle;
	const selectedItems = props.selectedItems;
	const selected = includes(selectedItems, item);

	return (
		<div title={`${getItemTitle(item)}`}>
			<div
				className={`cpr-multi-selector-item__icon ${selected ? "cps-bg-primary-green +selected" : ""}`}>

{`${getItemTitle(item)}`}

	)
}

DefaultItemComponent.propTypes = {
	item: React.PropTypes.any.isRequired,
	getItemTitle: React.PropTypes.func,
	selectedItems: React.PropTypes.array.isRequired
};

function nearest(element, className) {
	if (!element || !element.className) return false;
	return element.className.indexOf(className) > -1 || nearest(element.parentElement, className);
}

const MultiSelector = React.createClass({
	propTypes: {
		items: React.PropTypes.array.isRequired,
		initialSelectedItems: React.PropTypes.array,
		onInputChange: React.PropTypes.func,
		onChange: React.PropTypes.func,
		getItemTitle: React.PropTypes.func,
		ItemComponent: React.PropTypes.oneOfType(
			[React.PropTypes.element, React.PropTypes.func]
		),
		placeholder: React.PropTypes.string,
		maxLength: React.PropTypes.number,
		noRestrict: React.PropTypes.bool,
		pressEnterToAddPhrase: React.PropTypes.string,
		noResultsPhrase: React.PropTypes.string,
	},

	componentWillMount: function() {
		document.addEventListener('click', this.state.close);
	},

	componentWillUnmount: function() {
		document.removeEventListener('click', this.state.close);
	},

	getInitialState: function() {
		return {
			selectedItems: this.props.initialSelectedItems || [],
			mouseIndex: null,
			mouseActive: true,
			mouseFunc: null,
			dialogDisplayed: false,
			activeIndex: null,
			searchValue: '',
			close: (e) => {
				if (!nearest(e.target, 'cpr-multi-selector')) {
					if (this.state.dialogDisplayed)
						this.props.onBlur && this.props.onBlur();
					this.setState({
						dialogDisplayed: false,
						searchValue: ''
					});
				}
			},
			invalid: false,
		}
	},

	componentWillReceiveProps(nextProps) {
		this.setState({
			selectedItems: nextProps.initialSelectedItems || []
		})
	},

	displayDialog: function(e) {
		if (!this.state.dialogDisplayed)
			this.props.onFocus && this.props.onFocus();
		this.setState({
			dialogDisplayed: true
		})
	},

	removeItem: function(item, e) {
		this.setState({
			selectedItems: without(this.state.selectedItems, item)
		});

		setTimeout(this.triggerItemChange);
	},

	getItemTitle: function(item) {
		return item.label;
	},

	setActiveIndex(index) {
		this.setState({
			activeIndex: index,
			mouseIndex: null,
		}, () => {
			if (!isNull(this.state.activeIndex) && !!this.searchItems[this.state.activeIndex]) {
				this.searchItems[this.state.activeIndex].scrollIntoView();
				if (this.state.mouseActive) {
					this.setState({
						mouseActive: false,
						mouseFunc: () => {
							this.setState({
								mouseActive: true
							})
							document.removeEventListener("mousemove", this.state.mouseFunc);
						}
					}, () => {
						document.addEventListener("mousemove", this.state.mouseFunc);
					})
				}
			}
		})
	},

	handleChange: function(e) {
		e.persist();
		if (this.state.invalid && this.props.validate) {
			this.setState({
				invalid: !this.props.validate(e.target.value),
			});
		}
		this.setState({
			disabled: this.props.disableInput ? this.props.disableInput(e.target.value) : false,
		}, () => {
			this.inputChange(e.target.value);
		});
	},

	inputChange: function(newVal) {
		this.props.onInputChange && this.props.onInputChange(newVal);

		this.setState({
			searchValue: newVal
		});
	},

	keyDown: function(e) {
		const keycode = e.which;
		const activeIndex = this.state.activeIndex;
		const filterItems = this.getFilterItems(this.props.items);

		if (isNull(activeIndex) && filterItems.length !== 0) {
			this.setActiveIndex(0);
		} else if (filterItems.length === 0) {
			this.setActiveIndex(null);
		}

		if (keycode === 13) e.preventDefault();
		if(keycode === 40) { // press down key
			if (isNull(activeIndex) && filterItems.length !== 0) {
				return this.setActiveIndex(0);
			} else {
				if(activeIndex < filterItems.length - 1) {
					return this.setActiveIndex(activeIndex + 1);
				}
			}
		} else if(keycode === 38) { // press up key
			if(!activeIndex) {
				return this.setActiveIndex(0);
			} else {
				if(activeIndex > 0) {
					return this.setActiveIndex(activeIndex - 1);
				}
			}
		} else if(keycode === 13) { // press enter key
			if(!isNull(activeIndex) && filterItems.length !==0) {
				return this.selectItem(filterItems[activeIndex], e);
			} else if(this.props.noRestrict && e.currentTarget.value) {
				// if the noRestrict prop is true it adds the input as a string to the selected items on enter
				e.persist();
				return this.validateInput(e.currentTarget.value, e);
			}
		} else if(keycode === 27) { // press escape key
			return this.setState({
				activeIndex: null,
				dialogDisplayed: false
			});
		}
	},

	triggerItemChange: function() {
		if (this.props.onChange) {
			this.props.onChange.call(null, this.state.selectedItems);
		}
	},

	getSelectedClass: function(item) {
		return includes(this.state.selectedItems, item) ? '+selected' : '';
	},

	getActiveClass: function(index) {
		return this.state.activeIndex === index || this.state.mouseIndex === index
			? '+highlighted'
			: '';
	},

	getFilterItems: function(items = []) {
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;

		return items
			.filter((item) => {
				return getItemTitle(item).toLowerCase().indexOf(this.state.searchValue.toLowerCase()) > -1;
			})
	},

	getSearchItems: function(items = []) {
		let ItemComponent = this.props.ItemComponent || DefaultItemComponent;
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;
		let filterItems = this.getFilterItems(items);

		// Show a message that user can press enter to add new item
		if (filterItems.length === 0) {
			if (this.props.noRestrict && this.state.searchValue) {
				const pressEnterToAddPhrase = this.props.pressEnterToAddPhrase || 'Press Enter to add';
				return (

{pressEnterToAddPhrase} "{this.state.searchValue}"

				)
			} else {
				const noResultsPhrase = this.props.noResultsPhrase || 'No items found.';
				return (

{noResultsPhrase}

				)
			}
		}

		// If noRestrict & the search term doesn't have an exact match, append an additional "result" for the new item
		// This is to allow adding of new items when the search term has matching filtered items but not an exact match
		if (this.props.noRestrict && this.state.searchValue
		&& !find(filterItems, (item) => getItemTitle(item).toLowerCase() === this.state.searchValue.toLowerCase())) {
			filterItems.push(this.state.searchValue);
		}

		return filterItems.map((item, index) => {
			return (

 {
						if (this.searchItems) {
							this.searchItems[index] = ref;
						} else {
							this.searchItems = [];
							this.searchItems[index] = ref;
						}
					}}
					onMouseOver={() => {
						if (this.state.mouseActive) {
							this.setState({
								mouseIndex: index
							})
						}
					}}
					className={`cpr-multi-selector-item ${this.getSelectedClass(item)} ${this.getActiveClass(index)}`}
					onClick={this.selectItem.bind(this, item)}>
					<ItemComponent item={item} selectedItems={this.state.selectedItems} getItemTitle={getItemTitle}/>

			)
		})
	},

	selectItem: function(item, e) {
		let selectedItems = this.state.selectedItems;

		if(includes(selectedItems, item)) {
			this.setState({
				selectedItems: without(selectedItems, item),
				invalid: false,
			}, this.triggerItemChange);
		} else {
			this.setState({
				selectedItems: union(selectedItems, [ item ]),
				invalid: false,
			}, this.triggerItemChange);
		}

		if (e && e.currentTarget) {
			e.currentTarget.value = '';
			this.inputChange('');
		}
	},

	validateInput: function(input, e) {
		if (this.state.disabled) return;
		if (this.props.validate) {
			const valid = this.props.validate(input);
			if (valid) this.selectItem(input, e);
			else this.setState({invalid: true});
		} else {
			this.selectItem(input, e);
		}
	},

	positionDialog: function() {
		setTimeout(() => {
			let el = this.el;
			let height = el.clientHeight;
			let dialog = el.querySelector('.cpr-multi-selector__dialog');

			if (dialog) {
				dialog.style.top = (height + 1) + 'px';
				el.querySelector('.cpr-multi-selector__dialog__input').focus();
			}
		}, 100);
	},

	prevent: function(e){
		if(e.which === 13) e.preventDefault();
	},

	render: function() {
		//Get getItemTitle is the function that should be passed in to decide what `pill` will display on selection.
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;

		let pills = this.state.selectedItems
			.map((item, i) => {
				return (
					<div key={i} className="cpr-multi-selector__pill" title={`${getItemTitle(item)}`}>

							{getItemTitle(item)}

							 {
									e.stopPropagation();
									this.removeItem(item)
								}}
								className="cps-icon cps-icon-sm-neg">

				);
			});

		let dialog;

		if (this.state.dialogDisplayed) {
			let placeholder = this.props.placeholder ? this.props.placeholder : "Type a collaborators name...";
			let maxLength = this.props.maxLength;
			dialog = (

					<div
						className={`${this.state.invalid ? "cps-has-error" : ""}`}
						style={{padding: "16px", borderBottom: "1px solid #E9E9E9"}}>
						<input
							onChange={this.handleChange}
							onKeyDown={this.keyDown}
							className={`cps-form-control cpr-multi-selector__dialog__input`}
							placeholder={placeholder}
							{...(maxLength ? {maxLength} : {})}/>
						{this.state.invalid &&
							{this.props.invalidMsg}}

						{this.getSearchItems(this.props.items)}

						{(this.state.searchValue && this.props.doneButton) &&

								<button
									disabled={this.state.diabled}
									onClick={this.validateInput.bind(this, this.state.searchValue)}
									className={`cps-btn +primary ${this.state.disabled ? "+disabled" : ""}`}>
									DONE
								</button>

}

			)

			this.positionDialog();
		}

		return (

 { if (el) this.el = el }} className='cpr-multi-selector'>
				<input type="input" className="cpr-multi-selector__hidden-input" onFocus={this.displayDialog}/>

					{pills}

				{dialog}

		)
	}
});

if (window && !window.MultiSelector) window.MultiSelector = MultiSelector;

export default MultiSelector;
<commit_msg>Not calling setState() if the component is unmounted (#128)<commit_after>import React from 'react';
import {without, includes, union, isNull, find} from 'lodash';

function DefaultItemComponent(props) {
	const item = props.item;
	const getItemTitle = props.getItemTitle;
	const selectedItems = props.selectedItems;
	const selected = includes(selectedItems, item);

	return (
		<div title={`${getItemTitle(item)}`}>
			<div
				className={`cpr-multi-selector-item__icon ${selected ? "cps-bg-primary-green +selected" : ""}`}>

{`${getItemTitle(item)}`}

	)
}

DefaultItemComponent.propTypes = {
	item: React.PropTypes.any.isRequired,
	getItemTitle: React.PropTypes.func,
	selectedItems: React.PropTypes.array.isRequired
};

function nearest(element, className) {
	if (!element || !element.className) return false;
	return element.className.indexOf(className) > -1 || nearest(element.parentElement, className);
}

const MultiSelector = React.createClass({
	propTypes: {
		items: React.PropTypes.array.isRequired,
		initialSelectedItems: React.PropTypes.array,
		onInputChange: React.PropTypes.func,
		onChange: React.PropTypes.func,
		getItemTitle: React.PropTypes.func,
		ItemComponent: React.PropTypes.oneOfType(
			[React.PropTypes.element, React.PropTypes.func]
		),
		placeholder: React.PropTypes.string,
		maxLength: React.PropTypes.number,
		noRestrict: React.PropTypes.bool,
		pressEnterToAddPhrase: React.PropTypes.string,
		noResultsPhrase: React.PropTypes.string,
	},

	componentWillMount: function() {
		document.addEventListener('click', this.state.close);
	},

	componentWillUnmount: function() {
		document.removeEventListener('click', this.state.close);
	},

	getInitialState: function() {
		return {
			selectedItems: this.props.initialSelectedItems || [],
			mouseIndex: null,
			mouseActive: true,
			mouseFunc: null,
			dialogDisplayed: false,
			activeIndex: null,
			searchValue: '',
			close: (e) => {
				if (!nearest(e.target, 'cpr-multi-selector')) {
					setTimeout(() => {
						if (this.state.dialogDisplayed && this.isMounted()) {
							this.props.onBlur && this.props.onBlur();
							this.setState({
								dialogDisplayed: false,
								searchValue: ''
							});
						}
					})
				}
			},
			invalid: false,
		}
	},

	componentWillReceiveProps(nextProps) {
		this.setState({
			selectedItems: nextProps.initialSelectedItems || []
		})
	},

	displayDialog: function(e) {
		if (!this.state.dialogDisplayed)
			this.props.onFocus && this.props.onFocus();
		this.setState({
			dialogDisplayed: true
		})
	},

	removeItem: function(item, e) {
		this.setState({
			selectedItems: without(this.state.selectedItems, item)
		});

		setTimeout(this.triggerItemChange);
	},

	getItemTitle: function(item) {
		return item.label;
	},

	setActiveIndex(index) {
		this.setState({
			activeIndex: index,
			mouseIndex: null,
		}, () => {
			if (!isNull(this.state.activeIndex) && !!this.searchItems[this.state.activeIndex]) {
				this.searchItems[this.state.activeIndex].scrollIntoView();
				if (this.state.mouseActive) {
					this.setState({
						mouseActive: false,
						mouseFunc: () => {
							this.setState({
								mouseActive: true
							})
							document.removeEventListener("mousemove", this.state.mouseFunc);
						}
					}, () => {
						document.addEventListener("mousemove", this.state.mouseFunc);
					})
				}
			}
		})
	},

	handleChange: function(e) {
		e.persist();
		if (this.state.invalid && this.props.validate) {
			this.setState({
				invalid: !this.props.validate(e.target.value),
			});
		}
		this.setState({
			disabled: this.props.disableInput ? this.props.disableInput(e.target.value) : false,
		}, () => {
			this.inputChange(e.target.value);
		});
	},

	inputChange: function(newVal) {
		this.props.onInputChange && this.props.onInputChange(newVal);

		this.setState({
			searchValue: newVal
		});
	},

	keyDown: function(e) {
		const keycode = e.which;
		const activeIndex = this.state.activeIndex;
		const filterItems = this.getFilterItems(this.props.items);

		if (isNull(activeIndex) && filterItems.length !== 0) {
			this.setActiveIndex(0);
		} else if (filterItems.length === 0) {
			this.setActiveIndex(null);
		}

		if (keycode === 13) e.preventDefault();
		if(keycode === 40) { // press down key
			if (isNull(activeIndex) && filterItems.length !== 0) {
				return this.setActiveIndex(0);
			} else {
				if(activeIndex < filterItems.length - 1) {
					return this.setActiveIndex(activeIndex + 1);
				}
			}
		} else if(keycode === 38) { // press up key
			if(!activeIndex) {
				return this.setActiveIndex(0);
			} else {
				if(activeIndex > 0) {
					return this.setActiveIndex(activeIndex - 1);
				}
			}
		} else if(keycode === 13) { // press enter key
			if(!isNull(activeIndex) && filterItems.length !==0) {
				return this.selectItem(filterItems[activeIndex], e);
			} else if(this.props.noRestrict && e.currentTarget.value) {
				// if the noRestrict prop is true it adds the input as a string to the selected items on enter
				e.persist();
				return this.validateInput(e.currentTarget.value, e);
			}
		} else if(keycode === 27) { // press escape key
			return this.setState({
				activeIndex: null,
				dialogDisplayed: false
			});
		}
	},

	triggerItemChange: function() {
		if (this.props.onChange) {
			this.props.onChange.call(null, this.state.selectedItems);
		}
	},

	getSelectedClass: function(item) {
		return includes(this.state.selectedItems, item) ? '+selected' : '';
	},

	getActiveClass: function(index) {
		return this.state.activeIndex === index || this.state.mouseIndex === index
			? '+highlighted'
			: '';
	},

	getFilterItems: function(items = []) {
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;

		return items
			.filter((item) => {
				return getItemTitle(item).toLowerCase().indexOf(this.state.searchValue.toLowerCase()) > -1;
			})
	},

	getSearchItems: function(items = []) {
		let ItemComponent = this.props.ItemComponent || DefaultItemComponent;
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;
		let filterItems = this.getFilterItems(items);

		// Show a message that user can press enter to add new item
		if (filterItems.length === 0) {
			if (this.props.noRestrict && this.state.searchValue) {
				const pressEnterToAddPhrase = this.props.pressEnterToAddPhrase || 'Press Enter to add';
				return (

{pressEnterToAddPhrase} "{this.state.searchValue}"

				)
			} else {
				const noResultsPhrase = this.props.noResultsPhrase || 'No items found.';
				return (

{noResultsPhrase}

				)
			}
		}

		// If noRestrict & the search term doesn't have an exact match, append an additional "result" for the new item
		// This is to allow adding of new items when the search term has matching filtered items but not an exact match
		if (this.props.noRestrict && this.state.searchValue
		&& !find(filterItems, (item) => getItemTitle(item).toLowerCase() === this.state.searchValue.toLowerCase())) {
			filterItems.push(this.state.searchValue);
		}

		return filterItems.map((item, index) => {
			return (

 {
						if (this.searchItems) {
							this.searchItems[index] = ref;
						} else {
							this.searchItems = [];
							this.searchItems[index] = ref;
						}
					}}
					onMouseOver={() => {
						if (this.state.mouseActive) {
							this.setState({
								mouseIndex: index
							})
						}
					}}
					className={`cpr-multi-selector-item ${this.getSelectedClass(item)} ${this.getActiveClass(index)}`}
					onClick={this.selectItem.bind(this, item)}>
					<ItemComponent item={item} selectedItems={this.state.selectedItems} getItemTitle={getItemTitle}/>

			)
		})
	},

	selectItem: function(item, e) {
		let selectedItems = this.state.selectedItems;

		if(includes(selectedItems, item)) {
			this.setState({
				selectedItems: without(selectedItems, item),
				invalid: false,
			}, this.triggerItemChange);
		} else {
			this.setState({
				selectedItems: union(selectedItems, [ item ]),
				invalid: false,
			}, this.triggerItemChange);
		}

		if (e && e.currentTarget) {
			e.currentTarget.value = '';
			this.inputChange('');
		}
	},

	validateInput: function(input, e) {
		if (this.state.disabled) return;
		if (this.props.validate) {
			const valid = this.props.validate(input);
			if (valid) this.selectItem(input, e);
			else this.setState({invalid: true});
		} else {
			this.selectItem(input, e);
		}
	},

	positionDialog: function() {
		setTimeout(() => {
			let el = this.el;
			let height = el.clientHeight;
			let dialog = el.querySelector('.cpr-multi-selector__dialog');

			if (dialog) {
				dialog.style.top = (height + 1) + 'px';
				el.querySelector('.cpr-multi-selector__dialog__input').focus();
			}
		}, 100);
	},

	prevent: function(e){
		if(e.which === 13) e.preventDefault();
	},

	render: function() {
		//Get getItemTitle is the function that should be passed in to decide what `pill` will display on selection.
		let getItemTitle = this.props.getItemTitle || this.getItemTitle;

		let pills = this.state.selectedItems
			.map((item, i) => {
				return (
					<div key={i} className="cpr-multi-selector__pill" title={`${getItemTitle(item)}`}>

							{getItemTitle(item)}

							 {
									e.stopPropagation();
									this.removeItem(item)
								}}
								className="cps-icon cps-icon-sm-neg">

				);
			});

		let dialog;

		if (this.state.dialogDisplayed) {
			let placeholder = this.props.placeholder ? this.props.placeholder : "Type a collaborators name...";
			let maxLength = this.props.maxLength;
			dialog = (

					<div
						className={`${this.state.invalid ? "cps-has-error" : ""}`}
						style={{padding: "16px", borderBottom: "1px solid #E9E9E9"}}>
						<input
							onChange={this.handleChange}
							onKeyDown={this.keyDown}
							className={`cps-form-control cpr-multi-selector__dialog__input`}
							placeholder={placeholder}
							{...(maxLength ? {maxLength} : {})}/>
						{this.state.invalid &&
							{this.props.invalidMsg}}

						{this.getSearchItems(this.props.items)}

						{(this.state.searchValue && this.props.doneButton) &&

								<button
									disabled={this.state.diabled}
									onClick={this.validateInput.bind(this, this.state.searchValue)}
									className={`cps-btn +primary ${this.state.disabled ? "+disabled" : ""}`}>
									DONE
								</button>

}

			)

			this.positionDialog();
		}

		return (

 { if (el) this.el = el }} className='cpr-multi-selector'>
				<input type="input" className="cpr-multi-selector__hidden-input" onFocus={this.displayDialog}/>

					{pills}

				{dialog}

		)
	}
});

if (window && !window.MultiSelector) window.MultiSelector = MultiSelector;

export default MultiSelector;
<|endoftext|>


<commit_before>'use strict';

angular.module('mwComponentsBb', [])

  /**
   * @ngdoc directive
   * @name mwComponents.directive:mwFilterableSearch
   * @element div
   * @description
   *
   * Creates a search field to filter by in the sidebar. Search is triggered while typing.
   *
   * @param {filterable} filterable Filterable instance.
   * @param {expression} disabled If expression evaluates to true, input is disabled.
   * @param {string} property The name of the property on which the filtering should happen.
   */
  .directive('mwFilterableSearchBb', function ($timeout, ignoreKeyPress) {
    return {
      scope: {
        collection: '=',
        property: '@',
        customUrlParameter: '@',
        mwDisabled: '=',
        placeholder: '@'
      },
      templateUrl: 'uikit/templates/mwComponentsBb/mwFilterableSearch.html',
      link: function (scope, el) {
        var inputEl = el.find('input');

        var setFilterVal = function (val) {
          if (scope.customUrlParameter) {
            scope.collection.filterable.customUrlParams[scope.customUrlParameter] = val;
          } else {
            var filter = {};
            filter[scope.property] = val;
            scope.collection.filterable.setFilters(filter);
          }
        };

        scope.viewModel = {
          searchVal: ''
        };

        scope.search = function () {
          scope.searching = true;
          //backup searched text to reset after fetch complete in case of search text was empty
          setFilterVal(scope.viewModel.searchVal);
          return scope.collection.fetch().finally(function () {
            $timeout(function () {
              scope.searching = false;
            }, 500);
          });
        };

        scope.reset = function () {
          scope.viewModel.searchVal = '';
          scope.search();
        };

        scope.hasValue = function () {
          return inputEl.val().length > 0;
        };

        scope.keyUp = function () {
          ignoreKeyPress.ignoreEnterKey(event);
          scope.searching = true;
        };

        scope.focus = function () {
          inputEl.focus();
        };

        el.on('focus', 'input[type=text]', function () {
          el.children().addClass('is-focused');
        });

        el.on('blur', 'input[type=text]', function () {
          el.children().removeClass('is-focused');
        });
      }
    };
  })

  .directive('mwEmptyStateBb', function () {
    return {
      restrict: 'A',
      replace: true,
      scope: {
        collection: '=',
        text: '@mwEmptyStateBb',
        button: '&',
        buttonText: '@'
      },
      transclude: true,
      templateUrl: 'uikit/templates/mwComponentsBb/mwEmptyStateBb.html',
      link: function (scope) {

        if (scope.collection) {
          scope.showEmptyState = function () {
            return (scope.collection.length === 0 && !scope.collection.filterable.filterIsSet);
          };
        } else {
          scope.showEmptyState = function () {
            return true;
          };
        }
      }
    };
  })

  .directive('mwVersionSelector', function () {
    return {
      restrict: 'A',
      scope: {
        currentVersionModel: '=',
        versionCollection: '=',
        versionNumberKey: '@',
        url: '@'
      },
      templateUrl: 'uikit/templates/mwComponentsBb/mwVersionSelector.html',
      link: function (scope) {
        scope.versionNumberKey = scope.versionNumberKey || 'versionNumber';
        scope.getUrl = function (uuid) {
          return scope.url.replace('VERSION_UUID', uuid);
        };
      }
    };
  })

  .service('ignoreKeyPress', function() {
    var ENTER_KEY = 13;
    return {
      ignoreEnterKey: function(event) {
        if (event.which === ENTER_KEY) {
          event.preventDefault();
        }
      }
    };
  });

<commit_msg>make argument visible<commit_after>'use strict';

angular.module('mwComponentsBb', [])

  /**
   * @ngdoc directive
   * @name mwComponents.directive:mwFilterableSearch
   * @element div
   * @description
   *
   * Creates a search field to filter by in the sidebar. Search is triggered while typing.
   *
   * @param {filterable} filterable Filterable instance.
   * @param {expression} disabled If expression evaluates to true, input is disabled.
   * @param {string} property The name of the property on which the filtering should happen.
   */
  .directive('mwFilterableSearchBb', function ($timeout, ignoreKeyPress) {
    return {
      scope: {
        collection: '=',
        property: '@',
        customUrlParameter: '@',
        mwDisabled: '=',
        placeholder: '@'
      },
      templateUrl: 'uikit/templates/mwComponentsBb/mwFilterableSearch.html',
      link: function (scope, el) {
        var inputEl = el.find('input');

        var setFilterVal = function (val) {
          if (scope.customUrlParameter) {
            scope.collection.filterable.customUrlParams[scope.customUrlParameter] = val;
          } else {
            var filter = {};
            filter[scope.property] = val;
            scope.collection.filterable.setFilters(filter);
          }
        };

        scope.viewModel = {
          searchVal: ''
        };

        scope.search = function () {
          scope.searching = true;
          //backup searched text to reset after fetch complete in case of search text was empty
          setFilterVal(scope.viewModel.searchVal);
          return scope.collection.fetch().finally(function () {
            $timeout(function () {
              scope.searching = false;
            }, 500);
          });
        };

        scope.reset = function () {
          scope.viewModel.searchVal = '';
          scope.search();
        };

        scope.hasValue = function () {
          return inputEl.val().length > 0;
        };

        scope.keyUp = function (event) {
          ignoreKeyPress.ignoreEnterKey(event);
          scope.searching = true;
        };

        scope.focus = function () {
          inputEl.focus();
        };

        el.on('focus', 'input[type=text]', function () {
          el.children().addClass('is-focused');
        });

        el.on('blur', 'input[type=text]', function () {
          el.children().removeClass('is-focused');
        });
      }
    };
  })

  .directive('mwEmptyStateBb', function () {
    return {
      restrict: 'A',
      replace: true,
      scope: {
        collection: '=',
        text: '@mwEmptyStateBb',
        button: '&',
        buttonText: '@'
      },
      transclude: true,
      templateUrl: 'uikit/templates/mwComponentsBb/mwEmptyStateBb.html',
      link: function (scope) {

        if (scope.collection) {
          scope.showEmptyState = function () {
            return (scope.collection.length === 0 && !scope.collection.filterable.filterIsSet);
          };
        } else {
          scope.showEmptyState = function () {
            return true;
          };
        }
      }
    };
  })

  .directive('mwVersionSelector', function () {
    return {
      restrict: 'A',
      scope: {
        currentVersionModel: '=',
        versionCollection: '=',
        versionNumberKey: '@',
        url: '@'
      },
      templateUrl: 'uikit/templates/mwComponentsBb/mwVersionSelector.html',
      link: function (scope) {
        scope.versionNumberKey = scope.versionNumberKey || 'versionNumber';
        scope.getUrl = function (uuid) {
          return scope.url.replace('VERSION_UUID', uuid);
        };
      }
    };
  })

  .service('ignoreKeyPress', function() {
    var ENTER_KEY = 13;
    return {
      ignoreEnterKey: function(event) {
        if (event.which === ENTER_KEY) {
          event.preventDefault();
        }
      }
    };
  });

<|endoftext|>


<commit_before>'use strict';

function createXhr(method) {
    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
    //if it is available
    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
      !window.XMLHttpRequest)) {
      return new ActiveXObject("Microsoft.XMLHTTP");
    } else if (window.XMLHttpRequest) {
      return new window.XMLHttpRequest();
    }

    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
}

/**
 * @ngdoc object
 * @name ng.$httpBackend
 * @requires $browser
 * @requires $window
 * @requires $document
 *
 * @description
 * HTTP backend used by the {@link ng.$http service} that delegates to
 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
 *
 * You should never need to use this service directly, instead use the higher-level abstractions:
 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
 *
 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
 * $httpBackend} which can be trained with responses.
 */
function $HttpBackendProvider() {
  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
  }];
}

function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
  var ABORTED = -1;

  // TODO(vojta): fix the signature
  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
    var status;
    $browser.$$incOutstandingRequestCount();
    url = url || $browser.url();

    if (lowercase(method) == 'jsonp') {
      var callbackId = '_' + (callbacks.counter++).toString(36);
      callbacks[callbackId] = function(data) {
        callbacks[callbackId].data = data;
      };

      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
          function() {
        if (callbacks[callbackId].data) {
          completeRequest(callback, 200, callbacks[callbackId].data);
        } else {
          completeRequest(callback, status || -2);
        }
        callbacks[callbackId] = angular.noop;
      });
    } else {

      var xhr = createXhr(method);

      xhr.open(method, url, true);
      forEach(headers, function(value, key) {
        if (isDefined(value)) {
            xhr.setRequestHeader(key, value);
        }
      });

      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
      // response is in the cache. the promise api will ensure that to the app code the api is
      // always async
      xhr.onreadystatechange = function() {
        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
        // xhrs that are resolved while the app is in the background (see #5426).
        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
        // continuing
        //
        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
        // Safari respectively.
        if (xhr && xhr.readyState == 4) {
          var responseHeaders = null,
              response = null;

          if(status !== ABORTED) {
            responseHeaders = xhr.getAllResponseHeaders();

            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
            response = ('response' in xhr) ? xhr.response : xhr.responseText;
          }

          completeRequest(callback,
              status || xhr.status,
              response,
              responseHeaders);
        }
      };

      if (withCredentials) {
        xhr.withCredentials = true;
      }

      if (responseType) {
        xhr.responseType = responseType;
      }

      xhr.send(post || null);
    }

    if (timeout > 0) {
      var timeoutId = $browserDefer(timeoutRequest, timeout);
    } else if (timeout && timeout.then) {
      timeout.then(timeoutRequest);
    }

    function timeoutRequest() {
      status = ABORTED;
      jsonpDone && jsonpDone();
      xhr && xhr.abort();
    }

    function completeRequest(callback, status, response, headersString) {
      // cancel timeout and subsequent timeout promise resolution
      timeoutId && $browserDefer.cancel(timeoutId);
      jsonpDone = xhr = null;

      // fix status code when it is 0 (0 status is undocumented).
      // Occurs when accessing file resources.
      // On Android 4.1 stock browser it occurs while retrieving files from application cache.
      status = (status === 0) ? (response ? 200 : 404) : status;

      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
      status = status == 1223 ? 204 : status;

      callback(status, response, headersString);
      $browser.$$completeOutstandingRequest(noop);
    }
  };

  function jsonpReq(url, done) {
    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
    // - fetches local scripts via XHR and evals them
    // - adds and immediately removes script elements from the document
    var script = rawDocument.createElement('script'),
        doneWrapper = function() {
          script.onreadystatechange = script.onload = script.onerror = null;
          rawDocument.body.removeChild(script);
          if (done) done();
        };

    script.type = 'text/javascript';
    script.src = url;

    if (msie && msie <= 8) {
      script.onreadystatechange = function() {
        if (/loaded|complete/.test(script.readyState)) {
          doneWrapper();
        }
      };
    } else {
      script.onload = script.onerror = function() {
        doneWrapper();
      };
    }

    rawDocument.body.appendChild(script);
    return doneWrapper;
  }
}
<commit_msg>fix(http): make jshint happy<commit_after>'use strict';

function createXhr(method) {
    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
    //if it is available
    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
      !window.XMLHttpRequest)) {
      return new window.ActiveXObject("Microsoft.XMLHTTP");
    } else if (window.XMLHttpRequest) {
      return new window.XMLHttpRequest();
    }

    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
}

/**
 * @ngdoc object
 * @name ng.$httpBackend
 * @requires $browser
 * @requires $window
 * @requires $document
 *
 * @description
 * HTTP backend used by the {@link ng.$http service} that delegates to
 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
 *
 * You should never need to use this service directly, instead use the higher-level abstractions:
 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
 *
 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
 * $httpBackend} which can be trained with responses.
 */
function $HttpBackendProvider() {
  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
  }];
}

function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
  var ABORTED = -1;

  // TODO(vojta): fix the signature
  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
    var status;
    $browser.$$incOutstandingRequestCount();
    url = url || $browser.url();

    if (lowercase(method) == 'jsonp') {
      var callbackId = '_' + (callbacks.counter++).toString(36);
      callbacks[callbackId] = function(data) {
        callbacks[callbackId].data = data;
      };

      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
          function() {
        if (callbacks[callbackId].data) {
          completeRequest(callback, 200, callbacks[callbackId].data);
        } else {
          completeRequest(callback, status || -2);
        }
        callbacks[callbackId] = angular.noop;
      });
    } else {

      var xhr = createXhr(method);

      xhr.open(method, url, true);
      forEach(headers, function(value, key) {
        if (isDefined(value)) {
            xhr.setRequestHeader(key, value);
        }
      });

      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
      // response is in the cache. the promise api will ensure that to the app code the api is
      // always async
      xhr.onreadystatechange = function() {
        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
        // xhrs that are resolved while the app is in the background (see #5426).
        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
        // continuing
        //
        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
        // Safari respectively.
        if (xhr && xhr.readyState == 4) {
          var responseHeaders = null,
              response = null;

          if(status !== ABORTED) {
            responseHeaders = xhr.getAllResponseHeaders();

            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
            response = ('response' in xhr) ? xhr.response : xhr.responseText;
          }

          completeRequest(callback,
              status || xhr.status,
              response,
              responseHeaders);
        }
      };

      if (withCredentials) {
        xhr.withCredentials = true;
      }

      if (responseType) {
        xhr.responseType = responseType;
      }

      xhr.send(post || null);
    }

    if (timeout > 0) {
      var timeoutId = $browserDefer(timeoutRequest, timeout);
    } else if (timeout && timeout.then) {
      timeout.then(timeoutRequest);
    }

    function timeoutRequest() {
      status = ABORTED;
      jsonpDone && jsonpDone();
      xhr && xhr.abort();
    }

    function completeRequest(callback, status, response, headersString) {
      // cancel timeout and subsequent timeout promise resolution
      timeoutId && $browserDefer.cancel(timeoutId);
      jsonpDone = xhr = null;

      // fix status code when it is 0 (0 status is undocumented).
      // Occurs when accessing file resources.
      // On Android 4.1 stock browser it occurs while retrieving files from application cache.
      status = (status === 0) ? (response ? 200 : 404) : status;

      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
      status = status == 1223 ? 204 : status;

      callback(status, response, headersString);
      $browser.$$completeOutstandingRequest(noop);
    }
  };

  function jsonpReq(url, done) {
    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
    // - fetches local scripts via XHR and evals them
    // - adds and immediately removes script elements from the document
    var script = rawDocument.createElement('script'),
        doneWrapper = function() {
          script.onreadystatechange = script.onload = script.onerror = null;
          rawDocument.body.removeChild(script);
          if (done) done();
        };

    script.type = 'text/javascript';
    script.src = url;

    if (msie && msie <= 8) {
      script.onreadystatechange = function() {
        if (/loaded|complete/.test(script.readyState)) {
          doneWrapper();
        }
      };
    } else {
      script.onload = script.onerror = function() {
        doneWrapper();
      };
    }

    rawDocument.body.appendChild(script);
    return doneWrapper;
  }
}
<|endoftext|>


<commit_before>import { Vector3 } from '../math/Vector3';
import { Object3D } from '../core/Object3D';
import { SpriteMaterial } from '../materials/SpriteMaterial';

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function Sprite( material ) {

	Object3D.call( this );

	this.type = 'Sprite';

	this.material = ( material !== undefined ) ? material : new SpriteMaterial();

}

Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {

	constructor: Sprite,

	isSprite: true,

	raycast: ( function () {

		var intersectPoint = new Vector3();
		var matrixPosition = new Vector3();

		return function raycast( raycaster, intersects ) {

			matrixPosition.setFromMatrixPosition( this.matrixWorld );
			raycaster.ray.closestPointToPoint( matrixPosition, intersectPoint );
			var guessSizeSq = this.scale.x * this.scale.y / 4;

			if ( matrixPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;

			var distance = raycaster.ray.origin.distanceTo( intersectPoint );

			if ( distance < raycaster.near || distance > raycaster.far ) return;

			intersects.push( {

				distance: distance,
				point: intersectPoint.clone(),
				face: null,
				object: this

			} );

		};

	}() ),

	clone: function () {

		return new this.constructor( this.material ).copy( this );

	}

} );

export { Sprite };
<commit_msg>Fix #9677: use world scale for sprite raycasting<commit_after>import { Vector3 } from '../math/Vector3';
import { Object3D } from '../core/Object3D';
import { SpriteMaterial } from '../materials/SpriteMaterial';

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

function Sprite( material ) {

	Object3D.call( this );

	this.type = 'Sprite';

	this.material = ( material !== undefined ) ? material : new SpriteMaterial();

}

Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {

	constructor: Sprite,

	isSprite: true,

	raycast: ( function () {

		var intersectPoint = new Vector3();
		var worldPosition = new Vector3();
		var worldScale = new Vector3();

		return function raycast( raycaster, intersects ) {

			worldPosition.setFromMatrixPosition( this.matrixWorld );
			raycaster.ray.closestPointToPoint( worldPosition, intersectPoint );

			worldScale.setFromMatrixScale( this.matrixWorld );
			var guessSizeSq = worldScale.x * worldScale.y / 4;

			if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;

			var distance = raycaster.ray.origin.distanceTo( intersectPoint );

			if ( distance < raycaster.near || distance > raycaster.far ) return;

			intersects.push( {

				distance: distance,
				point: intersectPoint.clone(),
				face: null,
				object: this

			} );

		};

	}() ),

	clone: function () {

		return new this.constructor( this.material ).copy( this );

	}

} );

export { Sprite };
<|endoftext|>


<commit_before>// FIXME handle geolocation not supported

goog.provide('ol.Geolocation');
goog.provide('ol.GeolocationProperty');

goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.Coordinate');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Polygon');
goog.require('ol.has');
goog.require('ol.math');
goog.require('ol.proj');
goog.require('ol.sphere.WGS84');

/**
 * @enum {string}
 */
ol.GeolocationProperty = {
  ACCURACY: 'accuracy',
  ACCURACY_GEOMETRY: 'accuracyGeometry',
  ALTITUDE: 'altitude',
  ALTITUDE_ACCURACY: 'altitudeAccuracy',
  HEADING: 'heading',
  POSITION: 'position',
  PROJECTION: 'projection',
  SPEED: 'speed',
  TRACKING: 'tracking',
  TRACKING_OPTIONS: 'trackingOptions'
};

/**
 * @classdesc
 * Helper class for providing HTML5 Geolocation capabilities.
 * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
 * is used to locate a user's position.
 *
 * To get notified of position changes, register a listener for the generic
 * `change` event on your instance of `ol.Geolocation`.
 *
 * Example:
 *
 *     var geolocation = new ol.Geolocation({
 *       // take the projection to use from the map's view
 *       projection: view.getProjection()
 *     });
 *     // listen to changes in position
 *     geolocation.on('change', function(evt) {
 *       window.console.log(geolocation.getPosition());
 *     });
 *
 * @fires error
 * @constructor
 * @extends {ol.Object}
 * @param {olx.GeolocationOptions=} opt_options Options.
 * @api stable
 */
ol.Geolocation = function(opt_options) {

  goog.base(this);

  var options = opt_options || {};

  /**
   * The unprojected (EPSG:4326) device position.
   * @private
   * @type {ol.Coordinate}
   */
  this.position_ = null;

  /**
   * @private
   * @type {ol.TransformFunction}
   */
  this.transform_ = ol.proj.identityTransform;

  /**
   * @private
   * @type {number|undefined}
   */
  this.watchId_ = undefined;

  ol.events.listen(
      this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
      this.handleProjectionChanged_, this);
  ol.events.listen(
      this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
      this.handleTrackingChanged_, this);

  if (options.projection !== undefined) {
    this.setProjection(ol.proj.get(options.projection));
  }
  if (options.trackingOptions !== undefined) {
    this.setTrackingOptions(options.trackingOptions);
  }

  this.setTracking(options.tracking !== undefined ? options.tracking : false);

};
goog.inherits(ol.Geolocation, ol.Object);

/**
 * @inheritDoc
 */
ol.Geolocation.prototype.disposeInternal = function() {
  this.setTracking(false);
  goog.base(this, 'disposeInternal');
};

/**
 * @private
 */
ol.Geolocation.prototype.handleProjectionChanged_ = function() {
  var projection = this.getProjection();
  if (projection) {
    this.transform_ = ol.proj.getTransformFromProjections(
        ol.proj.get('EPSG:4326'), projection);
    if (this.position_) {
      this.set(
          ol.GeolocationProperty.POSITION, this.transform_(this.position_));
    }
  }
};

/**
 * @private
 */
ol.Geolocation.prototype.handleTrackingChanged_ = function() {
  if (ol.has.GEOLOCATION) {
    var tracking = this.getTracking();
    if (tracking && this.watchId_ === undefined) {
      this.watchId_ = goog.global.navigator.geolocation.watchPosition(
          this.positionChange_.bind(this),
          this.positionError_.bind(this),
          this.getTrackingOptions());
    } else if (!tracking && this.watchId_ !== undefined) {
      goog.global.navigator.geolocation.clearWatch(this.watchId_);
      this.watchId_ = undefined;
    }
  }
};

/**
 * @private
 * @param {GeolocationPosition} position position event.
 */
ol.Geolocation.prototype.positionChange_ = function(position) {
  var coords = position.coords;
  this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
  this.set(ol.GeolocationProperty.ALTITUDE,
      coords.altitude === null ? undefined : coords.altitude);
  this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
      coords.altitudeAccuracy === null ?
      undefined : coords.altitudeAccuracy);
  this.set(ol.GeolocationProperty.HEADING, coords.heading === null ?
      undefined : ol.math.toRadians(coords.heading));
  if (!this.position_) {
    this.position_ = [coords.longitude, coords.latitude];
  } else {
    this.position_[0] = coords.longitude;
    this.position_[1] = coords.latitude;
  }
  var projectedPosition = this.transform_(this.position_);
  this.set(ol.GeolocationProperty.POSITION, projectedPosition);
  this.set(ol.GeolocationProperty.SPEED,
      coords.speed === null ? undefined : coords.speed);
  var geometry = ol.geom.Polygon.circular(
      ol.sphere.WGS84, this.position_, coords.accuracy);
  geometry.applyTransform(this.transform_);
  this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
  this.changed();
};

/**
 * Triggered when the Geolocation returns an error.
 * @event error
 * @api
 */

/**
 * @private
 * @param {GeolocationPositionError} error error object.
 */
ol.Geolocation.prototype.positionError_ = function(error) {
  error.type = ol.events.EventType.ERROR;
  this.setTracking(false);
  this.dispatchEvent(/** @type {{type: string}} */ (error));
};

/**
 * Get the accuracy of the position in meters.
 * @return {number|undefined} The accuracy of the position measurement in
 *     meters.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAccuracy = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ACCURACY));
};

/**
 * Get a geometry of the position accuracy.
 * @return {?ol.geom.Geometry} A geometry of the position accuracy.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAccuracyGeometry = function() {
  return /** @type {?ol.geom.Geometry} */ (
      this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null);
};

/**
 * Get the altitude associated with the position.
 * @return {number|undefined} The altitude of the position in meters above mean
 *     sea level.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAltitude = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ALTITUDE));
};

/**
 * Get the altitude accuracy of the position.
 * @return {number|undefined} The accuracy of the altitude measurement in
 *     meters.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAltitudeAccuracy = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
};

/**
 * Get the heading as radians clockwise from North.
 * @return {number|undefined} The heading of the device in radians from north.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getHeading = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.HEADING));
};

/**
 * Get the position of the device.
 * @return {ol.Coordinate|undefined} The current position of the device reported
 *     in the current projection.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getPosition = function() {
  return /** @type {ol.Coordinate|undefined} */ (
      this.get(ol.GeolocationProperty.POSITION));
};

/**
 * Get the projection associated with the position.
 * @return {ol.proj.Projection|undefined} The projection the position is
 *     reported in.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getProjection = function() {
  return /** @type {ol.proj.Projection|undefined} */ (
      this.get(ol.GeolocationProperty.PROJECTION));
};

/**
 * Get the speed in meters per second.
 * @return {number|undefined} The instantaneous speed of the device in meters
 *     per second.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getSpeed = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.SPEED));
};

/**
 * Determine if the device location is being tracked.
 * @return {boolean} The device location is being tracked.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getTracking = function() {
  return /** @type {boolean} */ (
      this.get(ol.GeolocationProperty.TRACKING));
};

/**
 * Get the tracking options.
 * @see http://www.w3.org/TR/geolocation-API/#position-options
 * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
 *     the [HTML5 Geolocation spec
 *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getTrackingOptions = function() {
  return /** @type {GeolocationPositionOptions|undefined} */ (
      this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
};

/**
 * Set the projection to use for transforming the coordinates.
 * @param {ol.proj.Projection} projection The projection the position is
 *     reported in.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setProjection = function(projection) {
  this.set(ol.GeolocationProperty.PROJECTION, projection);
};

/**
 * Enable or disable tracking.
 * @param {boolean} tracking Enable tracking.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setTracking = function(tracking) {
  this.set(ol.GeolocationProperty.TRACKING, tracking);
};

/**
 * Set the tracking options.
 * @see http://www.w3.org/TR/geolocation-API/#position-options
 * @param {GeolocationPositionOptions} options PositionOptions as defined by the
 *     [HTML5 Geolocation spec
 *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setTrackingOptions = function(options) {
  this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
};
<commit_msg>Fix geolocation error cast<commit_after>// FIXME handle geolocation not supported

goog.provide('ol.Geolocation');
goog.provide('ol.GeolocationProperty');

goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.Coordinate');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Polygon');
goog.require('ol.has');
goog.require('ol.math');
goog.require('ol.proj');
goog.require('ol.sphere.WGS84');

/**
 * @enum {string}
 */
ol.GeolocationProperty = {
  ACCURACY: 'accuracy',
  ACCURACY_GEOMETRY: 'accuracyGeometry',
  ALTITUDE: 'altitude',
  ALTITUDE_ACCURACY: 'altitudeAccuracy',
  HEADING: 'heading',
  POSITION: 'position',
  PROJECTION: 'projection',
  SPEED: 'speed',
  TRACKING: 'tracking',
  TRACKING_OPTIONS: 'trackingOptions'
};

/**
 * @classdesc
 * Helper class for providing HTML5 Geolocation capabilities.
 * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
 * is used to locate a user's position.
 *
 * To get notified of position changes, register a listener for the generic
 * `change` event on your instance of `ol.Geolocation`.
 *
 * Example:
 *
 *     var geolocation = new ol.Geolocation({
 *       // take the projection to use from the map's view
 *       projection: view.getProjection()
 *     });
 *     // listen to changes in position
 *     geolocation.on('change', function(evt) {
 *       window.console.log(geolocation.getPosition());
 *     });
 *
 * @fires error
 * @constructor
 * @extends {ol.Object}
 * @param {olx.GeolocationOptions=} opt_options Options.
 * @api stable
 */
ol.Geolocation = function(opt_options) {

  goog.base(this);

  var options = opt_options || {};

  /**
   * The unprojected (EPSG:4326) device position.
   * @private
   * @type {ol.Coordinate}
   */
  this.position_ = null;

  /**
   * @private
   * @type {ol.TransformFunction}
   */
  this.transform_ = ol.proj.identityTransform;

  /**
   * @private
   * @type {number|undefined}
   */
  this.watchId_ = undefined;

  ol.events.listen(
      this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
      this.handleProjectionChanged_, this);
  ol.events.listen(
      this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
      this.handleTrackingChanged_, this);

  if (options.projection !== undefined) {
    this.setProjection(ol.proj.get(options.projection));
  }
  if (options.trackingOptions !== undefined) {
    this.setTrackingOptions(options.trackingOptions);
  }

  this.setTracking(options.tracking !== undefined ? options.tracking : false);

};
goog.inherits(ol.Geolocation, ol.Object);

/**
 * @inheritDoc
 */
ol.Geolocation.prototype.disposeInternal = function() {
  this.setTracking(false);
  goog.base(this, 'disposeInternal');
};

/**
 * @private
 */
ol.Geolocation.prototype.handleProjectionChanged_ = function() {
  var projection = this.getProjection();
  if (projection) {
    this.transform_ = ol.proj.getTransformFromProjections(
        ol.proj.get('EPSG:4326'), projection);
    if (this.position_) {
      this.set(
          ol.GeolocationProperty.POSITION, this.transform_(this.position_));
    }
  }
};

/**
 * @private
 */
ol.Geolocation.prototype.handleTrackingChanged_ = function() {
  if (ol.has.GEOLOCATION) {
    var tracking = this.getTracking();
    if (tracking && this.watchId_ === undefined) {
      this.watchId_ = goog.global.navigator.geolocation.watchPosition(
          this.positionChange_.bind(this),
          this.positionError_.bind(this),
          this.getTrackingOptions());
    } else if (!tracking && this.watchId_ !== undefined) {
      goog.global.navigator.geolocation.clearWatch(this.watchId_);
      this.watchId_ = undefined;
    }
  }
};

/**
 * @private
 * @param {GeolocationPosition} position position event.
 */
ol.Geolocation.prototype.positionChange_ = function(position) {
  var coords = position.coords;
  this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
  this.set(ol.GeolocationProperty.ALTITUDE,
      coords.altitude === null ? undefined : coords.altitude);
  this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
      coords.altitudeAccuracy === null ?
      undefined : coords.altitudeAccuracy);
  this.set(ol.GeolocationProperty.HEADING, coords.heading === null ?
      undefined : ol.math.toRadians(coords.heading));
  if (!this.position_) {
    this.position_ = [coords.longitude, coords.latitude];
  } else {
    this.position_[0] = coords.longitude;
    this.position_[1] = coords.latitude;
  }
  var projectedPosition = this.transform_(this.position_);
  this.set(ol.GeolocationProperty.POSITION, projectedPosition);
  this.set(ol.GeolocationProperty.SPEED,
      coords.speed === null ? undefined : coords.speed);
  var geometry = ol.geom.Polygon.circular(
      ol.sphere.WGS84, this.position_, coords.accuracy);
  geometry.applyTransform(this.transform_);
  this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
  this.changed();
};

/**
 * Triggered when the Geolocation returns an error.
 * @event error
 * @api
 */

/**
 * @private
 * @param {GeolocationPositionError} error error object.
 */
ol.Geolocation.prototype.positionError_ = function(error) {
  error.type = ol.events.EventType.ERROR;
  this.setTracking(false);
  this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
};

/**
 * Get the accuracy of the position in meters.
 * @return {number|undefined} The accuracy of the position measurement in
 *     meters.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAccuracy = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ACCURACY));
};

/**
 * Get a geometry of the position accuracy.
 * @return {?ol.geom.Geometry} A geometry of the position accuracy.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAccuracyGeometry = function() {
  return /** @type {?ol.geom.Geometry} */ (
      this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null);
};

/**
 * Get the altitude associated with the position.
 * @return {number|undefined} The altitude of the position in meters above mean
 *     sea level.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAltitude = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ALTITUDE));
};

/**
 * Get the altitude accuracy of the position.
 * @return {number|undefined} The accuracy of the altitude measurement in
 *     meters.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getAltitudeAccuracy = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
};

/**
 * Get the heading as radians clockwise from North.
 * @return {number|undefined} The heading of the device in radians from north.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getHeading = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.HEADING));
};

/**
 * Get the position of the device.
 * @return {ol.Coordinate|undefined} The current position of the device reported
 *     in the current projection.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getPosition = function() {
  return /** @type {ol.Coordinate|undefined} */ (
      this.get(ol.GeolocationProperty.POSITION));
};

/**
 * Get the projection associated with the position.
 * @return {ol.proj.Projection|undefined} The projection the position is
 *     reported in.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getProjection = function() {
  return /** @type {ol.proj.Projection|undefined} */ (
      this.get(ol.GeolocationProperty.PROJECTION));
};

/**
 * Get the speed in meters per second.
 * @return {number|undefined} The instantaneous speed of the device in meters
 *     per second.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getSpeed = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.GeolocationProperty.SPEED));
};

/**
 * Determine if the device location is being tracked.
 * @return {boolean} The device location is being tracked.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getTracking = function() {
  return /** @type {boolean} */ (
      this.get(ol.GeolocationProperty.TRACKING));
};

/**
 * Get the tracking options.
 * @see http://www.w3.org/TR/geolocation-API/#position-options
 * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
 *     the [HTML5 Geolocation spec
 *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.getTrackingOptions = function() {
  return /** @type {GeolocationPositionOptions|undefined} */ (
      this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
};

/**
 * Set the projection to use for transforming the coordinates.
 * @param {ol.proj.Projection} projection The projection the position is
 *     reported in.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setProjection = function(projection) {
  this.set(ol.GeolocationProperty.PROJECTION, projection);
};

/**
 * Enable or disable tracking.
 * @param {boolean} tracking Enable tracking.
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setTracking = function(tracking) {
  this.set(ol.GeolocationProperty.TRACKING, tracking);
};

/**
 * Set the tracking options.
 * @see http://www.w3.org/TR/geolocation-API/#position-options
 * @param {GeolocationPositionOptions} options PositionOptions as defined by the
 *     [HTML5 Geolocation spec
 *     ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
 * @observable
 * @api stable
 */
ol.Geolocation.prototype.setTrackingOptions = function(options) {
  this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
};
<|endoftext|>


<commit_before>var throng = require('throng');
var donateServer = require('./server');
var workers = process.env.WEB_CONCURRENCY || 1;

function start() {
  var server = donateServer();

  server.start(function() {
    server.log('info', 'Running server at: ' + server.info.uri);
  });

  var shutdown = () => {
    server.stop(() => {
      process.exit(0);
    });
  };

  process.on('SIGINT', shutdown);
  process.on('SIGTERM', shutdown);
}

// lol @ Infinity actually being used for something meaningful
throng(workers, start);
<commit_msg>Revert "Update throng to v3.0.0"<commit_after>var throng = require('throng');
var donateServer = require('./server');
var workers = process.env.WEB_CONCURRENCY || 1;

function start() {
  var server = donateServer();

  server.start(function() {
    server.log('info', 'Running server at: ' + server.info.uri);
  });

  var shutdown = () => {
    server.stop(() => {
      process.exit(0);
    });
  };

  process.on('SIGINT', shutdown);
  process.on('SIGTERM', shutdown);
}

// lol @ Infinity actually being used for something meaningful
throng(start, {
  workers,
  lifetime: Infinity
});
<|endoftext|>


<commit_before>var Class = require('class');

require('./bootstrap')(function () {
    var Router = require('./RestRoutingHandler'),
        HttpHandler = require('./handler/HttpHandler'),
        AuthenticationContext = require('./contexts/AuthenticationContext'),
        MinimalRequest = require('./MinimalRequest'),
        MoreAdvancedRequest = require('./request/moreadvancedrequest'),
        RateLimitMiddleware = require('./middleware/RateLimitMiddleware'),
        users = require('./users');

    var router = new Router;
    new (require('./controllers/AuthenticationController'))().registerRouter(router);
    new (require('./controllers/QuestController'))().registerRouter(router);
    new (require('./controllers/MetagameController'))().registerRouter(router);
    new (require('./controllers/AdminController'))().registerRouter(router);

    var port = process.env['CCC_PORT'] || 8888;
    var webserver = new HttpHandler({
        requestclass: MoreAdvancedRequest,
        port: port
    });

/*    webserver.registerMiddleware(new RateLimitMiddleware({
        enabled: true,
        requests: 400,
        time: 'min',
    }));*/

    webserver.error(function (err) {
        console.log(err);
    });

    webserver.requestFinished(function (request) {
            request.req.on('abort', function () {
                log('Request abort');
                request.end();
            });

            request.req.on('aborted', function () {
                log('Request aborted');
                request.end();
            });

            // Add the routing handler
            request.context = new AuthenticationContext(request);
            request.handlers = [ router ];
            request.handle();
    });
});
<commit_msg>remove unrequired dependencies<commit_after>var Class = require('class');

require('./bootstrap')(function () {
    var Router = require('./RestRoutingHandler'),
        HttpHandler = require('./handler/HttpHandler'),
        AuthenticationContext = require('./contexts/AuthenticationContext'),
        MinimalRequest = require('./MinimalRequest'),
        MoreAdvancedRequest = require('./request/moreadvancedrequest'),
        RateLimitMiddleware = require('./middleware/RateLimitMiddleware');

    var router = new Router;
    new (require('./controllers/AuthenticationController'))().registerRouter(router);
    new (require('./controllers/QuestController'))().registerRouter(router);
    new (require('./controllers/MetagameController'))().registerRouter(router);
    new (require('./controllers/AdminController'))().registerRouter(router);

    var port = process.env['CCC_PORT'] || 8888;
    var webserver = new HttpHandler({
        requestclass: MoreAdvancedRequest,
        port: port
    });

/*    webserver.registerMiddleware(new RateLimitMiddleware({
        enabled: true,
        requests: 400,
        time: 'min',
    }));*/

    webserver.error(function (err) {
        console.log(err);
    });

    webserver.requestFinished(function (request) {
            request.req.on('abort', function () {
                log('Request abort');
                request.end();
            });

            request.req.on('aborted', function () {
                log('Request aborted');
                request.end();
            });

            // Add the routing handler
            request.context = new AuthenticationContext(request);
            request.handlers = [ router ];
            request.handle();
    });
});
<|endoftext|>


<commit_before>var Cookies = require('cookies');
var url = require('url');

module.exports = function(serverError) {
	return {
		/**
		 * Create an object that keeps the state during a full request / response
		 * cycle. This state will not be kept between request. It's purpose is to
		 * bundle all data collected while building the response to one request.
		 */
		'create': function(req, res) {
			var state = {
				'request': req,
				'result': res,
				'fail': function(logmessage, errorcode) {
					serverError(state, logmessage, errorcode);
				},
				'cookies': new Cookies(req, res),
				'sendToLogin': function(message) {
					// TODO pass message to template
					ejs.render(state, '/login.tpl');
				},
				'context': {
						'meta': {'currentpage': ''}
				},
				'url': url.parse(req.url, true)
			};

			var session_key, user_id;

			// convenience..
			state.session_key = function(key) {
				if(key === undefined) {
					if(session_key === undefined) {
						session_key = state.cookies.get('session_key');
					}
					return session_key;
				} else {
					session_key = key;
					state.cookies.set('session_key', session_key);
					return session_key;
				}
			}
			state.user_id = function(id) {
				if(id === undefined) {
					if(user_id === undefined) {
						user_id = state.cookies.get('user_id');
					}
					return user_id;
				} else {
					user_id = id;
					state.cookies.set('user_id', user_id);
					return user_id;
				}
			}

			return state;
		}
	}
}
<commit_msg>Fix crash when rendering login screen.<commit_after>var Cookies = require('cookies');
var url = require('url');
var ejs = require('./ejs.js')

module.exports = function(serverError) {
	return {
		/**
		 * Create an object that keeps the state during a full request / response
		 * cycle. This state will not be kept between request. It's purpose is to
		 * bundle all data collected while building the response to one request.
		 */
		'create': function(req, res) {
			var state = {
				'request': req,
				'result': res,
				'fail': function(logmessage, errorcode) {
					serverError(state, logmessage, errorcode);
				},
				'cookies': new Cookies(req, res),
				'sendToLogin': function(message) {
					// TODO pass message to template
					ejs.render(state, '/login.tpl');
				},
				'context': {
						'meta': {'currentpage': ''}
				},
				'url': url.parse(req.url, true)
			};

			var session_key, user_id;

			// convenience..
			state.session_key = function(key) {
				if(key === undefined) {
					if(session_key === undefined) {
						session_key = state.cookies.get('session_key');
					}
					return session_key;
				} else {
					session_key = key;
					state.cookies.set('session_key', session_key);
					return session_key;
				}
			}
			state.user_id = function(id) {
				if(id === undefined) {
					if(user_id === undefined) {
						user_id = state.cookies.get('user_id');
					}
					return user_id;
				} else {
					user_id = id;
					state.cookies.set('user_id', user_id);
					return user_id;
				}
			}

			return state;
		}
	}
}
<|endoftext|>


<commit_before>(function (exports) {

    var sum, mean, deviation, variance, standardDeviation, standardize, correlation;

 // @param {[number]} x Array of numbers.
    exports.sum = sum = function (x) {
        return x.reduce(function (previousValue, currentValue) {
            return previousValue + currentValue;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.mean = mean = function (x) {
        return sum(x) / x.length;
    };

 // @param {[number]} x Array of numbers.
    exports.deviation = deviation = function (x) {
        var xBar;
        xBar = mean(x);
        return x.map(function (xi) {
            return xi - xBar;
        });
    };

 // Calculates the sample variance.
 // @param {[number]} x Array of numbers.
    exports.variance = variance = function (x) {
        return sum(deviation(x).map(function (xi) {
            return Math.pow(xi, 2);
        })) / (x.length - 1);
    };

 // Calculates the sample standard deviation.
 // @param {[number]} x Array of numbers.
    exports.standardDeviation = standardDeviation = function (x) {
        return Math.sqrt(variance(x));
    };

 // @param {[number]} x Array of numbers.
    exports.standardize = standardize = function (x) {
        var sd;
        sd = standardDeviation(x);
        return deviation(x).map(function (xi) {
            return xi / sd;
        });
    };

 // Calculates the Pearson correlation coefficient for two variables.
 // @param {[number]} x Array of numbers.
 // @param {[number]} y Array of numbers.
    exports.correlation = correlation = function (x, y) {
        x = standardize(x);
        y = standardize(y);
        return sum(x.map(function (xi, i) {
            return xi * y[i];
        })) / (x.length - 1);
    };

}(typeof exports === "undefined" ? this["stats"] = {} : exports));
<commit_msg>Use strict.<commit_after>(function (exports) {
    "use strict";

    var sum, mean, deviation, variance, standardDeviation, standardize, correlation;

 // @param {[number]} x Array of numbers.
    exports.sum = sum = function (x) {
        return x.reduce(function (previousValue, currentValue) {
            return previousValue + currentValue;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.mean = mean = function (x) {
        return sum(x) / x.length;
    };

 // @param {[number]} x Array of numbers.
    exports.deviation = deviation = function (x) {
        var xBar;
        xBar = mean(x);
        return x.map(function (xi) {
            return xi - xBar;
        });
    };

 // Calculates the sample variance.
 // @param {[number]} x Array of numbers.
    exports.variance = variance = function (x) {
        return sum(deviation(x).map(function (xi) {
            return Math.pow(xi, 2);
        })) / (x.length - 1);
    };

 // Calculates the sample standard deviation.
 // @param {[number]} x Array of numbers.
    exports.standardDeviation = standardDeviation = function (x) {
        return Math.sqrt(variance(x));
    };

 // @param {[number]} x Array of numbers.
    exports.standardize = standardize = function (x) {
        var sd;
        sd = standardDeviation(x);
        return deviation(x).map(function (xi) {
            return xi / sd;
        });
    };

 // Calculates the Pearson correlation coefficient for two variables.
 // @param {[number]} x Array of numbers.
 // @param {[number]} y Array of numbers.
    exports.correlation = correlation = function (x, y) {
        x = standardize(x);
        y = standardize(y);
        return sum(x.map(function (xi, i) {
            return xi * y[i];
        })) / (x.length - 1);
    };

}(typeof exports === "undefined" ? this.stats = {} : exports));
<|endoftext|>


<commit_before>(function (exports) {
    "use strict";

    var sum, mean, deviation, variance, standardDeviation, standardize, rank, correlation;

 // @param {[number]} x Array of numbers.
    exports.sum = sum = function (x) {
        return x.reduce(function (previousValue, currentValue) {
            return previousValue + currentValue;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.mean = mean = function (x) {
        return sum(x) / x.length;
    };

 // @param {[number]} x Array of numbers.
    exports.deviation = deviation = function (x) {
        var xBar;
        xBar = mean(x);
        return x.map(function (xi) {
            return xi - xBar;
        });
    };

 // Calculates the sample variance.
 // @param {[number]} x Array of numbers.
    exports.variance = variance = function (x) {
        return sum(deviation(x).map(function (xi) {
            return Math.pow(xi, 2);
        })) / (x.length - 1);
    };

 // Calculates the sample standard deviation.
 // @param {[number]} x Array of numbers.
    exports.standardDeviation = standardDeviation = function (x) {
        return Math.sqrt(variance(x));
    };

 // @param {[number]} x Array of numbers.
    exports.standardize = standardize = function (x) {
        var sd;
        sd = standardDeviation(x);
        return deviation(x).map(function (xi) {
            return xi / sd;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.rank = rank = function (x) {
        var ranks;
     // Copy array.
        ranks = x.slice();
     // Sort array.
        ranks.sort(function (a, b) {
            return a - b;
        });
     // Calculate ranks.
        return x.map(function (xi) {
            var rank, first, last;
         // Handle tied ranks.
            first = ranks.indexOf(xi);
            last = ranks.lastIndexOf(xi);
            if (first === last) {
                rank = first;
            } else {
                rank = (first + last) / 2;
            }
         // Add 1 because ranks start with 1.
            return rank + 1;
        });
    };

 // Calculates the Pearson correlation coefficient for two variables.
 // @param {[number]} x Array of numbers.
 // @param {[number]} y Array of numbers.
    exports.correlation = correlation = function (x, y) {
        x = standardize(x);
        y = standardize(y);
        return sum(x.map(function (xi, i) {
            return xi * y[i];
        })) / (x.length - 1);
    };

}(typeof exports === "undefined" ? this.stats = {} : exports));
<commit_msg>Add Spearman's rank correlation coefficient.<commit_after>(function (exports) {
    "use strict";

    var sum, mean, deviation, variance, standardDeviation, standardize, rank, correlation;

 // @param {[number]} x Array of numbers.
    exports.sum = sum = function (x) {
        return x.reduce(function (previousValue, currentValue) {
            return previousValue + currentValue;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.mean = mean = function (x) {
        return sum(x) / x.length;
    };

 // @param {[number]} x Array of numbers.
    exports.deviation = deviation = function (x) {
        var xBar;
        xBar = mean(x);
        return x.map(function (xi) {
            return xi - xBar;
        });
    };

 // Calculates the sample variance.
 // @param {[number]} x Array of numbers.
    exports.variance = variance = function (x) {
        return sum(deviation(x).map(function (xi) {
            return Math.pow(xi, 2);
        })) / (x.length - 1);
    };

 // Calculates the sample standard deviation.
 // @param {[number]} x Array of numbers.
    exports.standardDeviation = standardDeviation = function (x) {
        return Math.sqrt(variance(x));
    };

 // @param {[number]} x Array of numbers.
    exports.standardize = standardize = function (x) {
        var sd;
        sd = standardDeviation(x);
        return deviation(x).map(function (xi) {
            return xi / sd;
        });
    };

 // @param {[number]} x Array of numbers.
    exports.rank = rank = function (x) {
        var ranks;
     // Copy array.
        ranks = x.slice();
     // Sort array.
        ranks.sort(function (a, b) {
            return a - b;
        });
     // Calculate ranks.
        return x.map(function (xi) {
            var rank, first, last;
         // Handle tied ranks.
            first = ranks.indexOf(xi);
            last = ranks.lastIndexOf(xi);
            if (first === last) {
                rank = first;
            } else {
                rank = (first + last) / 2;
            }
         // Add 1 because ranks start with 1.
            return rank + 1;
        });
    };

 // Calculates the correlation coefficient for two variables.
 // @param {[number]} x Array of numbers.
 // @param {[number]} y Array of numbers.
 // @param {string} method "pearson" (default) or "spearman".
    exports.correlation = correlation = function (x, y, method) {
        if (["pearson", "spearman"].indexOf(method) === -1) {
            method = "pearson";
        }
        switch (method) {
            case "pearson":
                x = standardize(x);
                y = standardize(y);
                return sum(x.map(function (xi, i) {
                    return xi * y[i];
                })) / (x.length - 1);
                break;
            case "spearman":
                x = rank(x);
                y = rank(y);
                return 1 - ((6 * sum(x.map(function (xi, i) {
                    return Math.pow(xi - y[i], 2);
                }))) / (x.length * (Math.pow(x.length, 2) - 1)));
                break;
        }
    };

}(typeof exports === "undefined" ? this.stats = {} : exports));
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import { Image, StyleSheet, Text, View, ToastAndroid } from 'react-native';
import { Button } from 'react-native-ui-components';
import Icon from 'react-native-vector-icons/FontAwesome';

import { navStrings } from '../localization';
import { SETTINGS_KEYS } from '../settings';

import globalStyles, { APP_FONT_FAMILY, SHADOW_BORDER, GREY, WARMER_GREY } from '../globalStyles';

const { SYNC_SITE_NAME } = SETTINGS_KEYS;

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.databaseListenerId = null;
  }

  exportData = async () => {
    const { settings, database } = this.props;
    const syncSiteName = settings.get(SYNC_SITE_NAME);
    const { success, error } = await database.exportData(syncSiteName);
    let toastMessage;
    if (success) {
      toastMessage = 'Exported data file';
    } else {
      const { message } = error;
      toastMessage = `Couldn't export data: ${message}`;
    }
    ToastAndroid.show(toastMessage, ToastAndroid.SHORT);
  };

  render() {
    const { isInAdminMode, logOut, navigateTo } = this.props;
    return (
      <View style={[globalStyles.pageContentContainer, localStyles.pageContentContainer]}>
        <View style={[globalStyles.horizontalContainer, localStyles.horizontalContainer]}>
          <View style={localStyles.container}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_people.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.customer_invoices}
              onPress={() => navigateTo('customerInvoices', navStrings.customer_invoices)}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.customer_requisitions}
              onPress={() => navigateTo('customerRequisitions', navStrings.customer_requisitions)}
            />
          </View>

          <View style={[localStyles.container, localStyles.centralContainer]}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_truck.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.supplier_invoices}
              onPress={() => navigateTo('supplierInvoices', navStrings.supplier_invoices)}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.supplier_requisitions}
              onPress={() => navigateTo('supplierRequisitions', navStrings.supplier_requisitions)}
            />
            {isInAdminMode && (
              <Button
                style={globalStyles.menuButton}
                textStyle={globalStyles.menuButtonText}
                text="Export Data"
                onPress={this.exportData}
              />
            )}
          </View>

          <View style={localStyles.container}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_pc_clipboard.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.current_stock}
              onPress={() => navigateTo('stock', navStrings.current_stock)}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.stocktakes}
              onPress={() => navigateTo('stocktakes', navStrings.stocktakes)}
            />
            {isInAdminMode && (
              <Button
                style={globalStyles.menuButton}
                textStyle={globalStyles.menuButtonText}
                text="Realm Explorer"
                onPress={() => navigateTo('realmExplorer', 'Database Contents')}
              />
            )}
          </View>
        </View>
        <View style={globalStyles.bottomContainer}>
          <Icon.Button
            name="power-off"
            underlayColor="#888888"
            iconStyle={localStyles.bottomIcon}
            borderRadius={4}
            backgroundColor="rgba(255,255,255,0)"
            onPress={logOut}
          >
            <Text style={localStyles.logOutText}>{navStrings.log_out}</Text>
          </Icon.Button>
        </View>
      </View>
    );
  }
}

export const MenuPage = connect()(Menu);

/* eslint-disable react/require-default-props, react/forbid-prop-types */
Menu.propTypes = {
  database: PropTypes.object.isRequired,
  isInAdminMode: PropTypes.bool,
  logOut: PropTypes.func.isRequired,
  navigateTo: PropTypes.func.isRequired,
  settings: PropTypes.object.isRequired,
};

const localStyles = StyleSheet.create({
  pageContentContainer: {
    padding: 0,
  },
  horizontalContainer: {
    flex: 9,
    justifyContent: 'space-between',
  },
  container: {
    alignSelf: 'stretch',
    flex: 1,
    paddingTop: 30,
    paddingHorizontal: 30,
    borderColor: SHADOW_BORDER,
    borderWidth: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    backgroundColor: 'white',
  },
  centralContainer: {
    marginHorizontal: 40,
  },
  image: {
    height: 150,
    width: 150,
    marginBottom: 30,
  },
  logOutText: {
    fontFamily: APP_FONT_FAMILY,
    color: WARMER_GREY,
  },
  bottomIcon: {
    color: GREY,
  },
});
<commit_msg>Add mapping of dispatch to props in MenuPage<commit_after>/* eslint-disable react/forbid-prop-types */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import { Image, StyleSheet, Text, View, ToastAndroid } from 'react-native';
import { Button } from 'react-native-ui-components';
import Icon from 'react-native-vector-icons/FontAwesome';

import { navStrings } from '../localization';
import { SETTINGS_KEYS } from '../settings';

import globalStyles, { APP_FONT_FAMILY, SHADOW_BORDER, GREY, WARMER_GREY } from '../globalStyles';
import {
  gotoCustomerInvoices,
  gotoCustomerRequisitions,
  gotoSupplierInvoices,
  gotoSupplierRequisitions,
  gotoStock,
  gotoStocktakes,
  gotoRealmExplorer,
} from '../navigation/actions';

const { SYNC_SITE_NAME } = SETTINGS_KEYS;

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.databaseListenerId = null;
  }

  exportData = async () => {
    const { settings, database } = this.props;
    const syncSiteName = settings.get(SYNC_SITE_NAME);
    const { success, error } = await database.exportData(syncSiteName);
    let toastMessage;
    if (success) {
      toastMessage = 'Exported data file';
    } else {
      const { message } = error;
      toastMessage = `Couldn't export data: ${message}`;
    }
    ToastAndroid.show(toastMessage, ToastAndroid.SHORT);
  };

  render() {
    const {
      isInAdminMode,
      logOut,
      navigateToCustomerInvoices,
      navigateToCustomerRequisitions,
      navigateToStock,
      navigateToStocktakes,
      navigateToSupplierInvoices,
      navigateToSupplierRequisitions,
      navigateToRealmExplorer,
    } = this.props;

    return (
      <View style={[globalStyles.pageContentContainer, localStyles.pageContentContainer]}>
        <View style={[globalStyles.horizontalContainer, localStyles.horizontalContainer]}>
          <View style={localStyles.container}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_people.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.customer_invoices}
              onPress={navigateToCustomerInvoices}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.customer_requisitions}
              onPress={navigateToCustomerRequisitions}
            />
          </View>

          <View style={[localStyles.container, localStyles.centralContainer]}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_truck.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.supplier_invoices}
              onPress={navigateToSupplierInvoices}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.supplier_requisitions}
              onPress={navigateToSupplierRequisitions}
            />
            {isInAdminMode && (
              <Button
                style={globalStyles.menuButton}
                textStyle={globalStyles.menuButtonText}
                text="Export Data"
                onPress={this.exportData}
              />
            )}
          </View>

          <View style={localStyles.container}>
            <Image
              style={localStyles.image}
              resizeMode="contain"
              // eslint-disable-next-line global-require
              source={require('../images/menu_pc_clipboard.png')}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.current_stock}
              onPress={navigateToStock}
            />
            <Button
              style={globalStyles.menuButton}
              textStyle={globalStyles.menuButtonText}
              text={navStrings.stocktakes}
              onPress={navigateToStocktakes}
            />
            {isInAdminMode && (
              <Button
                style={globalStyles.menuButton}
                textStyle={globalStyles.menuButtonText}
                text="Realm Explorer"
                onPress={navigateToRealmExplorer}
              />
            )}
          </View>
        </View>
        <View style={globalStyles.bottomContainer}>
          <Icon.Button
            name="power-off"
            underlayColor="#888888"
            iconStyle={localStyles.bottomIcon}
            borderRadius={4}
            backgroundColor="rgba(255,255,255,0)"
            onPress={logOut}
          >
            <Text style={localStyles.logOutText}>{navStrings.log_out}</Text>
          </Icon.Button>
        </View>
      </View>
    );
  }
}

const actionCreators = {
  navigateToCustomerInvoices: gotoCustomerInvoices,
  navigateToCustomerRequisitions: gotoCustomerRequisitions,
  navigateToStock: gotoStock,
  navigateToStocktakes: gotoStocktakes,
  navigateToSupplierInvoices: gotoSupplierInvoices,
  navigateToSupplierRequisitions: gotoSupplierRequisitions,
  navigateToRealmExplorer: gotoRealmExplorer,
};

export const MenuPage = connect(
  null,
  actionCreators
)(Menu);

Menu.defaultProps = {
  isInAdminMode: false,
};

Menu.propTypes = {
  database: PropTypes.object.isRequired,
  isInAdminMode: PropTypes.bool,
  logOut: PropTypes.func.isRequired,
  settings: PropTypes.object.isRequired,
  navigateToCustomerInvoices: PropTypes.func.isRequired,
  navigateToCustomerRequisitions: PropTypes.func.isRequired,
  navigateToStock: PropTypes.func.isRequired,
  navigateToStocktakes: PropTypes.func.isRequired,
  navigateToSupplierInvoices: PropTypes.func.isRequired,
  navigateToSupplierRequisitions: PropTypes.func.isRequired,
  navigateToRealmExplorer: PropTypes.func.isRequired,
};

const localStyles = StyleSheet.create({
  pageContentContainer: {
    padding: 0,
  },
  horizontalContainer: {
    flex: 9,
    justifyContent: 'space-between',
  },
  container: {
    alignSelf: 'stretch',
    flex: 1,
    paddingTop: 30,
    paddingHorizontal: 30,
    borderColor: SHADOW_BORDER,
    borderWidth: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    backgroundColor: 'white',
  },
  centralContainer: {
    marginHorizontal: 40,
  },
  image: {
    height: 150,
    width: 150,
    marginBottom: 30,
  },
  logOutText: {
    fontFamily: APP_FONT_FAMILY,
    color: WARMER_GREY,
  },
  bottomIcon: {
    color: GREY,
  },
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

const fs = require('fs');
const xml2js = require('xml2js');

const config = require('./config');

var parser = new xml2js.Parser();
function parse1(fileName) {
	return new Promise((response, reject) => {
		fs.readFile(fileName, function(err, data) {
			parser.parseString(data, function(error, result) {
				if (error) reject(error);

				const modsXML = result['METS:mets']['mets:dmdSec'][0]['mets:mdWrap'][0]['mets:xmlData'][0]['mods:mods'][0];
				const detailsXML = modsXML['mods:relatedItem'][0]['mods:part'][0]['mods:detail'];

				const title = modsXML['mods:titleInfo'][0]['mods:title'][0];
				const dateIssued = modsXML['mods:originInfo'][0]['mods:dateIssued'][0]['_'];
				const details = detailsXML.map(detail => ({
					caption: detail['mods:caption'][0],
					number: detail['mods:number'][0],
				}));
				response({ title, dateIssued, details });
			});
		});
	})
}

const file1 = `${config.dataDir}/metadata/DOCS/19300101_0/19300101_0-METS.xml`;
parse1(file1)
	.then(data => {
		console.log(JSON.stringify(data, null, 2));
	})
<commit_msg>improved meta data parsing<commit_after>#!/usr/bin/env node

const fs = require('fs');
const xml2js = require('xml2js');

const config = require('./config');

const idRegEx = /FID-F_SBB_\d+_(\d+_\d+_\d+)_(\d+)_(\d+)-OCRMASTER-TECHMD/;

const parser = new xml2js.Parser();
function xml2obj(fileName) {
	return new Promise((resolve, reject) => {
		fs.readFile(fileName, function(err, data) {
			parser.parseString(data, function(error, result) {
				if (error) reject(error);
				else resolve(result);
			})
		})
	});
}

function parse1(fileName) {
	return xml2obj(fileName).then(result => {
		const rootXML = result['METS:mets'];
		const modsXML =
			rootXML['mets:dmdSec'][0]['mets:mdWrap'][0]['mets:xmlData'][0]['mods:mods'][0];
		const detailsXML = modsXML['mods:relatedItem'][0]['mods:part'][0]['mods:detail'];
		const pagesXML = rootXML['mets:amdSec'][0]['mets:techMD'];

		const pages = pagesXML.map(pageXML => {
			const id = pageXML['$'].ID;
			return {
				id,
				idParts: idRegEx.exec(id).slice(1),
				dpi:
					pageXML['mets:mdWrap'][0]['mets:xmlData'][0]['mix:mix'][0][
						'mix:ImageAssessmentMetadata'
					][0]['mix:SpatialMetrics'][0]['mix:xSamplingFrequency'][0]['mix:numerator'][0],
			};
		});

		const title = modsXML['mods:titleInfo'][0]['mods:title'][0];
		const dateIssued = modsXML['mods:originInfo'][0]['mods:dateIssued'][0]['_'];
		const details = detailsXML.map(detail => ({
			caption: detail['mods:caption'][0],
			number: detail['mods:number'][0],
		}));
		return { title, dateIssued, details, pages };
	});
}

function zeroPad(num, size) {
  const s = `000000000${num}`;
  return s.substr(s.length - size);
}

const baseDir = `${config.dataDir}/metadata/DOCS/19300101_0`
const file1 = `${baseDir}/19300101_0-METS.xml`;
parse1(file1).then(data => {

	// FID-F_SBB_00009_19300101_078_001_0_004-OCRMASTER-TECHMD
	// 18900930_038_228_2-0001.xml
	Promise.all(data.pages.map(page => {
		const p = page.idParts
		return xml2obj(`${baseDir}/ALTO/${p[0]}_${p[1]}-${zeroPad(parseInt(p[2],10),4)}.xml`).then(result => {
			console.log("result", result);
			const PrintSpaceXML = result['alto']['Layout'][0]['Page'][0]['PrintSpace'];
			console.log("PrintSpaceXML", PrintSpaceXML);
		});
	}));
	// console.log(JSON.stringify(data, null, 2));
});
<|endoftext|>