<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.m.StandardListItem.
sap.ui.define([
	'./ListItemBase',
	'./library',
	'sap/ui/core/IconPool',
	'sap/ui/core/Icon',
	'./TreeItemBaseRenderer',
	'sap/ui/events/KeyCodes'
],
	function(ListItemBase, library, IconPool, Icon, TreeItemBaseRenderer, KeyCodes) {
	"use strict";

	// shortcut for sap.m.ListMode
	var ListMode = library.ListMode;

	/**
	 * Constructor for a new TreeItemBase.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * The sap.m.TreeItemBase contains the basic features of all specific tree items.
	 * @extends sap.m.ListItemBase
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.42.0
	 * @alias sap.m.TreeItemBase
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var TreeItemBase = ListItemBase.extend("sap.m.TreeItemBase", /** @lends sap.m.TreeItemBase.prototype */ { metadata : {
		library : "sap.m"
	}});

	TreeItemBase.prototype.ExpandedIconURI = IconPool.getIconURI("navigation-down-arrow");
	TreeItemBase.prototype.CollapsedIconURI = IconPool.getIconURI("navigation-right-arrow");

	TreeItemBase.prototype.getTree = function() {
		var oParent = this.getParent();
		if (oParent && oParent.isA("sap.m.Tree")) {
			return oParent;
		}
	};

	TreeItemBase.prototype.getList = TreeItemBase.prototype.getTree;
	TreeItemBase.prototype.informTree = TreeItemBase.prototype.informList;

	/**
	 * Gets the context of the node.
	 *
	 * @returns {Object}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getItemNodeContext = function() {
		var oTree = this.getTree();
		var oNode = null;
		var oBinding = oTree ? oTree.getBinding("items") : null;

		if (oTree && oBinding) {
			oBinding = oTree.getBinding("items");
			oNode = oBinding.getNodeByIndex(oTree.indexOfItem(this));
		}

		return oNode;
	};

	/**
	 * Gets the parent node control.
	 *
	 * @returns {sap.m.TreeItemBase | undefined}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getParentNode = function() {

		if (this.isTopLevel()) {
			return;
		}

		var oTree = this.getTree(),
			iNodeLevel = this.getLevel(),
			oParentNode = null,
			i = oTree.indexOfItem(this) - 1,
			aItems = oTree.getItems(),
			iLevel;

		while (i >= 0) {
			iLevel = aItems[i].getLevel();
			if (iLevel === iNodeLevel - 1) {
				oParentNode = aItems[i];
				break;
			}
			i--;
		}

		return oParentNode;
	};

	/**
	 * Gets the context of the parent node control.
	 *
	 * @returns {Object}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getParentNodeContext = function() {
		return this.getItemNodeContext().parent;
	};

	/**
	 * Determines if the node is a leaf.
	 *
	 * @returns {boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.isLeaf = function() {
		var oTree = this.getTree(),
			oNode = this.getItemNodeContext();

		return oNode ? !oTree.getBinding("items").nodeHasChildren(oNode) : false;
	};

	/**
	 * Checks if the node is the top level node.
	 *
	 * @returns {boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.isTopLevel = function() {
		return (this.getLevel() === 0);
	};

	/**
	 * Gets the node level in the hierarchy.
	 *
	 * @returns {int}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getLevel = function() {
		return (this.getItemNodeContext() || {}).level;
	};

	/**
	 * Gets the expanding information of the node.
	 *
	 * @returns {Boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getExpanded = function() {
		var oTree = this.getTree();
		if (!oTree) {
			return false;
		}

		var iIndex = oTree.indexOfItem(this);
		var oBinding = oTree.getBinding("items");
		return (oBinding && oBinding.isExpanded(iIndex));
	};

	TreeItemBase.prototype.setSelected = function (bSelected) {
		ListItemBase.prototype.setSelected.apply(this, arguments);

		// update the binding context
		var oTree = this.getTree();
		var oBinding = oTree ? oTree.getBinding("items") : null;
		var iIndex = -1;

		if (oTree && oBinding) {
			iIndex = oTree.indexOfItem(this);
			if (oTree.getMode() === ListMode.SingleSelect) {
				oBinding.setSelectedIndex(iIndex);
			}
			if (oTree.getMode() === ListMode.MultiSelect) {
				if (bSelected) {
					oBinding.addSelectionInterval(iIndex, iIndex);
				} else {
					oBinding.removeSelectionInterval(iIndex, iIndex);
				}
			}
		}

		return this;
	};

	/**
	 * Gets the expander control for rendering purposes.
	 *
	 * @returns {Boolean}
	 * @private
	 * @since 1.42.0
	 */
	TreeItemBase.prototype._getExpanderControl = function() {
		var sSrc = this.CollapsedIconURI,
			oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"),
			sIconTooltip = oBundle.getText("TREE_ITEM_EXPAND_NODE");

		if (this.getExpanded()) {
			sSrc = this.ExpandedIconURI;
			sIconTooltip = oBundle.getText("TREE_ITEM_COLLAPSE_NODE");
		}

		if (this._oExpanderControl) {
			this._oExpanderControl.setSrc(sSrc);
			this._oExpanderControl.setTooltip(sIconTooltip);
			return this._oExpanderControl;
		}

		this._oExpanderControl = new Icon({
			id: this.getId() + "-expander",
			src: sSrc,
			tooltip: sIconTooltip,
			noTabStop: true
		}).setParent(this, null, true).addStyleClass("sapMTreeItemBaseExpander").attachPress(function(oEvent) {
			this.informTree("ExpanderPressed");
		}, this);

		return this._oExpanderControl;
	};

	/**
	 * Updates the item by assigning the relavant expander, styles and attributes.
	 *
	 * @private
	 * @since 1.46.0
	 */
	TreeItemBase.prototype._updateItem = function() {
		if (this._bInvalidated) {
			return;
		}

		var oTree = this.getTree();
		if (oTree && oTree._bInvalidated) {
			return;
		}

		if (this._oExpanderControl) {
			var sSrc = this.CollapsedIconURI;
			if (this.getExpanded()) {
				sSrc = this.ExpandedIconURI;
			}
			this._oExpanderControl.setSrc(sSrc);

			// make the expander visible
			var $this = this.$();
			// adapt the tree items styles and the expander
			if (!this.isLeaf()) {
				$this.removeClass("sapMTreeItemBaseLeaf");
				$this.attr("aria-expanded", this.getExpanded());
			} else {
				$this.addClass("sapMTreeItemBaseLeaf");
				$this.removeAttr("aria-expanded");
			}
			$this.toggleClass("sapMTreeItemBaseChildren", !this.isTopLevel());
			// adapt aria-level (in cases like sorting of the tree items is performed)
			$this.attr("aria-level", this.getLevel() + 1);

			// update the indentation again
			var iIndentation = this._getPadding(),
				sStyleRule = sap.ui.getCore().getConfiguration().getRTL() ? "paddingRight" : "paddingLeft";
			$this.css(sStyleRule, iIndentation + "rem");

		}

	};

	TreeItemBase.prototype.invalidate = function() {
		ListItemBase.prototype.invalidate.apply(this, arguments);
		this._bInvalidated = true;
	};

	TreeItemBase.prototype.onAfterRendering = function() {
		ListItemBase.prototype.onAfterRendering.apply(this, arguments);
		this._bInvalidated = false;
	};

	TreeItemBase.prototype.setBindingContext = function() {
		ListItemBase.prototype.setBindingContext.apply(this, arguments);
		this._updateItem();
		return this;
	};

	/**
	 * Gets the indentation of the node for rendering purposes.
	 *
	 * @returns {Boolean}
	 * @private
	 * @since 1.42.0
	 */
	TreeItemBase.prototype._getPadding = function() {
		var oTree = this.getTree(),
		iNodeLevel = this.getLevel(),
		iIndentation = 0,
		iDeepestLevel;

		// use number count from hierarchy binding
		if (oTree) {
			iDeepestLevel = oTree.getDeepestLevel();
		}

		// for add node
		if (iDeepestLevel < iNodeLevel) {
			oTree._iDeepestLevel = iNodeLevel;
			iDeepestLevel = oTree._iDeepestLevel;
		}

		if (iDeepestLevel < 2) {
			iIndentation = iNodeLevel * 1.5;
		} else if (iDeepestLevel === 2) {
			iIndentation = iNodeLevel * 1;
		} else if (iDeepestLevel < 6) {
			iIndentation = iNodeLevel * 0.5;
		} else {
			iIndentation = iNodeLevel * 0.25;
		}

		return iIndentation;
	};

	/**
	 * The event is fired when + is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapplus = function(oEvent) {
		this.informTree("ExpanderPressed", true);
	};

	/**
	 * The event is fired when - is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapminus = function(oEvent) {
		this.informTree("ExpanderPressed", false);
	};

	/**
	 * The event is fired when the right arrow key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapright = function(oEvent) {
		if (oEvent.srcControl !== this || this.isLeaf()) {
			return;
		}

		if (!this.getExpanded()) {
			this.informTree("ExpanderPressed", true);
		} else {
			// Change the keyCode so that the item navigation handles the down navigation.
			oEvent.keyCode = KeyCodes.ARROW_DOWN;
		}

	};

	/**
	 * The event is fired when the left arrow key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapleft = function(oEvent) {
		if (oEvent.srcControl !== this || this.isTopLevel() && !this.getExpanded()) {
			return;
		}

		if (!this.isLeaf()) {
			if (this.getExpanded()) {
				this.informTree("ExpanderPressed", false);
			} else {
				this.getParentNode().focus();
			}
		} else {
			this.getParentNode().focus();
		}

	};

	/**
	 * The event is fired when the backspace key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapbackspace = function(oEvent) {
		// Only set focus on parent when the event is fired by item itself.
		// Prevent miss-set when the content of CustomTreeItem fires event.
		if (oEvent.srcControl !== this) {
			return;
		}

		if (!this.isTopLevel()) {
				this.getParentNode().focus();
		}

	};

	TreeItemBase.prototype.getAccessibilityType = function(oBundle) {
		return oBundle.getText("ACC_CTR_TYPE_TREEITEM");
	};

	TreeItemBase.prototype.exit = function() {
		ListItemBase.prototype.exit.apply(this, arguments);
		this.destroyControls(["Expander"]);
	};

	TreeItemBase.prototype.onlongdragover = function(oEvent) {
		this.informTree("LongDragOver");
	};

	return TreeItemBase;

});<commit_msg>[INTERNAL] TreeItemBase: fix double announcement when tree item is expanded<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.m.StandardListItem.
sap.ui.define([
	'./ListItemBase',
	'./library',
	'sap/ui/core/IconPool',
	'sap/ui/core/Icon',
	'./TreeItemBaseRenderer',
	'sap/ui/events/KeyCodes'
],
	function(ListItemBase, library, IconPool, Icon, TreeItemBaseRenderer, KeyCodes) {
	"use strict";

	// shortcut for sap.m.ListMode
	var ListMode = library.ListMode;

	/**
	 * Constructor for a new TreeItemBase.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * The sap.m.TreeItemBase contains the basic features of all specific tree items.
	 * @extends sap.m.ListItemBase
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.42.0
	 * @alias sap.m.TreeItemBase
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var TreeItemBase = ListItemBase.extend("sap.m.TreeItemBase", /** @lends sap.m.TreeItemBase.prototype */ { metadata : {
		library : "sap.m"
	}});

	TreeItemBase.prototype.ExpandedIconURI = IconPool.getIconURI("navigation-down-arrow");
	TreeItemBase.prototype.CollapsedIconURI = IconPool.getIconURI("navigation-right-arrow");

	TreeItemBase.prototype.getTree = function() {
		var oParent = this.getParent();
		if (oParent && oParent.isA("sap.m.Tree")) {
			return oParent;
		}
	};

	TreeItemBase.prototype.getList = TreeItemBase.prototype.getTree;
	TreeItemBase.prototype.informTree = TreeItemBase.prototype.informList;

	/**
	 * Gets the context of the node.
	 *
	 * @returns {Object}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getItemNodeContext = function() {
		var oTree = this.getTree();
		var oNode = null;
		var oBinding = oTree ? oTree.getBinding("items") : null;

		if (oTree && oBinding) {
			oBinding = oTree.getBinding("items");
			oNode = oBinding.getNodeByIndex(oTree.indexOfItem(this));
		}

		return oNode;
	};

	/**
	 * Gets the parent node control.
	 *
	 * @returns {sap.m.TreeItemBase | undefined}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getParentNode = function() {

		if (this.isTopLevel()) {
			return;
		}

		var oTree = this.getTree(),
			iNodeLevel = this.getLevel(),
			oParentNode = null,
			i = oTree.indexOfItem(this) - 1,
			aItems = oTree.getItems(),
			iLevel;

		while (i >= 0) {
			iLevel = aItems[i].getLevel();
			if (iLevel === iNodeLevel - 1) {
				oParentNode = aItems[i];
				break;
			}
			i--;
		}

		return oParentNode;
	};

	/**
	 * Gets the context of the parent node control.
	 *
	 * @returns {Object}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getParentNodeContext = function() {
		return this.getItemNodeContext().parent;
	};

	/**
	 * Determines if the node is a leaf.
	 *
	 * @returns {boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.isLeaf = function() {
		var oTree = this.getTree(),
			oNode = this.getItemNodeContext();

		return oNode ? !oTree.getBinding("items").nodeHasChildren(oNode) : false;
	};

	/**
	 * Checks if the node is the top level node.
	 *
	 * @returns {boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.isTopLevel = function() {
		return (this.getLevel() === 0);
	};

	/**
	 * Gets the node level in the hierarchy.
	 *
	 * @returns {int}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getLevel = function() {
		return (this.getItemNodeContext() || {}).level;
	};

	/**
	 * Gets the expanding information of the node.
	 *
	 * @returns {Boolean}
	 * @public
	 * @since 1.42.0
	 */
	TreeItemBase.prototype.getExpanded = function() {
		var oTree = this.getTree();
		if (!oTree) {
			return false;
		}

		var iIndex = oTree.indexOfItem(this);
		var oBinding = oTree.getBinding("items");
		return (oBinding && oBinding.isExpanded(iIndex));
	};

	TreeItemBase.prototype.setSelected = function (bSelected) {
		ListItemBase.prototype.setSelected.apply(this, arguments);

		// update the binding context
		var oTree = this.getTree();
		var oBinding = oTree ? oTree.getBinding("items") : null;
		var iIndex = -1;

		if (oTree && oBinding) {
			iIndex = oTree.indexOfItem(this);
			if (oTree.getMode() === ListMode.SingleSelect) {
				oBinding.setSelectedIndex(iIndex);
			}
			if (oTree.getMode() === ListMode.MultiSelect) {
				if (bSelected) {
					oBinding.addSelectionInterval(iIndex, iIndex);
				} else {
					oBinding.removeSelectionInterval(iIndex, iIndex);
				}
			}
		}

		return this;
	};

	/**
	 * Gets the expander control for rendering purposes.
	 *
	 * @returns {Boolean}
	 * @private
	 * @since 1.42.0
	 */
	TreeItemBase.prototype._getExpanderControl = function() {
		var sSrc = this.CollapsedIconURI,
			oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"),
			sIconTooltip = oBundle.getText("TREE_ITEM_EXPAND_NODE");

		if (this.getExpanded()) {
			sSrc = this.ExpandedIconURI;
			sIconTooltip = oBundle.getText("TREE_ITEM_COLLAPSE_NODE");
		}

		if (this._oExpanderControl) {
			this._oExpanderControl.setSrc(sSrc);
			this._oExpanderControl.setTooltip(sIconTooltip);
			return this._oExpanderControl;
		}

		this._oExpanderControl = new Icon({
			id: this.getId() + "-expander",
			src: sSrc,
			tooltip: sIconTooltip,
			noTabStop: true
		}).setParent(this, null, true).addStyleClass("sapMTreeItemBaseExpander").attachPress(function(oEvent) {
			this.informTree("ExpanderPressed");
		}, this);

		return this._oExpanderControl;
	};

	TreeItemBase.prototype.invalidate = function() {
		ListItemBase.prototype.invalidate.apply(this, arguments);
		this._bInvalidated = true;
	};

	TreeItemBase.prototype.onAfterRendering = function() {
		ListItemBase.prototype.onAfterRendering.apply(this, arguments);
		this._bInvalidated = false;
	};

	TreeItemBase.prototype.setBindingContext = function() {
		ListItemBase.prototype.setBindingContext.apply(this, arguments);
		this.invalidate();
		return this;
	};

	/**
	 * Gets the indentation of the node for rendering purposes.
	 *
	 * @returns {Boolean}
	 * @private
	 * @since 1.42.0
	 */
	TreeItemBase.prototype._getPadding = function() {
		var oTree = this.getTree(),
		iNodeLevel = this.getLevel(),
		iIndentation = 0,
		iDeepestLevel;

		// use number count from hierarchy binding
		if (oTree) {
			iDeepestLevel = oTree.getDeepestLevel();
		}

		// for add node
		if (iDeepestLevel < iNodeLevel) {
			oTree._iDeepestLevel = iNodeLevel;
			iDeepestLevel = oTree._iDeepestLevel;
		}

		if (iDeepestLevel < 2) {
			iIndentation = iNodeLevel * 1.5;
		} else if (iDeepestLevel === 2) {
			iIndentation = iNodeLevel * 1;
		} else if (iDeepestLevel < 6) {
			iIndentation = iNodeLevel * 0.5;
		} else {
			iIndentation = iNodeLevel * 0.25;
		}

		return iIndentation;
	};

	/**
	 * The event is fired when + is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapplus = function(oEvent) {
		this.informTree("ExpanderPressed", true);
	};

	/**
	 * The event is fired when - is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapminus = function(oEvent) {
		this.informTree("ExpanderPressed", false);
	};

	/**
	 * The event is fired when the right arrow key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapright = function(oEvent) {
		if (oEvent.srcControl !== this || this.isLeaf()) {
			return;
		}

		if (!this.getExpanded()) {
			this.informTree("ExpanderPressed", true);
		} else {
			// Change the keyCode so that the item navigation handles the down navigation.
			oEvent.keyCode = KeyCodes.ARROW_DOWN;
		}

	};

	/**
	 * The event is fired when the left arrow key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapleft = function(oEvent) {
		if (oEvent.srcControl !== this || this.isTopLevel() && !this.getExpanded()) {
			return;
		}

		if (!this.isLeaf()) {
			if (this.getExpanded()) {
				this.informTree("ExpanderPressed", false);
			} else {
				this.getParentNode().focus();
			}
		} else {
			this.getParentNode().focus();
		}

	};

	/**
	 * The event is fired when the backspace key is pressed.
	 *
	 * @param {jQuery.Event} The event object.
	 */
	TreeItemBase.prototype.onsapbackspace = function(oEvent) {
		// Only set focus on parent when the event is fired by item itself.
		// Prevent miss-set when the content of CustomTreeItem fires event.
		if (oEvent.srcControl !== this) {
			return;
		}

		if (!this.isTopLevel()) {
				this.getParentNode().focus();
		}

	};

	TreeItemBase.prototype.getAccessibilityType = function(oBundle) {
		return oBundle.getText("ACC_CTR_TYPE_TREEITEM");
	};

	TreeItemBase.prototype.exit = function() {
		ListItemBase.prototype.exit.apply(this, arguments);
		this.destroyControls(["Expander"]);
	};

	TreeItemBase.prototype.onlongdragover = function(oEvent) {
		this.informTree("LongDragOver");
	};

	return TreeItemBase;

});<|endoftext|>


<commit_before>const { iff, isProvider } = require('feathers-hooks-common');
const { Configuration } = require('@schul-cloud/commons');
const { NotAuthenticated } = require('@feathersjs/errors');

const checkForKey = (context) => {
	const key = context.params.headers['x-api-key'];
	if (!key === Configuration.get('CLIENT_API_KEY')) throw new NotAuthenticated('no permission');
	return context;
}

module.exports = {
	before: {
		all: [iff(isProvider('external'), [
			checkForKey,
		])],
	},
}<commit_msg>lint<commit_after>const { iff, isProvider } = require('feathers-hooks-common');
const { Configuration } = require('@schul-cloud/commons');
const { NotAuthenticated } = require('@feathersjs/errors');

const checkForKey = (context) => {
	const key = context.params.headers['x-api-key'];
	if (!key === Configuration.get('CLIENT_API_KEY')) throw new NotAuthenticated('no permission');
	return context;
};

module.exports = {
	before: {
		all: [iff(isProvider('external'), [
			checkForKey,
		])],
	},
};
<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const reqlib = require('app-root-path').require;

const errorHandlers = require('./errors');

const { Forbidden } = reqlib('src/errors');

class LdapConfigService {
	setup(app) {
		this.app = app;
	}

	/**
	 * `GET /ldap-config/:systemId`
	 * Returns the ldapConfig of a given system in the same format as accepted
	 * by the other methods of this service.
	 * If the given system is not a LDAP system (i.e. does not have the ldapConfig
	 * attribute) or is not of the type `general` (i.e. a self-service config), the
	 * access is denied.
	 * To access the system data, the authentication information are proxied to the
	 * System service, so that access is only granted to administrators and only to
	 * systems of the own school.
	 * @param {ObjectId} systemId ID of an existing system with LDAP config
	 * @param {Object} params Feathers request params
	 * @returns {Object} ldapConfig attribute of the given system
	 */
	async get(systemId, params) {
		// Proxying the request params here to have the system service hooks check
		// the permissions, filtering sensitive data, etc.
		const system = await this.app.service('systems').get(systemId, params);
		if (!system.ldapConfig || system.ldapConfig.provider !== 'general') {
			throw new Forbidden('The requested system is not configurable with this endpoint');
		}
		return system.ldapConfig;
	}

	/**
	 * `POST /ldap-config`
	 * Creates a new system with the given LDAP config and attaches it to the
	 * caller's school, if the config is validated successfully. The validation
	 * result is returned.
	 * If `validateOnly === true`, changes are not persisted to the systems and
	 * school collection. Otherwise, a new system is created.
	 * After creating the system, if `activate !== false`, it is added as a login
	 * system to the caller's school and the school's ldapSchoolIdentifier attribute
	 * is set to the config's base path.
	 * @param {Object} config an LDAP config (given as JSON in request body)
	 * @param {Object} params Feathers request params
	 * @returns {Object} validation result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async create(config, params) {
		return this.verifyAndSaveLdapConfig(config, this.getOptions(params));
	}

	/**
	 * `PATCH /ldap-config/:systemId`
	 * Patches an existing system with the given LDAP config and attaches it to
	 * the caller's school if the config is validated successfully.
	 * If `validateOnly === true`, changes are not persisted to the systems and
	 * school collection. Otherwise, the system is patched.
	 * After patching the system, if `activate !== false`, it is added as a login
	 * system to the caller's school and the school's ldapSchoolIdentifier attribute
	 * is set to the config's base path.
	 * @param {ObjectId} id systemId of system to patch
	 * @param {Object} config LDAP config object
	 * @param {Object} params Feathers request params
	 * @returns validation result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async patch(id, config, params) {
		return this.verifyAndSaveLdapConfig(config, {
			...this.getOptions(params),
			systemId: id,
		});
	}

	/**
	 * Retrieves and returns options object to be used for #verifyAndSaveLdapConfig
	 * @param {Object} params feathers request params
	 * @returns {Object} options `{ school: School, activateSystem: Boolean, saveSystem: Boolean}`
	 */
	getOptions(params) {
		const { verifyOnly, activate } = params.query;

		const saveSystem = verifyOnly !== true && verifyOnly !== 'true';
		const activateSystem = activate !== false && activate !== 'false';

		return {
			school: params.school,
			activateSystem,
			saveSystem,
		};
	}

	/**
	 * Actual business logic to validate and save LDAP configs
	 * @param {Object} config config data
	 * @param {Object} options options object
	 * @returns {Object} verification result
	 */
	async verifyAndSaveLdapConfig(config, options) {
		const verificationResult = await this.verifyConfig(config);
		if (verificationResult.ok && options.saveSystem) {
			await this.saveConfig(config, options.school, options.systemId, options.activateSystem);
		}
		return verificationResult;
	}

	/**
	 * Verifies a given config by connecting to the server and retrieving sample
	 * objects. Errors are caught and categorized.
	 * @param {Object} config LDAP config object
	 * @returns {Object} verification result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async verifyConfig(config) {
		const ldap = this.app.service('ldap');
		const result = {
			ok: false,
			errors: [],
			users: {},
			classes: {},
		};
		try {
			const users = await ldap.getUsers(config);
			result.users = LdapConfigService.generateUserStats(users);
			if (LdapConfigService.shouldVerifyClasses(config)) {
				const classes = await ldap.getClasses(config);
				result.classes = LdapConfigService.generateClassStats(classes);
			}
			result.ok = true;
		} catch (error) {
			for (const { match, message, type } of errorHandlers) {
				if (match(error)) {
					result.errors.push({ message: message(error), type });
				}
			}
			if (result.errors.length === 0) {
				// Something unexpected happened, so let's push it to the logs and
				// tell the client that this was not planned
				throw error;
			}
		} finally {
			ldap.disconnect(config);
		}
		return result;
	}

	/**
	 * Saves (and optionally activates) an LDAP config for a given school.
	 * If no systemId is given, a new system will be created and assigned.
	 * @param {Object} config LDAP config object
	 * @param {School} school the school to update
	 * @param {Object} [systemId] optional id of the system to update
	 * @param {Boolean} [activate=true] optional value for `ldapConfig.active`
	 */
	async saveConfig(config, school, systemId = undefined, activate = true) {
		const systemService = await this.app.service('systems');
		const schoolsService = await this.app.service('schools');

		const system = LdapConfigService.constructSystem(config, school, activate);

		const session = await mongoose.startSession();
		await session.withTransaction(async () => {
			if (systemId) {
				// update existing system (already assigned to school)
				const thingsToDo = [systemService.patch(systemId, system)];
				if (activate) {
					thingsToDo.push(
						schoolsService.patch(school._id, {
							ldapSchoolIdentifier: config.rootPath,
						})
					);
				}
				await Promise.all(thingsToDo);
			} else {
				// create a new system and assign it to the school
				const { _id: newSystemId } = await systemService.create(system);
				if (activate) {
					await schoolsService.patch(school._id, {
						ldapSchoolIdentifier: config.rootPath,
						$addToSet: {
							systems: newSystemId,
						},
					});
				}
			}
		});
		await session.endSession();
	}

	/**
	 * Returns a system collection object based on an abbreviated LDAP config
	 * object and a school object. The school's name will be used for both system
	 * `alias` and `ldapConfig.providerOptions.schoolName`. Provider is always
	 * `general`. Type is always `ldap`.
	 * @static
	 * @param {Object} config LDAP config object
	 * @param {School} school the school at which to activate the system
	 * @param {boolean} [activate=true] optional value for `ldapConfig.active`
	 * @returns {System} system object to be used for creating or updating
	 */
	static constructSystem(config, school, activate = true) {
		return {
			type: 'ldap',
			alias: school.name,
			ldapConfig: {
				...config,
				provider: 'general',
				providerOptions: {
					...config.providerOptions,
					schoolName: school.name,
				},
				active: activate,
			},
		};
	}

	/**
	 * Generates statistics about LDAP verification result for users.
	 * @static
	 * @param {Array} [users=[]] array of users returned from LDAP provider strategy #getUsers
	 * @returns {Object} statistics
	 * `{ total: Number, admin: Number, teacher: Number, student: Number, sample: {} }`
	 */
	static generateUserStats(users = []) {
		const result = {
			total: users.length,
			admin: 0,
			teacher: 0,
			student: 0,
			sample: users.length > 0 ? users[0] : {},
		};
		for (const user of users) {
			if (user.roles.includes('administrator')) result.admin += 1;
			if (user.roles.includes('teacher')) result.teacher += 1;
			if (user.roles.includes('student')) result.student += 1;
		}
		return result;
	}

	/**
	 * Generates statistics about LDAP verification result for classes.
	 * @static
	 * @param {Array} [classes=[]] array of classes returned from LDAP provider strategy #getClasses
	 * @returns {Object} statistics
	 * `{ total: Number, sample: {} }`
	 */
	static generateClassStats(classes = []) {
		return {
			total: classes.length,
			sample: classes.length > 0 ? classes[0] : {},
		};
	}

	/**
	 * Determines whether a given config needs to sync classes.
	 * Specifically, returns `false` if classPathAdditions are undefined or empty
	 * and `true` otherwise
	 * @static
	 * @param {Object} config LDAP config object
	 * @returns {Boolean} true/false
	 */
	static shouldVerifyClasses(config) {
		return (
			config.providerOptions &&
			config.providerOptions.classPathAdditions &&
			config.providerOptions.classPathAdditions !== ''
		);
	}
}

module.exports = LdapConfigService;
<commit_msg>Protect against users without roles<commit_after>const mongoose = require('mongoose');
const reqlib = require('app-root-path').require;

const errorHandlers = require('./errors');

const { Forbidden } = reqlib('src/errors');

class LdapConfigService {
	setup(app) {
		this.app = app;
	}

	/**
	 * `GET /ldap-config/:systemId`
	 * Returns the ldapConfig of a given system in the same format as accepted
	 * by the other methods of this service.
	 * If the given system is not a LDAP system (i.e. does not have the ldapConfig
	 * attribute) or is not of the type `general` (i.e. a self-service config), the
	 * access is denied.
	 * To access the system data, the authentication information are proxied to the
	 * System service, so that access is only granted to administrators and only to
	 * systems of the own school.
	 * @param {ObjectId} systemId ID of an existing system with LDAP config
	 * @param {Object} params Feathers request params
	 * @returns {Object} ldapConfig attribute of the given system
	 */
	async get(systemId, params) {
		// Proxying the request params here to have the system service hooks check
		// the permissions, filtering sensitive data, etc.
		const system = await this.app.service('systems').get(systemId, params);
		if (!system.ldapConfig || system.ldapConfig.provider !== 'general') {
			throw new Forbidden('The requested system is not configurable with this endpoint');
		}
		return system.ldapConfig;
	}

	/**
	 * `POST /ldap-config`
	 * Creates a new system with the given LDAP config and attaches it to the
	 * caller's school, if the config is validated successfully. The validation
	 * result is returned.
	 * If `validateOnly === true`, changes are not persisted to the systems and
	 * school collection. Otherwise, a new system is created.
	 * After creating the system, if `activate !== false`, it is added as a login
	 * system to the caller's school and the school's ldapSchoolIdentifier attribute
	 * is set to the config's base path.
	 * @param {Object} config an LDAP config (given as JSON in request body)
	 * @param {Object} params Feathers request params
	 * @returns {Object} validation result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async create(config, params) {
		return this.verifyAndSaveLdapConfig(config, this.getOptions(params));
	}

	/**
	 * `PATCH /ldap-config/:systemId`
	 * Patches an existing system with the given LDAP config and attaches it to
	 * the caller's school if the config is validated successfully.
	 * If `validateOnly === true`, changes are not persisted to the systems and
	 * school collection. Otherwise, the system is patched.
	 * After patching the system, if `activate !== false`, it is added as a login
	 * system to the caller's school and the school's ldapSchoolIdentifier attribute
	 * is set to the config's base path.
	 * @param {ObjectId} id systemId of system to patch
	 * @param {Object} config LDAP config object
	 * @param {Object} params Feathers request params
	 * @returns validation result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async patch(id, config, params) {
		return this.verifyAndSaveLdapConfig(config, {
			...this.getOptions(params),
			systemId: id,
		});
	}

	/**
	 * Retrieves and returns options object to be used for #verifyAndSaveLdapConfig
	 * @param {Object} params feathers request params
	 * @returns {Object} options `{ school: School, activateSystem: Boolean, saveSystem: Boolean}`
	 */
	getOptions(params) {
		const { verifyOnly, activate } = params.query;

		const saveSystem = verifyOnly !== true && verifyOnly !== 'true';
		const activateSystem = activate !== false && activate !== 'false';

		return {
			school: params.school,
			activateSystem,
			saveSystem,
		};
	}

	/**
	 * Actual business logic to validate and save LDAP configs
	 * @param {Object} config config data
	 * @param {Object} options options object
	 * @returns {Object} verification result
	 */
	async verifyAndSaveLdapConfig(config, options) {
		const verificationResult = await this.verifyConfig(config);
		if (verificationResult.ok && options.saveSystem) {
			await this.saveConfig(config, options.school, options.systemId, options.activateSystem);
		}
		return verificationResult;
	}

	/**
	 * Verifies a given config by connecting to the server and retrieving sample
	 * objects. Errors are caught and categorized.
	 * @param {Object} config LDAP config object
	 * @returns {Object} verification result object
	 * `{ ok: Boolean, errors: [], users: {}, classes: {} }`
	 */
	async verifyConfig(config) {
		const ldap = this.app.service('ldap');
		const result = {
			ok: false,
			errors: [],
			users: {},
			classes: {},
		};
		try {
			const users = await ldap.getUsers(config);
			result.users = LdapConfigService.generateUserStats(users);
			if (LdapConfigService.shouldVerifyClasses(config)) {
				const classes = await ldap.getClasses(config);
				result.classes = LdapConfigService.generateClassStats(classes);
			}
			result.ok = true;
		} catch (error) {
			for (const { match, message, type } of errorHandlers) {
				if (match(error)) {
					result.errors.push({ message: message(error), type });
				}
			}
			if (result.errors.length === 0) {
				// Something unexpected happened, so let's push it to the logs and
				// tell the client that this was not planned
				throw error;
			}
		} finally {
			ldap.disconnect(config);
		}
		return result;
	}

	/**
	 * Saves (and optionally activates) an LDAP config for a given school.
	 * If no systemId is given, a new system will be created and assigned.
	 * @param {Object} config LDAP config object
	 * @param {School} school the school to update
	 * @param {Object} [systemId] optional id of the system to update
	 * @param {Boolean} [activate=true] optional value for `ldapConfig.active`
	 */
	async saveConfig(config, school, systemId = undefined, activate = true) {
		const systemService = await this.app.service('systems');
		const schoolsService = await this.app.service('schools');

		const system = LdapConfigService.constructSystem(config, school, activate);

		const session = await mongoose.startSession();
		await session.withTransaction(async () => {
			if (systemId) {
				// update existing system (already assigned to school)
				const thingsToDo = [systemService.patch(systemId, system)];
				if (activate) {
					thingsToDo.push(
						schoolsService.patch(school._id, {
							ldapSchoolIdentifier: config.rootPath,
						})
					);
				}
				await Promise.all(thingsToDo);
			} else {
				// create a new system and assign it to the school
				const { _id: newSystemId } = await systemService.create(system);
				if (activate) {
					await schoolsService.patch(school._id, {
						ldapSchoolIdentifier: config.rootPath,
						$addToSet: {
							systems: newSystemId,
						},
					});
				}
			}
		});
		await session.endSession();
	}

	/**
	 * Returns a system collection object based on an abbreviated LDAP config
	 * object and a school object. The school's name will be used for both system
	 * `alias` and `ldapConfig.providerOptions.schoolName`. Provider is always
	 * `general`. Type is always `ldap`.
	 * @static
	 * @param {Object} config LDAP config object
	 * @param {School} school the school at which to activate the system
	 * @param {boolean} [activate=true] optional value for `ldapConfig.active`
	 * @returns {System} system object to be used for creating or updating
	 */
	static constructSystem(config, school, activate = true) {
		return {
			type: 'ldap',
			alias: school.name,
			ldapConfig: {
				...config,
				provider: 'general',
				providerOptions: {
					...config.providerOptions,
					schoolName: school.name,
				},
				active: activate,
			},
		};
	}

	/**
	 * Generates statistics about LDAP verification result for users.
	 * @static
	 * @param {Array} [users=[]] array of users returned from LDAP provider strategy #getUsers
	 * @returns {Object} statistics
	 * `{ total: Number, admin: Number, teacher: Number, student: Number, sample: {} }`
	 */
	static generateUserStats(users = []) {
		const result = {
			total: users.length,
			admin: 0,
			teacher: 0,
			student: 0,
			sample: users.length > 0 ? users[0] : {},
		};
		for (const user of users) {
			const roles = user.roles || [];
			if (roles.includes('administrator')) result.admin += 1;
			if (roles.includes('teacher')) result.teacher += 1;
			if (roles.includes('student')) result.student += 1;
		}
		return result;
	}

	/**
	 * Generates statistics about LDAP verification result for classes.
	 * @static
	 * @param {Array} [classes=[]] array of classes returned from LDAP provider strategy #getClasses
	 * @returns {Object} statistics
	 * `{ total: Number, sample: {} }`
	 */
	static generateClassStats(classes = []) {
		return {
			total: classes.length,
			sample: classes.length > 0 ? classes[0] : {},
		};
	}

	/**
	 * Determines whether a given config needs to sync classes.
	 * Specifically, returns `false` if classPathAdditions are undefined or empty
	 * and `true` otherwise
	 * @static
	 * @param {Object} config LDAP config object
	 * @returns {Boolean} true/false
	 */
	static shouldVerifyClasses(config) {
		return (
			config.providerOptions &&
			config.providerOptions.classPathAdditions &&
			config.providerOptions.classPathAdditions !== ''
		);
	}
}

module.exports = LdapConfigService;
<|endoftext|>


<commit_before>define(['backbone', './main.jade', 'views/userMenu/userMenu', 'domain/net/auth', 'views/menu/menu', 'router',
        'views/entity/parentView', 'views/content/content'],
    function (Backbone, template) {

        var UserMenu = require('views/userMenu/userMenu'),
            Menu = require('views/menu/menu'),
            auth = require('domain/net/auth'),
            router = require('router'),
            Content = require('views/content/content'),
            ParentView = require('views/entity/parentView');

        return ParentView.extend({
            attributes: {
                class: 'v-main'
            },
            events: {
                'click [data-menu]': 'toggleLeftMenu'
            },
            initialize: function () {
                this.$el.html(template());
                this.renderUserMenu();
                this.renderMainMenu();
                this.renderContent();

                Backbone.history.start({pushState: true, root: '/pjax'});
            },
            toggleLeftMenu: function () {
               if (this.$('.leftPanel').hasClass('remove')) {
                    this.$('.leftPanel').removeClass('remove');
                } else {
                    this.$('.leftPanel').addClass('remove');
                }
            },
            renderUserMenu: function () {
                this.newChild(UserMenu, '.topPanel', {model: auth});
            },
            renderMainMenu: function () {
                this.newChild(Menu, '.mainMenuWrap');
            },
            renderContent: function () {
                this.newChild(Content, '[data-mainContent]');
            },
            newChild: function (View, el, data) {
                var v = new View(data);
                this.addChild(v);
                v.$el.appendTo(this.$(el));
                v.render();
            },
            remove: function () {
                Backbone.history.stop();
                ParentView.prototype.remove.apply(this);
            }
        });

    });<commit_msg>Backbone HIstory not stop<commit_after>define(['backbone', './main.jade', 'views/userMenu/userMenu', 'domain/net/auth', 'views/menu/menu', 'router',
        'views/entity/parentView', 'views/content/content'],
    function (Backbone, template) {

        var UserMenu = require('views/userMenu/userMenu'),
            Menu = require('views/menu/menu'),
            auth = require('domain/net/auth'),
            router = require('router'),
            Content = require('views/content/content'),
            ParentView = require('views/entity/parentView');

        return ParentView.extend({
            attributes: {
                class: 'v-main'
            },
            events: {
                'click [data-menu]': 'toggleLeftMenu'
            },
            initialize: function () {
                this.$el.html(template());
                this.renderUserMenu();
                this.renderMainMenu();
                this.renderContent();

                if (!Backbone.History.started) {
                    Backbone.history.start({pushState: true, root: '/pjax'});
                }
            },
            toggleLeftMenu: function () {
               if (this.$('.leftPanel').hasClass('remove')) {
                    this.$('.leftPanel').removeClass('remove');
                } else {
                    this.$('.leftPanel').addClass('remove');
                }
            },
            renderUserMenu: function () {
                this.newChild(UserMenu, '.topPanel', {model: auth});
            },
            renderMainMenu: function () {
                this.newChild(Menu, '.mainMenuWrap');
            },
            renderContent: function () {
                this.newChild(Content, '[data-mainContent]');
            },
            newChild: function (View, el, data) {
                var v = new View(data);
                this.addChild(v);
                v.$el.appendTo(this.$(el));
                v.render();
            },
            remove: function () {
                ParentView.prototype.remove.apply(this);
            }
        });

    });<|endoftext|>


<commit_before>var Scale = new Class({
    initialize: function(degrees, tuning) {
        this.degrees = degrees;
        this.tuning = tuning || new EqualTemperamentTuning(12);
    },

    getFrequency: function(degree, rootFrequency, octave) {
        var frequency = rootFrequency;
        frequency *= Math.pow(this.tuning.octaveRatio, octave);
        frequency *= this.tuning.ratios[this.degrees[degree]];
        return frequency;
    }
});
<commit_msg>Make scale automatically wrap high degrees to higher octaves.<commit_after>var Scale = new Class({
    initialize: function(degrees, tuning) {
        this.degrees = degrees;
        this.tuning = tuning || new EqualTemperamentTuning(12);
    },

    getFrequency: function(degree, rootFrequency, octave) {
        var frequency = rootFrequency;
        octave += Math.floor(degree / this.degrees.length);
        degree %= this.degrees.length;
        frequency *= Math.pow(this.tuning.octaveRatio, octave);
        frequency *= this.tuning.ratios[this.degrees[degree]];
        return frequency;
    }
});
<|endoftext|>


<commit_before>var ini =
{
  // all files in http-clients must be updated to the cvs version of this file //
  protocol_version: '5',
  max_frames: 100,
  debug: false,
  dragonfly_version: '$dfversion$',
  revision_number: '$revdate$',
  mercurial_revision: "",
  browser: window.opera ? 'opera' : window.chrome ? 'chrome' : 'firefox',
  default_shortcuts_os:
  {
    generic:
    {
      "global":
      {
        "default":
        {
          "ctrl a": "select-all",
          "ctrl f": "focus-container-search-field",
          "ctrl i": "invert-spotlight-colors",
          "f3": "focus-container-search-field",
          "f8": "continue-run",
          "f10": "continue-step-next-line",
          "f11": "continue-step-into-call",
          "shift f11": "continue-step-out-of-call",
          "escape": "toggle-console",
          "ctrl tab": "navigate-next-top-tab",
          "ctrl shift tab": "navigate-previous-top-tab",
          "ctrl f": "show-search"
        },
        "edit":
        {
          "f8": "continue-run",
          "f10": "continue-step-next-line",
          "f11": "continue-step-into-call",
          "shift f11": "continue-step-out-of-call",
          "enter": "highlight-next-match",
          "f3": "highlight-next-match",
          "shift enter": "highlight-previous-match",
          "shift f3": "highlight-previous-match",
          "ctrl enter": "show-script",
          "escape": "hide-search",
          "escape": "toggle-console",
          "ctrl tab": "navigate-next-top-tab",
          "ctrl shift tab": "navigate-previous-top-tab",
          "ctrl f": "show-search"
        }
      },
      "dom":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-left",
          "right": "nav-right",
          "enter": "dispatch-click",
          "shift enter": "dispatch-click",
          "ctrl enter": "dispatch-dbl-click",
          "delete": "remove-node"
        },
        "edit-attributes-and-text":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit",
          "escape": "exit-edit",
        },
        "edit-markup":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "ctrl enter": "submit-edit",
          "escape": "exit-edit",
        }
      },
      "css-inspector":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-up",
          "right": "nav-down",
          "ctrl enter": "dispatch-dbl-click",
        },
        "edit":
        {
          "up": "autocomplete-next",
          "down": "autocomplete-previous",
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit-and-new-edit",
          "escape": "exit-edit",
        }
      },
      "command_line":
      {
        "default":
        {
          "ctrl l": "clear-repl",
        },
        "single-line-edit":
        {
          "up": "backlog-prev",
          "down": "backlog-next",
          "tab": "autocomplete",
          "enter": "eval",
          "shift enter": "enter-multiline-mode",
          "ctrl l": "clear",
          "ctrl p": "backlog-prev",
          "ctrl n": "backlog-next",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl e": "move-to-end-of-line",
          "ctrl a": "move-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
        "multi-line-edit":
        {
          "shift enter": "exit-multiline-mode",
          "ctrl enter": "eval",
          "tab": "insert-tab-at-point",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
        "autocomplete":
        {
          "left": "prev-completion",
          "right": "next-completion",
          "tab": "next-completion",
          "shift tab": "prev-completion",
          "enter": "commit",
          "[": "commit-and-insert",
          "]": "commit-and-insert",
          ".": "commit-and-insert",
          "(": "commit-and-insert",
          ")": "commit-and-insert",
          "escape": "cancel-completion",
          "ctrl l": "clear",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
      },
      "js_source":
      {
        "default":
        {
          "up": "scroll-arrow-up",
          "down": "scroll-arrow-down",
          "page-up": "scroll-page-up",
          "page-down": "scroll-page-down",
          "ctrl g": "show-window-go-to-line"
        },
      },
      "go-to-line":
      {
        "default":
        {
          "enter": "submit",
        },
      },
      "watches":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
      "breakpoints":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
    },
    mac:
    {
      "global":
      {
        "default":
        {
          "cmd shift a": "select-all",
          "cmd f": "focus-container-search-field",
          "cmd i": "invert-spotlight-colors",
          "f5": "continue-run",
          "f6": "continue-step-next-line",
          "f7": "continue-step-into-call",
          "shift f7": "continue-step-out-of-call",
          "escape": "toggle-console"
        },
        "edit":
        {
          "f5": "continue-run",
          "f6": "continue-step-next-line",
          "f7": "continue-step-into-call",
          "shift f7": "continue-step-out-of-call",
          "enter": "highlight-next-match",
          "cmd g": "highlight-next-match",
          "shift enter": "highlight-previous-match",
          "cmd shift g": "highlight-previous-match",
          "escape": "toggle-console"
        }
      },
      "dom":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-left",
          "right": "nav-right",
          "enter": "dispatch-click",
          "shift enter": "dispatch-click",
          "cmd enter": "dispatch-dbl-click",
          "delete": "remove-node"
        },
        "edit-attributes-and-text":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit",
          "escape": "exit-edit",
        },
        "edit-markup":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "cmd enter": "submit-edit",
          "escape": "exit-edit",
        }
      },
      "css-inspector":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-up",
          "right": "nav-down",
          "cmd enter": "dispatch-dbl-click",
        },
        "edit":
        {
          "up": "autocomplete-previous",
          "down": "autocomplete-next",
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit-and-new-edit",
          "escape": "exit-edit",
        }
      },
      "command_line":
      {
        "default":
        {
          // "ctrl l": "clear-repl",
        },
        "single-line-edit":
        {
          "up": "backlog-prev",
          "down": "backlog-next",
          "tab": "autocomplete",
          "enter": "eval",
          "shift enter": "enter-multiline-mode",
          // "ctrl l": "clear",
          //"ctrl p": "backlog-prev",
          //"ctrl n": "backlog-next",
          // "ctrl k": "kill-to-end-of-line",
          // "ctrl u": "kill-to-beginning-of-line", // non-existent on mac afaict
          // "ctrl e": "move-to-end-of-LINE",
          // "ctrl a": "move-to-beginning-of-line",
          // "ctrl w": "kill-word-backwards", // non-existent on mac afaict
          // "ctrl y": "yank" // non-existent on mac afaict
        },
        "multi-line-edit":
        {
          "shift enter": "exit-multiline-mode",
          "cmd enter": "eval",
          "tab": "insert-tab-at-point",
          // "ctrl k": "kill-to-end-of-line",
          // "ctrl u": "kill-to-beginning-of-line",
          // "ctrl w": "kill-word-backwards",
          // "ctrl y": "yank"
        },
        "autocomplete":
        {
         "left": "prev-completion",
         "right": "next-completion",
         "tab": "next-completion",
         "shift tab": "prev-completion",
         "enter": "commit",
         "[": "commit-and-insert",
         "]": "commit-and-insert",
         ".": "commit-and-insert",
         "(": "commit-and-insert",
         ")": "commit-and-insert",
         "escape": "cancel-completion",
         // "ctrl l": "cancel-input",
         // "ctrl k": "kill-to-end-of-line",
         // "ctrl u": "kill-to-beginning-of-line",
         // "ctrl w": "kill-word-backwards",
         // "ctrl y": "yank"
        },
      },
    },
  },
  hostspotlight_matrixes:
  {
    /*
      box : null | [fill-color , frame-color, grid-color]
      color: 0 | [r, g, b, alpha]
    */
    "default":
    [
      // dimension box
      [
        [51,117,215, 52],
        0,
        0
      ],
      // padding box
      [
        [51,117,215, 104],
        0,
        0
      ],
      // border box
      [
        [51,117,215, 255],
        0,
        [51,117,215, 128]
      ],
      // margin box
      [
        [51,117,215, 156],
        0,
        0
      ]
    ],
    "metrics-hover":
    [
      // inner inner * box
      [
        [51,117,215, 48],
        0,
        0
      ],
      // inner box
      [
        [51,117,215, 48],
        0,
        0
      ],
      // active box
      [
        [51,117,215, 128],
        0,
        0
      ]
    ],
    "locked":
    [
      // dimension box
      [
        [51,117,215, 24],
        0,
        0
      ],
      // padding box
      [
        [51,117,215, 52],
        0,
        0
      ],
      // border box
      [
        [51,117,215, 128],
        0,
        [51,117,215, 64]
      ],
      // margin box
      [
        [51,117,215, 76],
        0,
        0
      ]
    ]
  }
};
window.ini.default_shortcuts = navigator.platform.toLowerCase().indexOf('mac') == -1 ?
                               ini.default_shortcuts_os.generic :
                               ini.default_shortcuts_os.mac;
<commit_msg>Synched with mainline<commit_after>var ini =
{
  // all files in http-clients must be updated to the cvs version of this file //
  protocol_version: '5',
  max_frames: 100,
  debug: false,
  dragonfly_version: '$dfversion$',
  revision_number: '$revdate$',
  mercurial_revision: "",
  browser: window.opera ? 'opera' : window.chrome ? 'chrome' : 'firefox',
  default_shortcuts_os:
  {
    generic:
    {
      "global":
      {
        "default":
        {
          "ctrl a": "select-all",
          "ctrl i": "invert-spotlight-colors",
          "f3": "focus-container-search-field", //  todo: should be "show search", has to always focus field
          "f8": "continue-run",
          "f10": "continue-step-next-line",
          "f11": "continue-step-into-call",
          "shift f11": "continue-step-out-of-call",
          "escape": "toggle-console",
          "ctrl tab": "navigate-next-top-tab",
          "ctrl shift tab": "navigate-previous-top-tab",
          "ctrl f": "show-search"
        },
        "edit":
        {
          "f8": "continue-run",
          "f10": "continue-step-next-line",
          "f11": "continue-step-into-call",
          "shift f11": "continue-step-out-of-call",
          "enter": "highlight-next-match",
          "f3": "highlight-next-match",
          "shift enter": "highlight-previous-match",
          "shift f3": "highlight-previous-match",
          "ctrl enter": "show-script",
          "escape": "toggle-console",
          "ctrl tab": "navigate-next-top-tab",
          "ctrl shift tab": "navigate-previous-top-tab",
          "ctrl f": "show-search"
        }
      },
      "dom":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-left",
          "right": "nav-right",
          "enter": "dispatch-click",
          "shift enter": "dispatch-click",
          "ctrl enter": "dispatch-dbl-click",
          "delete": "remove-node"
        },
        "edit-attributes-and-text":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit",
          "escape": "exit-edit",
        },
        "edit-markup":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "ctrl enter": "submit-edit",
          "escape": "exit-edit",
        }
      },
      "css-inspector":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-up",
          "right": "nav-down",
          "ctrl enter": "dispatch-dbl-click",
        },
        "edit":
        {
          "up": "autocomplete-next",
          "down": "autocomplete-previous",
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit-and-new-edit",
          "escape": "exit-edit",
        }
      },
      "command_line":
      {
        "default":
        {
          "ctrl l": "clear",
        },
        "single-line-edit":
        {
          "up": "backlog-prev",
          "down": "backlog-next",
          "tab": "autocomplete",
          "enter": "eval",
          "shift enter": "enter-multiline-mode",
          "ctrl l": "clear",
          "ctrl p": "backlog-prev",
          "ctrl n": "backlog-next",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl e": "move-to-end-of-line",
          "ctrl a": "move-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
        "multi-line-edit":
        {
          "shift enter": "exit-multiline-mode",
          "ctrl enter": "eval",
          "tab": "insert-tab-at-point",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
        "autocomplete":
        {
          "left": "prev-completion",
          "right": "next-completion",
          "tab": "next-completion",
          "shift tab": "prev-completion",
          "enter": "commit",
          "[": "commit-and-insert",
          "]": "commit-and-insert",
          ".": "commit-and-insert",
          "(": "commit-and-insert",
          ")": "commit-and-insert",
          "escape": "cancel-completion",
          "ctrl l": "clear",
          "ctrl k": "kill-to-end-of-line",
          "ctrl u": "kill-to-beginning-of-line",
          "ctrl w": "kill-word-backwards",
          "ctrl y": "yank"
        },
      },
      "js_source":
      {
        "default":
        {
          "up": "scroll-arrow-up",
          "down": "scroll-arrow-down",
          "page-up": "scroll-page-up",
          "page-down": "scroll-page-down",
          "ctrl g": "show-window-go-to-line"
        },
      },
      "go-to-line":
      {
        "default":
        {
          "enter": "submit",
        },
      },
      "watches":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
      "breakpoints":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
    },
    mac:
    {
      "global":
      {
        "default":
        {
          "cmd shift a": "select-all",
          "cmd i": "invert-spotlight-colors",
          "f3": "focus-container-search-field", //  todo: should be "show search", has to always focus field
          "f5": "continue-run",
          "f6": "continue-step-next-line",
          "f7": "continue-step-into-call",
          "shift f7": "continue-step-out-of-call",
          "escape": "toggle-console",
          // "ctrl tab": "navigate-next-top-tab",
          // "ctrl shift tab": "navigate-previous-top-tab",
          "cmd shift f": "show-search"
        },
        "edit":
        {
          "f5": "continue-run",
          "f6": "continue-step-next-line",
          "f7": "continue-step-into-call",
          "shift f7": "continue-step-out-of-call",
          "enter": "highlight-next-match",
          // "cmd g": "highlight-next-match", // seems it can't be stolen from Opera
          "shift enter": "highlight-previous-match",
          // "cmd shift g": "highlight-previous-match",
          "cmd enter": "show-script", // todo: check why that doesn't hide the floating search window on mac
          "escape": "toggle-console",
          // "ctrl tab": "navigate-next-top-tab",
          // "ctrl shift tab": "navigate-previous-top-tab",
          "cmd shift f": "show-search"
        }
      },
      "dom":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-left",
          "right": "nav-right",
          "enter": "dispatch-click",
          "shift enter": "dispatch-click",
          "cmd enter": "dispatch-dbl-click",
          "delete": "remove-node"
        },
        "edit-attributes-and-text":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit",
          "escape": "exit-edit",
        },
        "edit-markup":
        {
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "cmd enter": "submit-edit",
          "escape": "exit-edit",
        }
      },
      "css-inspector":
      {
        "default":
        {
          "up": "nav-up",
          "down": "nav-down",
          "left": "nav-up",
          "right": "nav-down",
          "cmd enter": "dispatch-dbl-click",
        },
        "edit":
        {
          "up": "autocomplete-next",
          "down": "autocomplete-previous",
          "shift tab": "edit-previous",
          "tab": "edit-next",
          "enter": "submit-edit-and-new-edit",
          "escape": "exit-edit",
        }
      },
      "command_line":
      {
        "default":
        {
          "cmd k": "clear",
        },
        "single-line-edit":
        {
          "up": "backlog-prev",
          "down": "backlog-next",
          "tab": "autocomplete",
          "enter": "eval",
          "shift enter": "enter-multiline-mode",
          "cmd k": "clear",
          //"ctrl p": "backlog-prev",
          //"ctrl n": "backlog-next",
          // "ctrl k": "kill-to-end-of-line", // supported on mac text input anyway
          // "ctrl u": "kill-to-beginning-of-line", // non-existent on mac afaict
          // "ctrl e": "move-to-end-of-LINE",
          // "ctrl a": "move-to-beginning-of-line",
          // "ctrl w": "kill-word-backwards", // non-existent on mac afaict
          // "ctrl y": "yank" // non-existent on mac afaict
        },
        "multi-line-edit":
        {
          "shift enter": "exit-multiline-mode",
          "cmd enter": "eval",
          "tab": "insert-tab-at-point",
          // "ctrl k": "kill-to-end-of-line",
          // "ctrl u": "kill-to-beginning-of-line",
          // "ctrl w": "kill-word-backwards",
          // "ctrl y": "yank"
        },
        "autocomplete":
        {
         "left": "prev-completion",
         "right": "next-completion",
         "tab": "next-completion",
         "shift tab": "prev-completion",
         "enter": "commit",
         "[": "commit-and-insert",
         "]": "commit-and-insert",
         ".": "commit-and-insert",
         "(": "commit-and-insert",
         ")": "commit-and-insert",
         "escape": "cancel-completion",
         "cmd k": "clear",
         // "ctrl k": "kill-to-end-of-line",
         // "ctrl u": "kill-to-beginning-of-line",
         // "ctrl w": "kill-word-backwards",
         // "ctrl y": "yank"
        },
      },
      "js_source":
      {
        "default":
        {
          "up": "scroll-arrow-up",
          "down": "scroll-arrow-down",
          "page-up": "scroll-page-up",
          "page-down": "scroll-page-down",
          "cmd l": "show-window-go-to-line"
        },
      },
      "go-to-line":
      {
        "default":
        {
          "enter": "submit",
        },
      },
      "watches":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
      "breakpoints":
      {
        "default":
        {

        },
        "edit":
        {
          "enter": "submit",
          "escape": "cancel",
        }
      },
    },
  },
  hostspotlight_matrixes:
  {
    /*
      box : null | [fill-color , frame-color, grid-color]
      color: 0 | [r, g, b, alpha]
    */
    "default":
    [
      // dimension box
      [
        [51,117,215, 52],
        0,
        0
      ],
      // padding box
      [
        [51,117,215, 104],
        0,
        0
      ],
      // border box
      [
        [51,117,215, 255],
        0,
        [51,117,215, 128]
      ],
      // margin box
      [
        [51,117,215, 156],
        0,
        0
      ]
    ],
    "metrics-hover":
    [
      // inner inner * box
      [
        [51,117,215, 48],
        0,
        0
      ],
      // inner box
      [
        [51,117,215, 48],
        0,
        0
      ],
      // active box
      [
        [51,117,215, 128],
        0,
        0
      ]
    ],
    "locked":
    [
      // dimension box
      [
        [51,117,215, 24],
        0,
        0
      ],
      // padding box
      [
        [51,117,215, 52],
        0,
        0
      ],
      // border box
      [
        [51,117,215, 128],
        0,
        [51,117,215, 64]
      ],
      // margin box
      [
        [51,117,215, 76],
        0,
        0
      ]
    ]
  }
};
window.ini.default_shortcuts = navigator.platform.toLowerCase().indexOf('mac') == -1 ?
                               ini.default_shortcuts_os.generic :
                               ini.default_shortcuts_os.mac;
<|endoftext|>


<commit_before>import {
  hasPerspective,
  hasTransition,
  hasTransform,
  hasTouch,
  style,
  offset,
  addEvent,
  removeEvent,
  getRect,
  preventDefaultException
} from '../util/dom'

import { extend } from '../util/lang'

const DEFAULT_OPTIONS = {
  startX: 0,
  startY: 0,
  scrollX: false,
  scrollY: true,
  freeScroll: false,
  directionLockThreshold: 5,
  eventPassthrough: '',
  click: false,
  tap: false,
  bounce: true,
  bounceTime: 700,
  momentum: true,
  momentumLimitTime: 300,
  momentumLimitDistance: 15,
  swipeTime: 2500,
  swipeBounceTime: 500,
  deceleration: 0.001,
  flickLimitTime: 200,
  flickLimitDistance: 100,
  resizePolling: 60,
  probeType: 0,
  preventDefault: true,
  preventDefaultException: {
    tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
  },
  HWCompositing: true,
  useTransition: true,
  useTransform: true,
  bindToWrapper: false,
  disableMouse: hasTouch,
  disableTouch: !hasTouch,
  /**
   * for picker
   * wheel: {
   *   selectedIndex: 0,
   *   rotate: 25,
   *   adjustTime: 400
   *   wheelWrapperClass: 'wheel-scroll',
   *   wheelItemClass: 'wheel-item'
   * }
   */
  wheel: false,
  /**
   * for slide
   * snap: {
   *   loop: false,
   *   el: domEl,
   *   threshold: 0.1,
   *   stepX: 100,
   *   stepY: 100,
   *   listenFlick: true
   * }
   */
  snap: false,
  /**
   * for scrollbar
   * scrollbar: {
   *   fade: true
   * }
   */
  scrollbar: false,
  /**
   * for pull down and refresh
   * pullDownRefresh: {
   *   threshold: 50,
   *   stop: 20
   * }
   */
  pullDownRefresh: false,
  /**
   * for pull up and load
   * pullUpLoad: {
   *   threshold: 50
   * }
   */
  pullUpLoad: false
}

export function initMixin(BScroll) {
  BScroll.prototype._init = function (el, options) {
    this._handleOptions(options)

    // init private custom events
    this._events = {}

    this.x = 0
    this.y = 0
    this.directionX = 0
    this.directionY = 0

    this._addDOMEvents()

    this._initExtFeatures()

    this._watchTransition()

    this._initDOMObserver()

    this.refresh()

    if (!this.options.snap) {
      this.scrollTo(this.options.startX, this.options.startY)
    }

    this.enable()
  }

  BScroll.prototype._handleOptions = function (options) {
    this.options = extend({}, DEFAULT_OPTIONS, options)

    this.translateZ = this.options.HWCompositing && hasPerspective ? ' translateZ(0)' : ''

    this.options.useTransition = this.options.useTransition && hasTransition
    this.options.useTransform = this.options.useTransform && hasTransform

    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault

    // If you want eventPassthrough I have to lock one of the axes
    this.options.scrollX = this.options.eventPassthrough === 'horizontal' ? false : this.options.scrollX
    this.options.scrollY = this.options.eventPassthrough === 'vertical' ? false : this.options.scrollY

    // With eventPassthrough we also need lockDirection mechanism
    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough
    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold

    if (this.options.tap === true) {
      this.options.tap = 'tap'
    }
  }

  BScroll.prototype._addDOMEvents = function () {
    let eventOperation = addEvent
    this._handleDOMEvents(eventOperation)
  }

  BScroll.prototype._removeDOMEvents = function () {
    let eventOperation = removeEvent
    this._handleDOMEvents(eventOperation)
  }

  BScroll.prototype._handleDOMEvents = function (eventOperation) {
    let target = this.options.bindToWrapper ? this.wrapper : window
    eventOperation(window, 'orientationchange', this)
    eventOperation(window, 'resize', this)

    if (this.options.click) {
      eventOperation(this.wrapper, 'click', this, true)
    }

    if (!this.options.disableMouse) {
      eventOperation(this.wrapper, 'mousedown', this)
      eventOperation(target, 'mousemove', this)
      eventOperation(target, 'mousecancel', this)
      eventOperation(target, 'mouseup', this)
    }

    if (hasTouch && !this.options.disableTouch) {
      eventOperation(this.wrapper, 'touchstart', this)
      eventOperation(target, 'touchmove', this)
      eventOperation(target, 'touchcancel', this)
      eventOperation(target, 'touchend', this)
    }

    eventOperation(this.scroller, style.transitionEnd, this)
  }

  BScroll.prototype._initExtFeatures = function () {
    if (this.options.snap) {
      this._initSnap()
    }
    if (this.options.scrollbar) {
      this._initScrollbar()
    }
    if (this.options.pullUpLoad) {
      this._initPullUp()
    }
    if (this.options.pullDownRefresh) {
      this._initPullDown()
    }
    if (this.options.wheel) {
      this._initWheel()
    }
  }

  BScroll.prototype._watchTransition = function () {
    if (typeof Object.defineProperty !== 'function') {
      return
    }
    let isInTransition = false
    let me = this
    let prePointerEvents = this.scroller.style.pointerEvents || 'auto'
    Object.defineProperty(this, 'isInTransition', {
      get() {
        return isInTransition
      },
      set(newVal) {
        isInTransition = newVal
        if (isInTransition) {
          me.scroller.style.pointerEvents = 'none'
        } else {
          me.scroller.style.pointerEvents = prePointerEvents
        }
      }
    })
  }

  BScroll.prototype._initDOMObserver = function () {
    if (typeof MutationObserver !== 'undefined') {
      let observer = new MutationObserver((mutations) => {
        let shouldRefresh = mutations.some((mutation) => {
          return mutation.type !== 'attributes'
        })
        if (shouldRefresh) {
          this.refresh()
        }
      })
      const config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
      }
      observer.observe(this.scroller, config)

      this.on('destroy', () => {
        observer.disconnect()
      })
    } else {
      this._checkDOMUpdate()
    }
  }

  BScroll.prototype._checkDOMUpdate = function () {
    let scrollerRect = getRect(this.scroller)
    let oldWidth = scrollerRect.width
    let oldHeight = scrollerRect.height

    function check() {
      if (this.destroyed) {
        return
      }
      scrollerRect = getRect(this.scroller)
      let newWidth = scrollerRect.width
      let newHeight = scrollerRect.height

      if (oldWidth !== newWidth || oldHeight !== newHeight) {
        this.refresh()
      }
      oldWidth = newWidth
      oldHeight = newHeight

      next.call(this)
    }

    function next() {
      setTimeout(() => {
        check.call(this)
      }, 1000)
    }

    next.call(this)
  }

  BScroll.prototype.handleEvent = function (e) {
    switch (e.type) {
      case 'touchstart':
      case 'mousedown':
        this._start(e)
        break
      case 'touchmove':
      case 'mousemove':
        this._move(e)
        break
      case 'touchend':
      case 'mouseup':
      case 'touchcancel':
      case 'mousecancel':
        this._end(e)
        break
      case 'orientationchange':
      case 'resize':
        this._resize()
        break
      case 'transitionend':
      case 'webkitTransitionEnd':
      case 'oTransitionEnd':
      case 'MSTransitionEnd':
        this._transitionEnd(e)
        break
      case 'click':
        if (this.enabled && !e._constructed) {
          if (!preventDefaultException(e.target, this.options.preventDefaultException)) {
            e.preventDefault()
          }
          e.stopPropagation()
        }
        break
    }
  }

  BScroll.prototype.refresh = function () {
    let wrapperRect = getRect(this.wrapper)
    this.wrapperWidth = wrapperRect.width
    this.wrapperHeight = wrapperRect.height

    let scrollerRect = getRect(this.scroller)
    this.scrollerWidth = scrollerRect.width
    this.scrollerHeight = scrollerRect.height

    const wheel = this.options.wheel
    if (wheel) {
      this.items = this.scroller.children
      this.options.itemHeight = this.itemHeight = this.items.length ? this.scrollerHeight / this.items.length : 0
      if (this.selectedIndex === undefined) {
        this.selectedIndex = wheel.selectedIndex || 0
      }
      this.options.startY = -this.selectedIndex * this.itemHeight
      this.maxScrollX = 0
      this.maxScrollY = -this.itemHeight * (this.items.length - 1)
    } else {
      this.maxScrollX = this.wrapperWidth - this.scrollerWidth
      this.maxScrollY = this.wrapperHeight - this.scrollerHeight
    }

    this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0
    this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0

    if (!this.hasHorizontalScroll) {
      this.maxScrollX = 0
      this.scrollerWidth = this.wrapperWidth
    }

    if (!this.hasVerticalScroll) {
      this.maxScrollY = 0
      this.scrollerHeight = this.wrapperHeight
    }

    this.endTime = 0
    this.directionX = 0
    this.directionY = 0
    this.wrapperOffset = offset(this.wrapper)

    this.trigger('refresh')

    this.resetPosition()
  }

  BScroll.prototype.enable = function () {
    this.enabled = true
  }

  BScroll.prototype.disable = function () {
    this.enabled = false
  }
}<commit_msg>remove useless MutationObserver config<commit_after>import {
  hasPerspective,
  hasTransition,
  hasTransform,
  hasTouch,
  style,
  offset,
  addEvent,
  removeEvent,
  getRect,
  preventDefaultException
} from '../util/dom'

import { extend } from '../util/lang'

const DEFAULT_OPTIONS = {
  startX: 0,
  startY: 0,
  scrollX: false,
  scrollY: true,
  freeScroll: false,
  directionLockThreshold: 5,
  eventPassthrough: '',
  click: false,
  tap: false,
  bounce: true,
  bounceTime: 700,
  momentum: true,
  momentumLimitTime: 300,
  momentumLimitDistance: 15,
  swipeTime: 2500,
  swipeBounceTime: 500,
  deceleration: 0.001,
  flickLimitTime: 200,
  flickLimitDistance: 100,
  resizePolling: 60,
  probeType: 0,
  preventDefault: true,
  preventDefaultException: {
    tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
  },
  HWCompositing: true,
  useTransition: true,
  useTransform: true,
  bindToWrapper: false,
  disableMouse: hasTouch,
  disableTouch: !hasTouch,
  /**
   * for picker
   * wheel: {
   *   selectedIndex: 0,
   *   rotate: 25,
   *   adjustTime: 400
   *   wheelWrapperClass: 'wheel-scroll',
   *   wheelItemClass: 'wheel-item'
   * }
   */
  wheel: false,
  /**
   * for slide
   * snap: {
   *   loop: false,
   *   el: domEl,
   *   threshold: 0.1,
   *   stepX: 100,
   *   stepY: 100,
   *   listenFlick: true
   * }
   */
  snap: false,
  /**
   * for scrollbar
   * scrollbar: {
   *   fade: true
   * }
   */
  scrollbar: false,
  /**
   * for pull down and refresh
   * pullDownRefresh: {
   *   threshold: 50,
   *   stop: 20
   * }
   */
  pullDownRefresh: false,
  /**
   * for pull up and load
   * pullUpLoad: {
   *   threshold: 50
   * }
   */
  pullUpLoad: false
}

export function initMixin(BScroll) {
  BScroll.prototype._init = function (el, options) {
    this._handleOptions(options)

    // init private custom events
    this._events = {}

    this.x = 0
    this.y = 0
    this.directionX = 0
    this.directionY = 0

    this._addDOMEvents()

    this._initExtFeatures()

    this._watchTransition()

    this._initDOMObserver()

    this.refresh()

    if (!this.options.snap) {
      this.scrollTo(this.options.startX, this.options.startY)
    }

    this.enable()
  }

  BScroll.prototype._handleOptions = function (options) {
    this.options = extend({}, DEFAULT_OPTIONS, options)

    this.translateZ = this.options.HWCompositing && hasPerspective ? ' translateZ(0)' : ''

    this.options.useTransition = this.options.useTransition && hasTransition
    this.options.useTransform = this.options.useTransform && hasTransform

    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault

    // If you want eventPassthrough I have to lock one of the axes
    this.options.scrollX = this.options.eventPassthrough === 'horizontal' ? false : this.options.scrollX
    this.options.scrollY = this.options.eventPassthrough === 'vertical' ? false : this.options.scrollY

    // With eventPassthrough we also need lockDirection mechanism
    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough
    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold

    if (this.options.tap === true) {
      this.options.tap = 'tap'
    }
  }

  BScroll.prototype._addDOMEvents = function () {
    let eventOperation = addEvent
    this._handleDOMEvents(eventOperation)
  }

  BScroll.prototype._removeDOMEvents = function () {
    let eventOperation = removeEvent
    this._handleDOMEvents(eventOperation)
  }

  BScroll.prototype._handleDOMEvents = function (eventOperation) {
    let target = this.options.bindToWrapper ? this.wrapper : window
    eventOperation(window, 'orientationchange', this)
    eventOperation(window, 'resize', this)

    if (this.options.click) {
      eventOperation(this.wrapper, 'click', this, true)
    }

    if (!this.options.disableMouse) {
      eventOperation(this.wrapper, 'mousedown', this)
      eventOperation(target, 'mousemove', this)
      eventOperation(target, 'mousecancel', this)
      eventOperation(target, 'mouseup', this)
    }

    if (hasTouch && !this.options.disableTouch) {
      eventOperation(this.wrapper, 'touchstart', this)
      eventOperation(target, 'touchmove', this)
      eventOperation(target, 'touchcancel', this)
      eventOperation(target, 'touchend', this)
    }

    eventOperation(this.scroller, style.transitionEnd, this)
  }

  BScroll.prototype._initExtFeatures = function () {
    if (this.options.snap) {
      this._initSnap()
    }
    if (this.options.scrollbar) {
      this._initScrollbar()
    }
    if (this.options.pullUpLoad) {
      this._initPullUp()
    }
    if (this.options.pullDownRefresh) {
      this._initPullDown()
    }
    if (this.options.wheel) {
      this._initWheel()
    }
  }

  BScroll.prototype._watchTransition = function () {
    if (typeof Object.defineProperty !== 'function') {
      return
    }
    let isInTransition = false
    let me = this
    let prePointerEvents = this.scroller.style.pointerEvents || 'auto'
    Object.defineProperty(this, 'isInTransition', {
      get() {
        return isInTransition
      },
      set(newVal) {
        isInTransition = newVal
        if (isInTransition) {
          me.scroller.style.pointerEvents = 'none'
        } else {
          me.scroller.style.pointerEvents = prePointerEvents
        }
      }
    })
  }

  BScroll.prototype._initDOMObserver = function () {
    if (typeof MutationObserver !== 'undefined') {
      let observer = new MutationObserver((mutations) => {
        this.refresh()
      })
      const config = {
        childList: true,
        subtree: true
      }
      observer.observe(this.scroller, config)

      this.on('destroy', () => {
        observer.disconnect()
      })
    } else {
      this._checkDOMUpdate()
    }
  }

  BScroll.prototype._checkDOMUpdate = function () {
    let scrollerRect = getRect(this.scroller)
    let oldWidth = scrollerRect.width
    let oldHeight = scrollerRect.height

    function check() {
      if (this.destroyed) {
        return
      }
      scrollerRect = getRect(this.scroller)
      let newWidth = scrollerRect.width
      let newHeight = scrollerRect.height

      if (oldWidth !== newWidth || oldHeight !== newHeight) {
        this.refresh()
      }
      oldWidth = newWidth
      oldHeight = newHeight

      next.call(this)
    }

    function next() {
      setTimeout(() => {
        check.call(this)
      }, 1000)
    }

    next.call(this)
  }

  BScroll.prototype.handleEvent = function (e) {
    switch (e.type) {
      case 'touchstart':
      case 'mousedown':
        this._start(e)
        break
      case 'touchmove':
      case 'mousemove':
        this._move(e)
        break
      case 'touchend':
      case 'mouseup':
      case 'touchcancel':
      case 'mousecancel':
        this._end(e)
        break
      case 'orientationchange':
      case 'resize':
        this._resize()
        break
      case 'transitionend':
      case 'webkitTransitionEnd':
      case 'oTransitionEnd':
      case 'MSTransitionEnd':
        this._transitionEnd(e)
        break
      case 'click':
        if (this.enabled && !e._constructed) {
          if (!preventDefaultException(e.target, this.options.preventDefaultException)) {
            e.preventDefault()
          }
          e.stopPropagation()
        }
        break
    }
  }

  BScroll.prototype.refresh = function () {
    let wrapperRect = getRect(this.wrapper)
    this.wrapperWidth = wrapperRect.width
    this.wrapperHeight = wrapperRect.height

    let scrollerRect = getRect(this.scroller)
    this.scrollerWidth = scrollerRect.width
    this.scrollerHeight = scrollerRect.height

    const wheel = this.options.wheel
    if (wheel) {
      this.items = this.scroller.children
      this.options.itemHeight = this.itemHeight = this.items.length ? this.scrollerHeight / this.items.length : 0
      if (this.selectedIndex === undefined) {
        this.selectedIndex = wheel.selectedIndex || 0
      }
      this.options.startY = -this.selectedIndex * this.itemHeight
      this.maxScrollX = 0
      this.maxScrollY = -this.itemHeight * (this.items.length - 1)
    } else {
      this.maxScrollX = this.wrapperWidth - this.scrollerWidth
      this.maxScrollY = this.wrapperHeight - this.scrollerHeight
    }

    this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0
    this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0

    if (!this.hasHorizontalScroll) {
      this.maxScrollX = 0
      this.scrollerWidth = this.wrapperWidth
    }

    if (!this.hasVerticalScroll) {
      this.maxScrollY = 0
      this.scrollerHeight = this.wrapperHeight
    }

    this.endTime = 0
    this.directionX = 0
    this.directionY = 0
    this.wrapperOffset = offset(this.wrapper)

    this.trigger('refresh')

    this.resetPosition()
  }

  BScroll.prototype.enable = function () {
    this.enabled = true
  }

  BScroll.prototype.disable = function () {
    this.enabled = false
  }
}<|endoftext|>


<commit_before>"use strict";

import { AudioContextBuilder } from "./audio_context_builder";
import { AudioSource } from "./audio_source";
import { NotePlayer } from "./note_player";
import { WaveWriter } from "./wave_writer";

export function OfflineTransport(tracks, songPlayer, notePlayer, tempo, masterAmplitude, completeCallback) {
  var NUM_CHANNELS = 1;
  var SAMPLE_RATE = 44100;
  var SIXTEENTHS_PER_MINUTE = tempo * 4;
  var STEP_INTERVAL_IN_SECONDS = 60.0 / SIXTEENTHS_PER_MINUTE;
  var FADE_OUT_TIME_IN_SECONDS = 1.5;

  var calculatePlaybackTimeInSeconds = function() {
    var minimumPlaybackTime = songPlayer.stepCount() * STEP_INTERVAL_IN_SECONDS;
    var actualPlaybackTime = songPlayer.playbackTime(notePlayer, STEP_INTERVAL_IN_SECONDS);

    return Math.max(minimumPlaybackTime, actualPlaybackTime) + FADE_OUT_TIME_IN_SECONDS;
  };

  var buildOfflineAudioContext = function(playbackTimeInSeconds) {
    var sampleCount = SAMPLE_RATE * playbackTimeInSeconds;
    var offlineAudioContext = AudioContextBuilder.buildOfflineAudioContext(NUM_CHANNELS, sampleCount, SAMPLE_RATE);

    offlineAudioContext.oncomplete = function(e) {
      var waveWriter = WaveWriter();

      var sampleData = e.renderedBuffer.getChannelData(0);
      var outputView = waveWriter.write(sampleData);
      var blob = new Blob([outputView], { type: "audio/wav" });

      completeCallback(blob);
    };

    return offlineAudioContext;
  };

  var tick = function() {
    var scheduleAheadTimeInSeconds = songPlayer.stepCount() * STEP_INTERVAL_IN_SECONDS;
    var startTimeInSeconds = offlineAudioContext.currentTime;
    var finalTimeInSeconds = startTimeInSeconds + scheduleAheadTimeInSeconds;

    songPlayer.reset(startTimeInSeconds);
    songPlayer.tick(offlineAudioSource, notePlayer, finalTimeInSeconds, STEP_INTERVAL_IN_SECONDS, false);

    offlineAudioContext.startRendering();
  };

  var i;
  var playbackTimeInSeconds = calculatePlaybackTimeInSeconds();
  var offlineAudioContext = buildOfflineAudioContext(playbackTimeInSeconds);
  var offlineAudioSource = AudioSource(offlineAudioContext);
  var track;
  offlineAudioSource.setMasterAmplitude(masterAmplitude);

  for (i = 0; i < tracks.length; i++) {
    track = tracks[i];
    offlineAudioSource.addChannel(track.id, track.volume, track.isMuted, track.reverbBuffer, track.reverbWetPercentage, track.delayTime, track.delayFeedback);
  }

  offlineAudioSource.masterGainNode().gain.setValueAtTime(masterAmplitude, playbackTimeInSeconds - FADE_OUT_TIME_IN_SECONDS);
  offlineAudioSource.masterGainNode().gain.linearRampToValueAtTime(0.0, playbackTimeInSeconds);

  return {
    tick: tick,
  };
};
<commit_msg>Extracting function<commit_after>"use strict";

import { AudioContextBuilder } from "./audio_context_builder";
import { AudioSource } from "./audio_source";
import { NotePlayer } from "./note_player";
import { WaveWriter } from "./wave_writer";

export function OfflineTransport(tracks, songPlayer, notePlayer, tempo, masterAmplitude, completeCallback) {
  var NUM_CHANNELS = 1;
  var SAMPLE_RATE = 44100;
  var SIXTEENTHS_PER_MINUTE = tempo * 4;
  var STEP_INTERVAL_IN_SECONDS = 60.0 / SIXTEENTHS_PER_MINUTE;
  var FADE_OUT_TIME_IN_SECONDS = 1.5;

  var calculatePlaybackTimeInSeconds = function() {
    var minimumPlaybackTime = songPlayer.stepCount() * STEP_INTERVAL_IN_SECONDS;
    var actualPlaybackTime = songPlayer.playbackTime(notePlayer, STEP_INTERVAL_IN_SECONDS);

    return Math.max(minimumPlaybackTime, actualPlaybackTime) + FADE_OUT_TIME_IN_SECONDS;
  };

  var buildOfflineAudioContext = function(playbackTimeInSeconds) {
    var sampleCount = SAMPLE_RATE * playbackTimeInSeconds;
    var offlineAudioContext = AudioContextBuilder.buildOfflineAudioContext(NUM_CHANNELS, sampleCount, SAMPLE_RATE);

    offlineAudioContext.oncomplete = function(e) {
      var waveWriter = WaveWriter();

      var sampleData = e.renderedBuffer.getChannelData(0);
      var outputView = waveWriter.write(sampleData);
      var blob = new Blob([outputView], { type: "audio/wav" });

      completeCallback(blob);
    };

    return offlineAudioContext;
  };

  var buildOfflineAudioSource = function(offlineAudioContext) {
    var i;
    var track;
    var offlineAudioSource = AudioSource(offlineAudioContext);

    offlineAudioSource.setMasterAmplitude(masterAmplitude);

    for (i = 0; i < tracks.length; i++) {
      track = tracks[i];
      offlineAudioSource.addChannel(track.id, track.volume, track.isMuted, track.reverbBuffer, track.reverbWetPercentage, track.delayTime, track.delayFeedback);
    }

    offlineAudioSource.masterGainNode().gain.setValueAtTime(masterAmplitude, playbackTimeInSeconds - FADE_OUT_TIME_IN_SECONDS);
    offlineAudioSource.masterGainNode().gain.linearRampToValueAtTime(0.0, playbackTimeInSeconds);

    return offlineAudioSource;
  };

  var tick = function() {
    var scheduleAheadTimeInSeconds = songPlayer.stepCount() * STEP_INTERVAL_IN_SECONDS;
    var startTimeInSeconds = offlineAudioContext.currentTime;
    var finalTimeInSeconds = startTimeInSeconds + scheduleAheadTimeInSeconds;

    songPlayer.reset(startTimeInSeconds);
    songPlayer.tick(offlineAudioSource, notePlayer, finalTimeInSeconds, STEP_INTERVAL_IN_SECONDS, false);

    offlineAudioContext.startRendering();
  };

  var playbackTimeInSeconds = calculatePlaybackTimeInSeconds();
  var offlineAudioContext = buildOfflineAudioContext(playbackTimeInSeconds);
  var offlineAudioSource = buildOfflineAudioSource(offlineAudioContext);

  return {
    tick: tick,
  };
};
<|endoftext|>


<commit_before>import fs from 'fs';

let weatherKey;
fs.readFile(__dirname + '/weather-key', (err, data) => {
  if (err){
    const error = "No weather-key provided. Please have weather-key in the keys folder";
    throw error;
  }
  weatherKey = data.toString().trim();
});

export function getWeatherUrl(lat, lng){
  return `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${weatherKey}`;
}

export function getStockUrl(nse) {
  return `http://www.google.com/finance/info?q=${nse}`;
}
<commit_msg>Update api endpoint<commit_after>import fs from 'fs';

let weatherKey;
fs.readFile(__dirname + '/weather-key', (err, data) => {
  if (err){
    const error = "No weather-key provided. Please have weather-key in the keys folder";
    throw error;
  }
  weatherKey = data.toString().trim();
});

export function getWeatherUrl(lat, lng){
  return `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${weatherKey}`;
}

export function getStockUrl(nse) {
  return `http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp?symbol=${nse}`;
}
<|endoftext|>


<commit_before>/* eslint-disable no-console */

import express from 'express';
import compression from 'compression';

import AccessTokenRetriever from './access-token-retriever';
import ConfigurationProvider from './configuration-provider';
import WindowsGraphUsersRetriever from './windows-graph-users-retriever';

export default class Main {
  constructor() {
    this.configuration = new ConfigurationProvider().getConfiguration();

    const defaultPort = 8081;

    this.app = express();
    this.port = process.env.port || defaultPort;

    this.directoryItems = [];

    this.isRefreshing = false;
    this.newDirectoryItems = [];
  }

  start() {
    return this.refreshData()
      .then(() => this.startExpress())
      .catch(err => {
        console.error(err);
        process.exit(-1); // eslint-disable-line no-process-exit, no-magic-numbers
      });
  }

  refreshData() {
    if (this.isRefreshing) {
      return Promise.resolve(true);
    }

    this.isRefreshing = true;

    return new AccessTokenRetriever()
      .getAccessToken(
        this.configuration.endpointId,
        this.configuration.clientId,
        this.configuration.clientSecret)
      .then(accessToken => new WindowsGraphUsersRetriever()
        .getUsers(this.configuration.endpointId, accessToken))
      .then(users => {
        this.directoryItems = users;
        this.isRefreshing = false;
      })
      .catch(x => {
        this.isRefreshing = false;
        return x;
      });
  }

  startExpress() {
    this.app.use(compression());

    this.app.get('/directory', (req, res) => {
      res.json(this.directoryItems);
    });

    this.app.get('/refresh', (req, res) => {
      this.refreshData()
        .catch(err => {
          console.error(err);
        });

      res.send('Refresh request received. Return to organizational chart');
    });

    this.app.use(express.static('public'));

    this.app.listen(this.port, () => {
      console.log(`Server listening on port: ${this.port}`);
    });
  }
}
<commit_msg>Remove unused newDirectoryItems<commit_after>/* eslint-disable no-console */

import express from 'express';
import compression from 'compression';

import AccessTokenRetriever from './access-token-retriever';
import ConfigurationProvider from './configuration-provider';
import WindowsGraphUsersRetriever from './windows-graph-users-retriever';

export default class Main {
  constructor() {
    this.configuration = new ConfigurationProvider().getConfiguration();

    const defaultPort = 8081;

    this.app = express();
    this.port = process.env.port || defaultPort;

    this.directoryItems = [];
    this.isRefreshing = false;
  }

  start() {
    return this.refreshData()
      .then(() => this.startExpress())
      .catch(err => {
        console.error(err);
        process.exit(-1); // eslint-disable-line no-process-exit, no-magic-numbers
      });
  }

  refreshData() {
    if (this.isRefreshing) {
      return Promise.resolve(true);
    }

    this.isRefreshing = true;

    return new AccessTokenRetriever()
      .getAccessToken(
        this.configuration.endpointId,
        this.configuration.clientId,
        this.configuration.clientSecret)
      .then(accessToken => new WindowsGraphUsersRetriever()
        .getUsers(this.configuration.endpointId, accessToken))
      .then(users => {
        this.directoryItems = users;
        this.isRefreshing = false;
      })
      .catch(x => {
        this.isRefreshing = false;
        return x;
      });
  }

  startExpress() {
    this.app.use(compression());

    this.app.get('/directory', (req, res) => {
      res.json(this.directoryItems);
    });

    this.app.get('/refresh', (req, res) => {
      this.refreshData()
        .catch(err => {
          console.error(err);
        });

      res.send('Refresh request received. Return to organizational chart');
    });

    this.app.use(express.static('public'));

    this.app.listen(this.port, () => {
      console.log(`Server listening on port: ${this.port}`);
    });
  }
}
<|endoftext|>