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

/*global FocusEvent, DragEvent, FileList, DataTransfer, DataTransferItemList, MouseEvent, document */
sap.ui.define([
	'sap/ui/base/ManagedObject',
	'sap/ui/qunit/QUnitUtils',
	'sap/ui/test/Opa5',
	'sap/ui/Device',
	"sap/ui/thirdparty/jquery",
	"sap/ui/test/_OpaLogger"
],
function (ManagedObject, QUnitUtils, Opa5, Device, jQueryDOM, _OpaLogger) {
	"use strict";

	/**
	 * @class Actions for Opa5 - needs to implement an executeOn function that should simulate a user interaction on a control
	 * @abstract
	 * @extends sap.ui.base.ManagedObject
	 * @public
	 * @name sap.ui.test.actions.Action
	 * @author SAP SE
	 * @since 1.34
	 */
	return ManagedObject.extend("sap.ui.test.actions.Action", {

		metadata : {
			properties: {
				/**
				 * Use this only if the target property or the default of the action does not work for your control.
				 * The id suffix of the DOM Element the press action will be executed on.
				 * For most of the controls you do not have to specify this, since the Control Adapters will find the correct DOM Element.
				 * But some controls have multiple DOM elements that could be target of your Action.
				 * Then you should set this property.
				 * For a detailed documentation of the suffix see {@link sap.ui.core.Element#$}
				 *
				 * @since 1.38
				 */
				idSuffix: {
					type: "string"
				}
			},
			publicMethods : [ "executeOn" ]
		},

		/**
		 * Checks if the matcher is matching - will get an instance of sap.ui.core.Control as parameter
		 * Should be overwritten by subclasses
		 *
		 * @param {sap.ui.core.Control} element the {@link sap.ui.core.Element} or a control (extends element) the action will be executed on
		 * @protected
		 * @name sap.ui.test.actions.Action#executeOn
		 * @function
		 */
		executeOn : function () {
			return true;
		},

		/**
		 * Finds the most suitable jQuery element to execute an action on.
		 * A control may have many elements in its DOM representation. The most suitable one is chosen by priority:
		 *

		 *
If the user provided an idSuffix, return the element that matches it, or null

		 *
If there is a control adapter for the action - return the element that matches it. See {@link sap.ui.test.Press.controlAdapters} for an example

		 *
If there is no control adapter, or it matches no elements, return the focusDomRef of the control. Note that some controls may not have a focusDomRef.

		 *

		 * @param {object} oControl the control to execute an action on
		 * @returns {jQuery} the jQuery element which is most suitable for the action
		 * @protected
		 */
		$: function (oControl) {
			var $ActionDomRef;
			var sErrorMessage = "";

			if (this.getIdSuffix()) {
				// if user requested an ID suffix, it should be used -- no fallback
				$ActionDomRef = oControl.$(this.getIdSuffix());
				sErrorMessage = $ActionDomRef.length ? "" : "DOM representation of control '" + oControl +
					"' has no element with user-provided ID suffix '" + this.getIdSuffix() + "'";
			} else {
				var sAdapter = this._getAdapter(oControl);
				if (sAdapter) {
					$ActionDomRef = oControl.$(sAdapter);
					sErrorMessage = $ActionDomRef.length ? "" : "DOM representation of control '" + oControl +
						"' has no element with ID suffix '" + sAdapter + "' which is the default adapter for '" + this.getMetadata().getName() + "'";
				}

				if (!$ActionDomRef || !$ActionDomRef.length) {
					// if no adapter is set or no element is found for it -- fallback to control focus dom ref
					$ActionDomRef = jQueryDOM(oControl.getFocusDomRef());
					if (!$ActionDomRef.length) {
						$ActionDomRef = oControl.$();
						if (!$ActionDomRef.length) {
							sErrorMessage += "DOM representation of control '" + oControl + "' has no focus DOM reference";
						}
					}
				}
			}

			if ($ActionDomRef.length) {
				this.oLogger.info("Found a DOM reference for the control '" + oControl + "'. Executing '" + this.getMetadata().getName() +
				"' on the DOM element with ID '" + $ActionDomRef[0].id + "'");
				return $ActionDomRef;
			} else {
				// the control has no dom ref of any kind - action has no target
				this.oLogger.error(sErrorMessage);
				throw new Error(sErrorMessage);
			}
		},

		/**
		 * Returns the QUnitUtils
		 * @returns {sap.ui.test.qunit.QUnitUtils} QUnit utils of the current window or the OPA frame
		 * @protected
		 */
		getUtils : function () {
			return Opa5.getUtils() || QUnitUtils;
		},

		init: function () {
			this.controlAdapters = {};
			this.oLogger = _OpaLogger.getLogger(this.getMetadata().getName());
		},

		dropPosition: {
			BEFORE: "BEFORE",
			AFTER: "AFTER",
			CENTER: "CENTER"
		},

		/**
		 * Traverses the metadata chain of a control and looks for action adapters.
		 * An action adapter is a suffix part of the ID of a DOM element, where
		 * the DOM element is part of a control DOM representation and should be used as a target for events
		 * @param {object} oControl the control for which to find an action adapter
		 * @returns {string|null} the ID suffix of the DOM element to use as event target
		 * @private
		 */
		_getAdapter : function (oControl) {
			var fnGetAdapterByMeta = function (oMetadata) {
				var vAdapter = this.controlAdapters[oMetadata.getName()];

				if (vAdapter) {
					if (jQueryDOM.isFunction(vAdapter)) {
						return vAdapter(oControl);
					}
					if (typeof vAdapter === "string") {
						return vAdapter;
					}
				}

				var oParentMetadata = oMetadata.getParent();
				if (oParentMetadata) {
					return fnGetAdapterByMeta(oParentMetadata);
				}

				return null;
			}.bind(this);

			return fnGetAdapterByMeta(oControl.getMetadata());
		},

		_tryOrSimulateFocusin: function ($DomRef, oControl) {
			var oDomRef = $DomRef[0];
			var bFireArtificialEvents = false;
			var isAlreadyFocused = this._isFocused(oDomRef);
			var bIsIE11 = Device.browser.msie && Device.browser.version < 12;
			var bIsNewFF = Device.browser.firefox && Device.browser.version >= 60;

			if (isAlreadyFocused || bIsIE11 || bIsNewFF) {
				// 1. If the event is already focused, make sure onfocusin event of the control will be properly fired when executing this action,
				// otherwise the next blur will not be able to safely remove the focus.
				// 2. In IE11 (and often in Firefox v61.0/v60.0 ESR), if the focus action fails and focusin is dispatched, onfocusin will be called twice.
				// To avoid this, directly dispatch the artificial events
				bFireArtificialEvents = true;
			} else {
				$DomRef.trigger("focus");
				var bWasFocused = this._isFocused(oDomRef);
				// if focus was successful, skip the artificial events and thus avoid recieving onfocusin twice.
				// else, fire the artificial events because we still want onfocusin to work.
				bFireArtificialEvents = !bWasFocused;
			}

			if (bFireArtificialEvents) {
				this.oLogger.debug("Control " + oControl + " could not be focused - maybe you are debugging?");

				this._createAndDispatchFocusEvent("focusin", oDomRef);
				this._createAndDispatchFocusEvent("focus", oDomRef);
				this._createAndDispatchFocusEvent("activate", oDomRef);
			}

			if (!this._isFocused(oDomRef)) {
				this.oLogger.trace("Control " + oControl + " could not be focused-in correctly. This may lead to lost interactions with the control");
			}
		},

		_simulateFocusout: function (oDomRef) {
			this._createAndDispatchFocusEvent("focusout", oDomRef);
			this._createAndDispatchFocusEvent("blur", oDomRef);
			this._createAndDispatchFocusEvent("deactivate", oDomRef);
		},

		/**
		 * Create the correct event object for a mouse event.
		 *
		 * @param {string} sName Name of the mouse event
		 * @param {Element} oDomRef DOM element on which the event is going to be triggered
		 * @private
		 */
		_createAndDispatchMouseEvent: function (sName, oDomRef) {
			// ignore scrolled down stuff (client X, Y not set)
			// and assume stuff is over the whole screen (screen X, Y not set)
			// See file jquery.sap.events.js for some insights to the magic
			var iLeftMouseButtonIndex = 0;
			var oMouseEvent;
			if (Device.browser.msie && Device.browser.version < 12) {
				oMouseEvent = document.createEvent("MouseEvent");
				oMouseEvent.initMouseEvent(sName, true, true, window, 0, 0, 0, 0, 0,
					false, false, false, false, iLeftMouseButtonIndex, oDomRef);
			} else {
				oMouseEvent = new MouseEvent(sName, {
					bubbles: true,
					cancelable: true,
					identifier: 1,
					target: oDomRef,
					radiusX: 1,
					radiusY: 1,
					rotationAngle: 0,
					button: iLeftMouseButtonIndex,
					type: sName // include the type so jQuery.event.fixHooks can copy properties properly
				});
			}
			oDomRef.dispatchEvent(oMouseEvent);
		},

		_createAndDispatchFocusEvent: function (sName, oDomRef) {
			var oFocusEvent;

			if (Device.browser.msie && (Device.browser.version < 12)) {
				oFocusEvent = document.createEvent("FocusEvent");
				oFocusEvent.initFocusEvent(sName, true, false, window, 0, oDomRef);
			} else {
				oFocusEvent = new FocusEvent(sName, {
					type: sName,
					target: oDomRef,
					curentTarget: oDomRef
				});
			}

			oDomRef.dispatchEvent(oFocusEvent);
			this.oLogger.info("Dispatched focus event: '" + sName + "'");
		},

		_createAndDispatchDragEvent: function (sName, oDomRef, oOptions) {
			// calculate drop position based on user input
			// determines where the source will be dropped: before, after or in place of the target
			if (Device.browser.msie && Device.browser.version < 12) {
				// drag and drop is not supported in IE11.
				// IE11's support for HTML5 drag and drop is questionable..
				// when an event is initialized, dataTransfer is nullified. later this causes a null reference error in sap/ui/core/dnd/DragDropInfo
				// (Unable to set property 'effectAllowed' of undefined or null reference).
				// Another difference is that DataTransfer is an object in IE11, and would be instantiate like: oDataTransfer = new DataTransfer.constructor()
				return;
			}
			var mCoordinates = this._getEventCoordinates(oDomRef, oOptions);
			var oDataTransfer = new DataTransfer();
			var oDragEvent;

			if (Device.browser.edge) {
				oDragEvent = document.createEvent("DragEvent");
				oDragEvent.initDragEvent(sName, true, true, window, 0, mCoordinates.x, mCoordinates.y, mCoordinates.x, mCoordinates.y,
					false, false, false, false, 1, oDomRef, oDataTransfer);
			} else {
				oDragEvent = new DragEvent(sName, {
					type: sName, // include the type so jQuery.event.fixHooks can copy properties properly
					eventPhase: 3,
					bubbles: true,
					cancelable: true,
					defaultPrevented: false,
					composed: true,
					returnValue: true,
					cancelBubble: false,
					target: oDomRef,
					toElement: oDomRef,
					srcElement: oDomRef,
					radiusX: 1,
					radiusY: 1,
					rotationAngle: 0,
					// coordinates are needed to infer drop elem. e.g. in the control handlers, the drop target can be recalculated using document.elementfromPoint.
					// even if set, pageXY and screenXY are zeroed. if clientXY is set, then xy and pageXY will be = clientXY, and offsetXY will be calculated correctly.
					// this may cause problems for controls outside the client area
					// in this case, users should scroll before the drag event
					clientX: mCoordinates.x,
					clientY: mCoordinates.y,
					// dataTransfer should be at least an empty object, to avoid undefined error
					dataTransfer: oDataTransfer
				});
			}

			oDomRef.dispatchEvent(oDragEvent);
		},

		_getEventCoordinates: function (oDomRef, oOptions) {
			var $domRef = jQueryDOM(oDomRef);
			var offset = $domRef.offset();
			var mCenterCoordinates = {
				x: offset.left + $domRef.outerWidth() / 2,
				y: offset.top + $domRef.outerHeight() / 2
			};
			if (!oOptions) {
				return mCenterCoordinates;
			}

			switch (oOptions.position) {
				case this.dropPosition.BEFORE:
					// coords of upper left corner
					return {
						x: offset.left,
						y: offset.top
					};
				case this.dropPosition.AFTER:
					// coords of bottom right corner
					return {
						x: offset.left + $domRef.outerWidth(),
						y: offset.top + $domRef.outerHeight()
					};
				case this.dropPosition.CENTER:
				default:
					return mCenterCoordinates;
			}
		},

		_isFocused: function (oDomRef) {
			// This check returns false if:
			// 1. you have the focus in the dev tools console, or a background tab, or the browser is not focused at all. (bDocumentHasFocus will be false)
			// 2. in IE11 and Firefox, because the document.activeElement wasn't updated. (bIsActiveElement will be false)
			var bIsActiveElement = oDomRef === document.activeElement;
			var bDocumentHasFocus = !document.hasFocus || document.hasFocus();
			var bIsElemInBody = !!(oDomRef.type || oDomRef.href || ~oDomRef.tabIndex);
			return bIsActiveElement && bDocumentHasFocus && bIsElemInBody;
		}
	});

});<commit_msg>[INTERNAL] test.actions.Action: set the 'bubbles' flag to focus event<commit_after>/*!
 * ${copyright}
 */

/*global FocusEvent, DragEvent, FileList, DataTransfer, DataTransferItemList, MouseEvent, document */
sap.ui.define([
	'sap/ui/base/ManagedObject',
	'sap/ui/qunit/QUnitUtils',
	'sap/ui/test/Opa5',
	'sap/ui/Device',
	"sap/ui/thirdparty/jquery",
	"sap/ui/test/_OpaLogger"
],
function (ManagedObject, QUnitUtils, Opa5, Device, jQueryDOM, _OpaLogger) {
	"use strict";

	/**
	 * @class Actions for Opa5 - needs to implement an executeOn function that should simulate a user interaction on a control
	 * @abstract
	 * @extends sap.ui.base.ManagedObject
	 * @public
	 * @name sap.ui.test.actions.Action
	 * @author SAP SE
	 * @since 1.34
	 */
	return ManagedObject.extend("sap.ui.test.actions.Action", {

		metadata : {
			properties: {
				/**
				 * Use this only if the target property or the default of the action does not work for your control.
				 * The id suffix of the DOM Element the press action will be executed on.
				 * For most of the controls you do not have to specify this, since the Control Adapters will find the correct DOM Element.
				 * But some controls have multiple DOM elements that could be target of your Action.
				 * Then you should set this property.
				 * For a detailed documentation of the suffix see {@link sap.ui.core.Element#$}
				 *
				 * @since 1.38
				 */
				idSuffix: {
					type: "string"
				}
			},
			publicMethods : [ "executeOn" ]
		},

		/**
		 * Checks if the matcher is matching - will get an instance of sap.ui.core.Control as parameter
		 * Should be overwritten by subclasses
		 *
		 * @param {sap.ui.core.Control} element the {@link sap.ui.core.Element} or a control (extends element) the action will be executed on
		 * @protected
		 * @name sap.ui.test.actions.Action#executeOn
		 * @function
		 */
		executeOn : function () {
			return true;
		},

		/**
		 * Finds the most suitable jQuery element to execute an action on.
		 * A control may have many elements in its DOM representation. The most suitable one is chosen by priority:
		 *

		 *
If the user provided an idSuffix, return the element that matches it, or null

		 *
If there is a control adapter for the action - return the element that matches it. See {@link sap.ui.test.Press.controlAdapters} for an example

		 *
If there is no control adapter, or it matches no elements, return the focusDomRef of the control. Note that some controls may not have a focusDomRef.

		 *

		 * @param {object} oControl the control to execute an action on
		 * @returns {jQuery} the jQuery element which is most suitable for the action
		 * @protected
		 */
		$: function (oControl) {
			var $ActionDomRef;
			var sErrorMessage = "";

			if (this.getIdSuffix()) {
				// if user requested an ID suffix, it should be used -- no fallback
				$ActionDomRef = oControl.$(this.getIdSuffix());
				sErrorMessage = $ActionDomRef.length ? "" : "DOM representation of control '" + oControl +
					"' has no element with user-provided ID suffix '" + this.getIdSuffix() + "'";
			} else {
				var sAdapter = this._getAdapter(oControl);
				if (sAdapter) {
					$ActionDomRef = oControl.$(sAdapter);
					sErrorMessage = $ActionDomRef.length ? "" : "DOM representation of control '" + oControl +
						"' has no element with ID suffix '" + sAdapter + "' which is the default adapter for '" + this.getMetadata().getName() + "'";
				}

				if (!$ActionDomRef || !$ActionDomRef.length) {
					// if no adapter is set or no element is found for it -- fallback to control focus dom ref
					$ActionDomRef = jQueryDOM(oControl.getFocusDomRef());
					if (!$ActionDomRef.length) {
						$ActionDomRef = oControl.$();
						if (!$ActionDomRef.length) {
							sErrorMessage += "DOM representation of control '" + oControl + "' has no focus DOM reference";
						}
					}
				}
			}

			if ($ActionDomRef.length) {
				this.oLogger.info("Found a DOM reference for the control '" + oControl + "'. Executing '" + this.getMetadata().getName() +
				"' on the DOM element with ID '" + $ActionDomRef[0].id + "'");
				return $ActionDomRef;
			} else {
				// the control has no dom ref of any kind - action has no target
				this.oLogger.error(sErrorMessage);
				throw new Error(sErrorMessage);
			}
		},

		/**
		 * Returns the QUnitUtils
		 * @returns {sap.ui.test.qunit.QUnitUtils} QUnit utils of the current window or the OPA frame
		 * @protected
		 */
		getUtils : function () {
			return Opa5.getUtils() || QUnitUtils;
		},

		init: function () {
			this.controlAdapters = {};
			this.oLogger = _OpaLogger.getLogger(this.getMetadata().getName());
		},

		dropPosition: {
			BEFORE: "BEFORE",
			AFTER: "AFTER",
			CENTER: "CENTER"
		},

		/**
		 * Traverses the metadata chain of a control and looks for action adapters.
		 * An action adapter is a suffix part of the ID of a DOM element, where
		 * the DOM element is part of a control DOM representation and should be used as a target for events
		 * @param {object} oControl the control for which to find an action adapter
		 * @returns {string|null} the ID suffix of the DOM element to use as event target
		 * @private
		 */
		_getAdapter : function (oControl) {
			var fnGetAdapterByMeta = function (oMetadata) {
				var vAdapter = this.controlAdapters[oMetadata.getName()];

				if (vAdapter) {
					if (jQueryDOM.isFunction(vAdapter)) {
						return vAdapter(oControl);
					}
					if (typeof vAdapter === "string") {
						return vAdapter;
					}
				}

				var oParentMetadata = oMetadata.getParent();
				if (oParentMetadata) {
					return fnGetAdapterByMeta(oParentMetadata);
				}

				return null;
			}.bind(this);

			return fnGetAdapterByMeta(oControl.getMetadata());
		},

		_tryOrSimulateFocusin: function ($DomRef, oControl) {
			var oDomRef = $DomRef[0];
			var bFireArtificialEvents = false;
			var isAlreadyFocused = this._isFocused(oDomRef);
			var bIsIE11 = Device.browser.msie && Device.browser.version < 12;
			var bIsNewFF = Device.browser.firefox && Device.browser.version >= 60;

			if (isAlreadyFocused || bIsIE11 || bIsNewFF) {
				// 1. If the event is already focused, make sure onfocusin event of the control will be properly fired when executing this action,
				// otherwise the next blur will not be able to safely remove the focus.
				// 2. In IE11 (and often in Firefox v61.0/v60.0 ESR), if the focus action fails and focusin is dispatched, onfocusin will be called twice.
				// To avoid this, directly dispatch the artificial events
				bFireArtificialEvents = true;
			} else {
				$DomRef.trigger("focus");
				var bWasFocused = this._isFocused(oDomRef);
				// if focus was successful, skip the artificial events and thus avoid recieving onfocusin twice.
				// else, fire the artificial events because we still want onfocusin to work.
				bFireArtificialEvents = !bWasFocused;
			}

			if (bFireArtificialEvents) {
				this.oLogger.debug("Control " + oControl + " could not be focused - maybe you are debugging?");

				this._createAndDispatchFocusEvent("focusin", oDomRef);
				this._createAndDispatchFocusEvent("focus", oDomRef);
				this._createAndDispatchFocusEvent("activate", oDomRef);
			}

			if (!this._isFocused(oDomRef)) {
				this.oLogger.trace("Control " + oControl + " could not be focused-in correctly. This may lead to lost interactions with the control");
			}
		},

		_simulateFocusout: function (oDomRef) {
			this._createAndDispatchFocusEvent("focusout", oDomRef);
			this._createAndDispatchFocusEvent("blur", oDomRef);
			this._createAndDispatchFocusEvent("deactivate", oDomRef);
		},

		/**
		 * Create the correct event object for a mouse event.
		 *
		 * @param {string} sName Name of the mouse event
		 * @param {Element} oDomRef DOM element on which the event is going to be triggered
		 * @private
		 */
		_createAndDispatchMouseEvent: function (sName, oDomRef) {
			// ignore scrolled down stuff (client X, Y not set)
			// and assume stuff is over the whole screen (screen X, Y not set)
			// See file jquery.sap.events.js for some insights to the magic
			var iLeftMouseButtonIndex = 0;
			var oMouseEvent;
			if (Device.browser.msie && Device.browser.version < 12) {
				oMouseEvent = document.createEvent("MouseEvent");
				oMouseEvent.initMouseEvent(sName, true, true, window, 0, 0, 0, 0, 0,
					false, false, false, false, iLeftMouseButtonIndex, oDomRef);
			} else {
				oMouseEvent = new MouseEvent(sName, {
					bubbles: true,
					cancelable: true,
					identifier: 1,
					target: oDomRef,
					radiusX: 1,
					radiusY: 1,
					rotationAngle: 0,
					button: iLeftMouseButtonIndex,
					type: sName // include the type so jQuery.event.fixHooks can copy properties properly
				});
			}
			oDomRef.dispatchEvent(oMouseEvent);
		},

		_createAndDispatchFocusEvent: function (sName, oDomRef) {
			var oFocusEvent,
				bBubbles = ["focusin", "focusout", "activate", "deactivate"].indexOf(sName) !== -1;

			if (Device.browser.msie && (Device.browser.version < 12)) {
				oFocusEvent = document.createEvent("FocusEvent");
				oFocusEvent.initFocusEvent(sName, bBubbles, false, window, 0, oDomRef);
			} else {
				oFocusEvent = new FocusEvent(sName, {
					type: sName,
					target: oDomRef,
					curentTarget: oDomRef,
					bubbles: bBubbles
				});
			}

			oDomRef.dispatchEvent(oFocusEvent);
			this.oLogger.info("Dispatched focus event: '" + sName + "'");
		},

		_createAndDispatchDragEvent: function (sName, oDomRef, oOptions) {
			// calculate drop position based on user input
			// determines where the source will be dropped: before, after or in place of the target
			if (Device.browser.msie && Device.browser.version < 12) {
				// drag and drop is not supported in IE11.
				// IE11's support for HTML5 drag and drop is questionable..
				// when an event is initialized, dataTransfer is nullified. later this causes a null reference error in sap/ui/core/dnd/DragDropInfo
				// (Unable to set property 'effectAllowed' of undefined or null reference).
				// Another difference is that DataTransfer is an object in IE11, and would be instantiate like: oDataTransfer = new DataTransfer.constructor()
				return;
			}
			var mCoordinates = this._getEventCoordinates(oDomRef, oOptions);
			var oDataTransfer = new DataTransfer();
			var oDragEvent;

			if (Device.browser.edge) {
				oDragEvent = document.createEvent("DragEvent");
				oDragEvent.initDragEvent(sName, true, true, window, 0, mCoordinates.x, mCoordinates.y, mCoordinates.x, mCoordinates.y,
					false, false, false, false, 1, oDomRef, oDataTransfer);
			} else {
				oDragEvent = new DragEvent(sName, {
					type: sName, // include the type so jQuery.event.fixHooks can copy properties properly
					eventPhase: 3,
					bubbles: true,
					cancelable: true,
					defaultPrevented: false,
					composed: true,
					returnValue: true,
					cancelBubble: false,
					target: oDomRef,
					toElement: oDomRef,
					srcElement: oDomRef,
					radiusX: 1,
					radiusY: 1,
					rotationAngle: 0,
					// coordinates are needed to infer drop elem. e.g. in the control handlers, the drop target can be recalculated using document.elementfromPoint.
					// even if set, pageXY and screenXY are zeroed. if clientXY is set, then xy and pageXY will be = clientXY, and offsetXY will be calculated correctly.
					// this may cause problems for controls outside the client area
					// in this case, users should scroll before the drag event
					clientX: mCoordinates.x,
					clientY: mCoordinates.y,
					// dataTransfer should be at least an empty object, to avoid undefined error
					dataTransfer: oDataTransfer
				});
			}

			oDomRef.dispatchEvent(oDragEvent);
		},

		_getEventCoordinates: function (oDomRef, oOptions) {
			var $domRef = jQueryDOM(oDomRef);
			var offset = $domRef.offset();
			var mCenterCoordinates = {
				x: offset.left + $domRef.outerWidth() / 2,
				y: offset.top + $domRef.outerHeight() / 2
			};
			if (!oOptions) {
				return mCenterCoordinates;
			}

			switch (oOptions.position) {
				case this.dropPosition.BEFORE:
					// coords of upper left corner
					return {
						x: offset.left,
						y: offset.top
					};
				case this.dropPosition.AFTER:
					// coords of bottom right corner
					return {
						x: offset.left + $domRef.outerWidth(),
						y: offset.top + $domRef.outerHeight()
					};
				case this.dropPosition.CENTER:
				default:
					return mCenterCoordinates;
			}
		},

		_isFocused: function (oDomRef) {
			// This check returns false if:
			// 1. you have the focus in the dev tools console, or a background tab, or the browser is not focused at all. (bDocumentHasFocus will be false)
			// 2. in IE11 and Firefox, because the document.activeElement wasn't updated. (bIsActiveElement will be false)
			var bIsActiveElement = oDomRef === document.activeElement;
			var bDocumentHasFocus = !document.hasFocus || document.hasFocus();
			var bIsElemInBody = !!(oDomRef.type || oDomRef.href || ~oDomRef.tabIndex);
			return bIsActiveElement && bDocumentHasFocus && bIsElemInBody;
		}
	});

});
<|endoftext|>


<commit_before>import P from '../components/paragraph'
import Post from '../components/post'

export default () => (

    <Post title='My first blog post'>

Hello there

This is an example of a componentized blog post

    </Post>

    <Post title='My second blog post'>

Hello there

This is another example.

Wa-hoo!

    </Post>

    <Post title='The final blog post'>

C'est fin

    </Post>

)
<commit_msg>examples/nested-components: use an apostrophe rather than a prime (#566)<commit_after>import P from '../components/paragraph'
import Post from '../components/post'

export default () => (

    <Post title='My first blog post'>

Hello there

This is an example of a componentized blog post

    </Post>

    <Post title='My second blog post'>

Hello there

This is another example.

Wa-hoo!

    </Post>

    <Post title='The final blog post'>

C’est fin

    </Post>

)
<|endoftext|>


<commit_before>'use strict';
const integrationTestHelpers = require('./integrationTestHelpers.js');
const sample = require('lodash').sample;
let uuid = require('node-uuid');

let request = require('supertest-as-promised');
const instanceUrl = process.env.INSTANCE_URL;
let app = instanceUrl ? instanceUrl : require('../../../src/app');

let listOfBranches = (res) => {
    if (!('branches' in res.body)) {
        throw new Error('branches not found');
    }
};

let listOfGroups = (res) => {
    if (!('groups' in res.body)) {
        throw new Error('groups not found');
    }
};

let listOfAdmins = (res) => {
    if (!('admins' in res.body)) {
        throw new Error('admins not found');
    }
};

let getBranches = () => {
    return request(app)
        .get('/branches')
        .expect(200)
        .expect(listOfBranches);
};

let makeBranch = () => {
    return {
        name: 'Melbourne',
        notes: 'organiser',
        contact: 'hey i\'m a contact',
    };
};

let makeBranchUpdates = (branch) => {
    branch.name = 'New Name!';
    return branch;
};

let hasBranch = (res) => {
    if (!(res.body.id)) {
        throw new Error('missing created branch');
    }
};

describe.only('Branches Integration Test', () => {

    let agent;
    let browserState = {};

    beforeEach(() => {
        agent = request.agent(app);

        return integrationTestHelpers.resetDatabase()
        .then(integrationTestHelpers.createBranch)
        .tap(integrationTestHelpers.createBranchAdmin)
        .tap(integrationTestHelpers.authenticateBranchAdmin(agent))
        .then(branch => {
            browserState.branch = branch;
        });
    });

    afterEach(() => {
        browserState = {};
    });

    it('should return a list of branches', () => {
        return getBranches();
    });

    it('should return a list of groups for a branch', () => {
        return agent
            .get(`/branches/${browserState.branch.id}/groups`)
            .expect(200)
            .expect(listOfGroups);
    });

    it('should return a list of admins for a branch', () => {
        return agent
            .get(`/branches/${browserState.branch.id}/admins`)
            .expect(200)
            .expect(listOfAdmins);
    });

    it('should return the list of branches the admin user has access to', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(res.body.branches.length).to.equal(1);
                expect(res.body.branches[0].id).to.equal(browserState.branch.id);
            });
    });

    it('should return a list of all branches for a super admin', () => {
        return integrationTestHelpers.createBranch()
        .then(integrationTestHelpers.createBranch)
        .tap(integrationTestHelpers.createSuperAdmin)
        .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
        .then(() => {
            return agent.get('/admin/branches')
                .expect(200)
                .then((res) => {
                    expect(res.body.branches).not.to.be.null;
                    expect(res.body.branches.length).to.equal(3);
                    expect(sample(res.body.r));
                });
        });
    });

    it('should return branches notes for super admins', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(sample(res.body.branches).notes).not.to.be.null;
            });
    });

    it('should not return branches notes for branch admins', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(sample(res.body.branches).notes).to.be.undefined;
            });
    });

    describe('delete', () => {
        it('should return a 200 when the branch is successfully deleted', () => {
            return integrationTestHelpers.createBranch()
                .tap(integrationTestHelpers.createSuperAdmin)
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then((branch) => {
                    return agent.delete(`/branches/${branch.id}/`)
                    .expect(200);
                });
        });

        it('should return a 400 if the input data is not valid', () => {
            return integrationTestHelpers.createSuperAdmin()
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.delete(`/branches/whatevs/`)
                    .expect(400);
                });
        });

        it('should return 500 when trying to delete a branch that does not exist', () => {
            return integrationTestHelpers.createBranch()
                .tap(integrationTestHelpers.createSuperAdmin)
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.delete(`/branches/${uuid.v4()}/`)
                    .expect(500);
                });
        });
    });

    describe('add', () => {

        it('should return 200 and a created branch when the input is valid', () => {
            return integrationTestHelpers.createSuperAdmin()
                .then(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .send(makeBranch())
                        .expect(200)
                        .expect(getBranches);
            });
        });

        it('should return 400 if the input is null', () => {
            return integrationTestHelpers.createSuperAdmin()
                .then(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .set('Accept', 'application/json')
                        .send(null)
                        .expect(400);
            });
        });

        it('should return 400 if the input is incomplete', () => {
            return integrationTestHelpers.createSuperAdmin()
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .set('Accept', 'application/json')
                        .send({invalid:'invalid'})
                        .expect(400);
            });
        });
    });

    describe('update', () => {
        it('should return 200 and an updated branch when the input is valid', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}/`)
                    .set('Content-Type', 'application/json')
                    .send(makeBranchUpdates(branch))
                    .expect(200)
                    .expect(hasBranch);
            });
        });

        it('should allow update without the password field in the payload', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send(makeBranchUpdates(branch))
                    .expect(200)
                    .expect(hasBranch);
            });
        });

        it('should return 400 if the input is null', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send(null)
                    .expect(400);
            });
        });

        it('should return 400 if the input is incomplete', () => {
            return integrationTestHelpers.createBranch()
            .then(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then(() => {
                return agent.put(`/branches/whatevs`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send({invalid: 'invalid'})
                    .expect(400);
            });
        });

    });
});
<commit_msg>removing the .only<commit_after>'use strict';
const integrationTestHelpers = require('./integrationTestHelpers.js');
const sample = require('lodash').sample;
let uuid = require('node-uuid');

let request = require('supertest-as-promised');
const instanceUrl = process.env.INSTANCE_URL;
let app = instanceUrl ? instanceUrl : require('../../../src/app');

let listOfBranches = (res) => {
    if (!('branches' in res.body)) {
        throw new Error('branches not found');
    }
};

let listOfGroups = (res) => {
    if (!('groups' in res.body)) {
        throw new Error('groups not found');
    }
};

let listOfAdmins = (res) => {
    if (!('admins' in res.body)) {
        throw new Error('admins not found');
    }
};

let getBranches = () => {
    return request(app)
        .get('/branches')
        .expect(200)
        .expect(listOfBranches);
};

let makeBranch = () => {
    return {
        name: 'Melbourne',
        notes: 'organiser',
        contact: 'hey i\'m a contact',
    };
};

let makeBranchUpdates = (branch) => {
    branch.name = 'New Name!';
    return branch;
};

let hasBranch = (res) => {
    if (!(res.body.id)) {
        throw new Error('missing created branch');
    }
};

describe('Branches Integration Test', () => {

    let agent;
    let browserState = {};

    beforeEach(() => {
        agent = request.agent(app);

        return integrationTestHelpers.resetDatabase()
        .then(integrationTestHelpers.createBranch)
        .tap(integrationTestHelpers.createBranchAdmin)
        .tap(integrationTestHelpers.authenticateBranchAdmin(agent))
        .then(branch => {
            browserState.branch = branch;
        });
    });

    afterEach(() => {
        browserState = {};
    });

    it('should return a list of branches', () => {
        return getBranches();
    });

    it('should return a list of groups for a branch', () => {
        return agent
            .get(`/branches/${browserState.branch.id}/groups`)
            .expect(200)
            .expect(listOfGroups);
    });

    it('should return a list of admins for a branch', () => {
        return agent
            .get(`/branches/${browserState.branch.id}/admins`)
            .expect(200)
            .expect(listOfAdmins);
    });

    it('should return the list of branches the admin user has access to', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(res.body.branches.length).to.equal(1);
                expect(res.body.branches[0].id).to.equal(browserState.branch.id);
            });
    });

    it('should return a list of all branches for a super admin', () => {
        return integrationTestHelpers.createBranch()
        .then(integrationTestHelpers.createBranch)
        .tap(integrationTestHelpers.createSuperAdmin)
        .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
        .then(() => {
            return agent.get('/admin/branches')
                .expect(200)
                .then((res) => {
                    expect(res.body.branches).not.to.be.null;
                    expect(res.body.branches.length).to.equal(3);
                    expect(sample(res.body.r));
                });
        });
    });

    it('should return branches notes for super admins', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(sample(res.body.branches).notes).not.to.be.null;
            });
    });

    it('should not return branches notes for branch admins', () => {
        return agent.get('/admin/branches')
            .expect(200)
            .then((res) => {
                expect(res.body.branches).not.to.be.null;
                expect(sample(res.body.branches).notes).to.be.undefined;
            });
    });

    describe('delete', () => {
        it('should return a 200 when the branch is successfully deleted', () => {
            return integrationTestHelpers.createBranch()
                .tap(integrationTestHelpers.createSuperAdmin)
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then((branch) => {
                    return agent.delete(`/branches/${branch.id}/`)
                    .expect(200);
                });
        });

        it('should return a 400 if the input data is not valid', () => {
            return integrationTestHelpers.createSuperAdmin()
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.delete(`/branches/whatevs/`)
                    .expect(400);
                });
        });

        it('should return 500 when trying to delete a branch that does not exist', () => {
            return integrationTestHelpers.createBranch()
                .tap(integrationTestHelpers.createSuperAdmin)
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.delete(`/branches/${uuid.v4()}/`)
                    .expect(500);
                });
        });
    });

    describe('add', () => {

        it('should return 200 and a created branch when the input is valid', () => {
            return integrationTestHelpers.createSuperAdmin()
                .then(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .send(makeBranch())
                        .expect(200)
                        .expect(getBranches);
            });
        });

        it('should return 400 if the input is null', () => {
            return integrationTestHelpers.createSuperAdmin()
                .then(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .set('Accept', 'application/json')
                        .send(null)
                        .expect(400);
            });
        });

        it('should return 400 if the input is incomplete', () => {
            return integrationTestHelpers.createSuperAdmin()
                .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
                .then(() => {
                    return agent.post(`/branches`)
                        .set('Content-Type', 'application/json')
                        .set('Accept', 'application/json')
                        .send({invalid:'invalid'})
                        .expect(400);
            });
        });
    });

    describe('update', () => {
        it('should return 200 and an updated branch when the input is valid', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}/`)
                    .set('Content-Type', 'application/json')
                    .send(makeBranchUpdates(branch))
                    .expect(200)
                    .expect(hasBranch);
            });
        });

        it('should allow update without the password field in the payload', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send(makeBranchUpdates(branch))
                    .expect(200)
                    .expect(hasBranch);
            });
        });

        it('should return 400 if the input is null', () => {
            return integrationTestHelpers.createBranch()
            .tap(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then((branch) => {
                return agent.put(`/branches/${branch.id}`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send(null)
                    .expect(400);
            });
        });

        it('should return 400 if the input is incomplete', () => {
            return integrationTestHelpers.createBranch()
            .then(integrationTestHelpers.createSuperAdmin)
            .tap(integrationTestHelpers.authenticateSuperAdmin(agent))
            .then(() => {
                return agent.put(`/branches/whatevs`)
                    .set('Content-Type', 'application/json')
                    .set('Accept', 'application/json')
                    .send({invalid: 'invalid'})
                    .expect(400);
            });
        });

    });
});
<|endoftext|>


<commit_before>import {startWatcher} from '../api/FsApi';
import * as GitApi from '../api/GitApi';
require('promise.prototype.finally');

// workingTree: only receive_status used.
export const RECEIVE_STATUS = 'RECEIVE_STATUS';

// stashes- all used but misses external updates!
export const RECEIVE_STASHES = 'RECEIVE_STASHES';
export const STASH_CREATED = 'STASH_CREATED';
export const STASH_POPPED = 'STASH_POPPED';

// commits
export const RECEIVE_COMMITS = 'RECEIVE_COMMITS';
export const RECEIVE_REMOTE_COMMITS = 'RECEIVE_REMOTE_COMMITS';
// commits not used.
export const REMOTE_FETCHED = 'REMOTE_FETCHED';
export const REMOTE_PUSHED = 'REMOTE_PUSHED';

const FSEVENT_DELAY = 500;
const repoPath = '.';

GitApi.getRepository(repoPath);

let refreshTrigger;

let refreshTriggered = false;

function remotePushed() {
  return {
    type: REMOTE_PUSHED
  };
}

let fsEventsEnabled = true;

function globalRefresh() {
  return dispatch => {
    dispatch(getStatus());
    dispatch(getLog());
    dispatch(getStashes());
  };
}

export function startMonitor() {
  return dispatch => {
    startWatcher(repoPath, () => {
      if (refreshTriggered) {
        global.clearTimeout(refreshTrigger);
      }

      if (!fsEventsEnabled) return;

      refreshTriggered = true;
      refreshTrigger = global.setTimeout(() => {
        refreshTriggered = false;
        console.log('Monitor - refresh triggered');
        dispatch(globalRefresh());
      }, FSEVENT_DELAY);
    });
  };
}

function muteFsEvents() {
  fsEventsEnabled = false;
  console.log('FS events muted');
}

function unMuteFsEvents() {
  setTimeout(() => {
    fsEventsEnabled = true;
    console.log('FS events unmuted');
  }, 1000);
}

export function fetch() {
  return dispatch => {
    GitApi.fetch()
      .then(() => GitApi.getRemoteLog())
      .then(commits => dispatch(receiveRemoteCommits(commits)));
  };
}

export function push() {
  return dispatch => {
    GitApi.push()
      .then(() => dispatch(remotePushed()));
  };
}

export function workingDirChanged() {
  return {
    type: WORKINGDIR_CHANGED
  };
}

export function receiveCommits(commits) {
  return {
    type: RECEIVE_COMMITS,
    commits: commits
  };
}

export function receiveRemoteCommits(commits) {
  return {
    type: RECEIVE_REMOTE_COMMITS,
    commits: commits
  };
}

export function stashCreated(newStash) {
  return {
    type: STASH_CREATED,
    stash: newStash
  };
}

export function stashPopped() {
  return {
    type: STASH_POPPED
  };
}

function commitCreated() {
  return dispatch => {
    GitApi.getLog()
      .then(commits => dispatch(receiveCommits(commits)));
    dispatch(getStatus());
  };
}

export function commit(text) {
  return dispatch => {
    muteFsEvents();
    GitApi.createCommit(text)
      .then(() => {
        dispatch(commitCreated());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function getLog() {
  return dispatch => {
    console.log('getting local commits');
    GitApi.getLog()
      .then(commits => dispatch(receiveCommits(commits)));
    console.log('getting remote commits');
    GitApi.getRemoteLog()
      .then(commits => dispatch(receiveRemoteCommits(commits)));
  };
}

export function receiveStatus(statuses) {
  return {
    type: RECEIVE_STATUS,
    statuses: statuses
  };
}

export function receiveStashes(stashes) {
  return {
    type: RECEIVE_STASHES,
    stashes: stashes
  };
}

export function stagePath(path) {
  return dispatch => {
    muteFsEvents();
    GitApi.stagePath(path)
      .then(() => dispatch(getStatus()))
      .catch(error => console.warn(error))
      .finally(() => unMuteFsEvents());
  };
}

export function resetPath(path) {
  return dispatch => {
    muteFsEvents();
    GitApi.resetPath(path)
      .then(() => dispatch(getStatus()))
      .finally(() => unMuteFsEvents());
  };
}

export function getStashes() {
  return dispatch => {
    console.log('getting stashes');
    GitApi.getStashes()
      .then(stashes => dispatch(receiveStashes(stashes)));
  };
}
export function stash() {
  return dispatch => {
    muteFsEvents();
    GitApi.stash()
      .then(newStash => {
        dispatch(stashCreated(newStash));
        dispatch(getStatus());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function popStash() {
  return dispatch => {
    muteFsEvents();
    GitApi.popStash()
      .then(() => {
        dispatch(stashPopped());
        dispatch(getStatus());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function getStatus() {
  return dispatch => {
    console.log('getting status');
    GitApi.getStatus()
      .then(status => dispatch(receiveStatus(status)));
  };
}
<commit_msg>fs muting for fetch/push, clean up some unused actions.<commit_after>import {startWatcher} from '../api/FsApi';
import * as GitApi from '../api/GitApi';
require('promise.prototype.finally');

// workingTree: only receive_status used.
export const RECEIVE_STATUS = 'RECEIVE_STATUS';

// stashes- all used but misses external updates!
export const RECEIVE_STASHES = 'RECEIVE_STASHES';
export const STASH_CREATED = 'STASH_CREATED';
export const STASH_POPPED = 'STASH_POPPED';

// commits
export const RECEIVE_COMMITS = 'RECEIVE_COMMITS';
export const RECEIVE_REMOTE_COMMITS = 'RECEIVE_REMOTE_COMMITS';

const FSEVENT_DELAY = 500;
const repoPath = '.';

GitApi.getRepository(repoPath);

let refreshTrigger;

let refreshTriggered = false;

let fsEventsEnabled = true;

function globalRefresh() {
  return dispatch => {
    dispatch(getStatus());
    dispatch(getLog());
    dispatch(getStashes());
  };
}

export function startMonitor() {
  return dispatch => {
    startWatcher(repoPath, () => {
      if (refreshTriggered) {
        global.clearTimeout(refreshTrigger);
      }

      if (!fsEventsEnabled) return;

      refreshTriggered = true;
      refreshTrigger = global.setTimeout(() => {
        refreshTriggered = false;
        console.log('Monitor - refresh triggered');
        dispatch(globalRefresh());
      }, FSEVENT_DELAY);
    });
  };
}

function muteFsEvents() {
  fsEventsEnabled = false;
  console.log('FS events muted');
}

function unMuteFsEvents() {
  setTimeout(() => {
    fsEventsEnabled = true;
    console.log('FS events unmuted');
  }, 1000);
}

export function fetch() {
  return dispatch => {
    muteFsEvents();
    GitApi.fetch()
      .then(() => GitApi.getRemoteLog())
      .then(commits => dispatch(receiveRemoteCommits(commits)))
      .finally(() => unMuteFsEvents());
  };
}

export function push() {
  return dispatch => {
    muteFsEvents();
    GitApi.push()
      .then(() => GitApi.getRemoteLog())
      .then(commits => dispatch(receiveRemoteCommits(commits)))
      .finally(() => unMuteFsEvents());
  };
}

export function receiveCommits(commits) {
  return {
    type: RECEIVE_COMMITS,
    commits: commits
  };
}

export function receiveRemoteCommits(commits) {
  return {
    type: RECEIVE_REMOTE_COMMITS,
    commits: commits
  };
}

export function stashCreated(newStash) {
  return {
    type: STASH_CREATED,
    stash: newStash
  };
}

export function stashPopped() {
  return {
    type: STASH_POPPED
  };
}

function commitCreated() {
  return dispatch => {
    GitApi.getLog()
      .then(commits => dispatch(receiveCommits(commits)));
    dispatch(getStatus());
  };
}

export function commit(text) {
  return dispatch => {
    muteFsEvents();
    GitApi.createCommit(text)
      .then(() => {
        dispatch(commitCreated());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function getLog() {
  return dispatch => {
    console.log('getting local commits');
    GitApi.getLog()
      .then(commits => dispatch(receiveCommits(commits)));
    console.log('getting remote commits');
    GitApi.getRemoteLog()
      .then(commits => dispatch(receiveRemoteCommits(commits)));
  };
}

export function receiveStatus(statuses) {
  return {
    type: RECEIVE_STATUS,
    statuses: statuses
  };
}

export function receiveStashes(stashes) {
  return {
    type: RECEIVE_STASHES,
    stashes: stashes
  };
}

export function stagePath(path) {
  return dispatch => {
    muteFsEvents();
    GitApi.stagePath(path)
      .then(() => dispatch(getStatus()))
      .catch(error => console.warn(error))
      .finally(() => unMuteFsEvents());
  };
}

export function resetPath(path) {
  return dispatch => {
    muteFsEvents();
    GitApi.resetPath(path)
      .then(() => dispatch(getStatus()))
      .finally(() => unMuteFsEvents());
  };
}

export function getStashes() {
  return dispatch => {
    console.log('getting stashes');
    GitApi.getStashes()
      .then(stashes => dispatch(receiveStashes(stashes)));
  };
}
export function stash() {
  return dispatch => {
    muteFsEvents();
    GitApi.stash()
      .then(newStash => {
        dispatch(stashCreated(newStash));
        dispatch(getStatus());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function popStash() {
  return dispatch => {
    muteFsEvents();
    GitApi.popStash()
      .then(() => {
        dispatch(stashPopped());
        dispatch(getStatus());
      })
      .finally(() => unMuteFsEvents());
  };
}

export function getStatus() {
  return dispatch => {
    console.log('getting status');
    GitApi.getStatus()
      .then(status => dispatch(receiveStatus(status)));
  };
}
<|endoftext|>


<commit_before>import {
  ADD_TASK,
  DELETE_TASK,
  EDIT_TASK,
  CHANGE_TASK_STATUS,
  INVALIDATE_TASKS,
  REQUEST_TASKS,
  REQUEST_TASKS_SUCCESS,
  REQUEST_TASKS_FAILED,
  UPDATE_TASK_REQUEST,
  UPDATE_TASK_SUCCESS,
  UPDATE_TASK_FAILED,
  UPDATE_SCHEDULE,
  CALL_API
} from '../constants/ActionTypes';
import { STATUS_COMPLETED } from '../constants/TaskStatuses';
import { doPut, doGet } from '../utils/apiUtils';
import { getTimeToSchedule } from '../utils/time';
import moment from 'moment-timezone';
import _ from 'lodash';

export function addTask(text) {
  return { type: ADD_TASK, text };
}

export function deleteTask(id) {
  return { type: DELETE_TASK, id };
}

export function editTask(id, text) {
  return { type: EDIT_TASK, id, text };
}

export function changeStatus(id) {
  return { type: CHANGE_TASK_STATUS, id };
}

export function toggleTaskStasus(id) {
  return (dispatch, getState) => {
    dispatch(changeStatus(id));
    const task = getState().tasks.items.find(loopTask => loopTask.id === id);

    return dispatch(updateTask(task));
  };
}

export function invalidateTasks() {
  return {
    type: INVALIDATE_TASKS
  };
}

export function scheduleTasks(tasks) {
  return (dispatch, getState) => {
    let taskScheduleMap = getState().tasks.schedule;
    // clear all timeout IDs
    _.forOwn(taskScheduleMap, (scheduleData) => {
      clearTimeout(scheduleData.timeoutId);
    });
    taskScheduleMap = {};

    tasks.forEach(function (task) {
      if (task.status === STATUS_COMPLETED) {
        return;
      }
      const time = getTimeToSchedule(task.text);
      if (time) {
        const deltaSeconds = moment(time, 'HH:mm').unix() - moment().unix();

        if (deltaSeconds >= 0) {
          const timeoutId = setTimeout(() => dispatch({
            type: 'SHOW_NOTIFICATION',
            payload: task.transformedText
          }), deltaSeconds * 1000);

          taskScheduleMap[task.id] = {
            timeoutId,
            scheduledFor: time
          };
        }
      }
    });

    return dispatch({ type: UPDATE_SCHEDULE, payload: taskScheduleMap });
  };
}

function fetchTasks() {
  return dispatch => {
    dispatch({
      type: CALL_API,
      statuses: [REQUEST_TASKS, REQUEST_TASKS_SUCCESS, REQUEST_TASKS_FAILED],
      doApiCall: (accessToken) => {
        return doGet('/api/todos', { day: 'today' }, accessToken)
          .then((tasks) => {
            dispatch(scheduleTasks(tasks));
            return tasks;
          });
      }
    });
  };
}

export function shouldFetchTasks(state) {
  const fetchedAt = state.fetchedAt;

  if (!fetchedAt) {
    return true;
  } else if (state.isFetching) {
    return false;
  }

  return state.didInvalidate;
}

export function fetchTasksIfNeeded() {
  return (dispatch, getState) => {
    if (shouldFetchTasks(getState())) {
      return dispatch(fetchTasks());
    }
  };
}

export function updateTask(task) {
  return (dispatch, getState) =>  {
    dispatch({
      type: CALL_API,
      statuses: [UPDATE_TASK_REQUEST, UPDATE_TASK_SUCCESS, UPDATE_TASK_FAILED],
      doApiCall: (accessToken) => {
        var url = `/api/todos/${ task.id }`;
        return doPut(url, task, accessToken).
          then(response => {
            dispatch(scheduleTasks(getState().tasks.items));
            return response;
          });
      }
    });
  }
}
<commit_msg>Update schedule when user change the task status<commit_after>import {
  ADD_TASK,
  DELETE_TASK,
  EDIT_TASK,
  CHANGE_TASK_STATUS,
  INVALIDATE_TASKS,
  REQUEST_TASKS,
  REQUEST_TASKS_SUCCESS,
  REQUEST_TASKS_FAILED,
  UPDATE_TASK_REQUEST,
  UPDATE_TASK_SUCCESS,
  UPDATE_TASK_FAILED,
  UPDATE_SCHEDULE,
  CALL_API
} from '../constants/ActionTypes';
import { STATUS_COMPLETED } from '../constants/TaskStatuses';
import { doPut, doGet } from '../utils/apiUtils';
import { getTimeToSchedule } from '../utils/time';
import moment from 'moment-timezone';
import _ from 'lodash';

export function addTask(text) {
  return { type: ADD_TASK, text };
}

export function deleteTask(id) {
  return { type: DELETE_TASK, id };
}

export function editTask(id, text) {
  return { type: EDIT_TASK, id, text };
}

export function changeStatus(id) {
  return { type: CHANGE_TASK_STATUS, id };
}

export function toggleTaskStasus(id) {
  return (dispatch, getState) => {
    dispatch(changeStatus(id));
    const task = getState().tasks.items.find(loopTask => loopTask.id === id);

    return dispatch(updateTask(task));
  };
}

export function invalidateTasks() {
  return {
    type: INVALIDATE_TASKS
  };
}

export function scheduleTasks(tasks) {
  return (dispatch, getState) => {
    let taskScheduleMap = getState().tasks.schedule;
    // clear all timeout IDs
    _.forOwn(taskScheduleMap, (scheduleData) => {
      clearTimeout(scheduleData.timeoutId);
    });
    taskScheduleMap = {};

    tasks.forEach(function (task) {
      if (task.status === STATUS_COMPLETED) {
        return;
      }
      const time = getTimeToSchedule(task.text);
      if (time) {
        const deltaSeconds = moment(time, 'HH:mm').unix() - moment().unix();

        if (deltaSeconds >= 0) {
          const timeoutId = setTimeout(() => dispatch({
            type: 'SHOW_NOTIFICATION',
            payload: task.transformedText
          }), deltaSeconds * 1000);

          taskScheduleMap[task.id] = {
            timeoutId,
            scheduledFor: time
          };
        }
      }
    });

    return dispatch({ type: UPDATE_SCHEDULE, payload: taskScheduleMap });
  };
}

function fetchTasks() {
  return dispatch => {
    dispatch({
      type: CALL_API,
      statuses: [REQUEST_TASKS, REQUEST_TASKS_SUCCESS, REQUEST_TASKS_FAILED],
      doApiCall: (accessToken) => {
        return doGet('/api/todos', { day: 'today' }, accessToken)
          .then((tasks) => {
            dispatch(scheduleTasks(tasks));
            return tasks;
          });
      }
    });
  };
}

export function shouldFetchTasks(state) {
  const fetchedAt = state.fetchedAt;

  if (!fetchedAt) {
    return true;
  } else if (state.isFetching) {
    return false;
  }

  return state.didInvalidate;
}

export function fetchTasksIfNeeded() {
  return (dispatch, getState) => {
    if (shouldFetchTasks(getState())) {
      return dispatch(fetchTasks());
    }
  };
}

export function updateTask(task) {
  return (dispatch, getState) => {
    dispatch({
      type: CALL_API,
      statuses: [UPDATE_TASK_REQUEST, UPDATE_TASK_SUCCESS, UPDATE_TASK_FAILED],
      doApiCall: (accessToken) => {
        var url = `/api/todos/${ task.id }`;
        return doPut(url, task, accessToken).
          then(response => {
            dispatch(scheduleTasks(getState().tasks.items));
            return response;
          });
      }
    });
  };
}
<|endoftext|>


<commit_before>const fs = require('fs');

// Commands are called with the following arguments:
// commands[command](message, config, msg, ...parameters)
// msg is the message content without the prefix or command
module.exports = {
    'ping': (message) => {
        message.reply("pong!");
    },

    // _ denotes arguments we don't care about
    'echo': (message, _, msg) => {
        if (msg) {
            message.channel.send(msg);
        }
    },

    'prefix': (message, config, _, newPrefix) => {
        if (newPrefix) {
            config.prefix = newPrefix;
            fs.writeFile("./config.json", JSON.stringify(config, null, 4), err => console.error);
            message.channel.send(`Prefix successfully set to '${newPrefix}'`)
        } else {
            message.channel.send("Please provide a prefix.");
        }
    },

    'die': (message, config) => {
        if (message.author.id === config.ids.soupmaster) {
            message.channel.send("Emptying can...")
                .then(() => {
                    console.log("Forced to disconnect.");
                    process.exit(0);
                });
        }
    },

    'factcheck': (message, _, msg) => {
        let bool1 = (Math.random() > 0.5),
            bool2 = (Math.random() > 0.5),
            str;

        if (msg) {
            str = `${message.author}'s claim, "${msg}",`
            str = bool1 ? `${str} is obviously ${bool2.toString()}.`
                        : `${str} can't possibly be ${bool2.toString()}.`;
        } else {
            str = bool1 ? `${message.author} is always ${bool2 ? "right" : "wrong"}.`
                        : `${message.author} is never ${bool2 ? "right" : "wrong"}.`
        }
        message.channel.send(str);
    },

    'coin': (message) => {
        let bool = (Math.random() > 0.5);
        message.channel.send(bool ? "Heads." : "Tails.");
    },

    'dice': (message, _, _, n) => {
        n = n || 6;
        message.channel.send(Math.floor(Math.random()*n) + 1);
    }
}
<commit_msg>Fix dice command<commit_after>const fs = require('fs');

// Commands are called with the following arguments:
// commands[command](message, config, msg, ...parameters)
// msg is the message content without the prefix or command
module.exports = {
    'ping': (message) => {
        message.reply("pong!");
    },

    // _ denotes arguments we don't care about
    'echo': (message, _, msg) => {
        if (msg) {
            message.channel.send(msg);
        }
    },

    'prefix': (message, config, _, newPrefix) => {
        if (newPrefix) {
            config.prefix = newPrefix;
            fs.writeFile("./config.json", JSON.stringify(config, null, 4), err => console.error);
            message.channel.send(`Prefix successfully set to '${newPrefix}'`)
        } else {
            message.channel.send("Please provide a prefix.");
        }
    },

    'die': (message, config) => {
        if (message.author.id === config.ids.soupmaster) {
            message.channel.send("Emptying can...")
                .then(() => {
                    console.log("Forced to disconnect.");
                    process.exit(0);
                });
        }
    },

    'factcheck': (message, _, msg) => {
        let bool1 = (Math.random() > 0.5),
            bool2 = (Math.random() > 0.5),
            str;

        if (msg) {
            str = `${message.author}'s claim, "${msg}",`
            str = bool1 ? `${str} is obviously ${bool2.toString()}.`
                        : `${str} can't possibly be ${bool2.toString()}.`;
        } else {
            str = bool1 ? `${message.author} is always ${bool2 ? "right" : "wrong"}.`
                        : `${message.author} is never ${bool2 ? "right" : "wrong"}.`
        }
        message.channel.send(str);
    },

    'coin': (message) => {
        let bool = (Math.random() > 0.5);
        message.channel.send(bool ? "Heads." : "Tails.");
    },

    'dice': (message, _, __, n) => {
        n = Math.max(parseInt(n), 0) || 6;
        message.channel.send(Math.floor(Math.random()*n) + 1);
    }
}
<|endoftext|>


<commit_before>/**
* Copyright 2017 HUAWEI. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* @file, definition of the MonitorDocker class
*        which is used to watch the resource consumption of specific local docker containers
*/

'use strict'

// todo: now we record the performance information in local variable, should use db later
var MonitorDocker = class {
    constructor(filter, interval) {
        this.filter       = filter;
        this.interval     = interval*1000; // ms
        this.si           = require('systeminformation');
        this.containers   = [];
        this.isReading    = false;
        this.intervalObj  = null;
        /* record statistics of each container
            {
                'time' : [] // time slot
                'container_id" : {              // refer to https://www.npmjs.com/package/systeminformatioin
                    'mem_usage'   : [],
                    'mem_percent' : [],
                    'cpu_percent' : [],
                    'netIO_rx'    : [],
                    'netIO_tx'    : [],
                    'blockIO_rx'  : [],
                    'blockIO_wx'  : []
                }
                next container
                .....
            }
        */
        this.stats = null;

    }

    /**
    * start monitoring
    * @isRestart {Boolean}, indicate whether it is restarting the monitor
    * @return {Promise}
    */
    start(isRestart) {
        if(typeof isRestart === 'undefined') {
            isRestart = false;
        }

        var p;
        if(isRestart) {
            p = Promise.resolve();
        }
        else {
            this.containers = [];
            this.stats = {'time': []};
            p = findContainers.call(this);
        }

        return p.then( () => {
            var self = this;
            function readContainerStats() {
                if(self.isReading) {
                    return;
                }
                self.isReading = true;
                var statPromises = [];
                for(let i = 0 ;i < self.containers.length ; i++){
                    statPromises.push(self.si.dockerContainerStats(self.containers[i].id));
                }
                Promise.all(statPromises).then((results) => {
                    self.stats.time.push(process.uptime());
                    for(let key in results) {
                        let stat = results[key];
                        self.stats[stat.id].mem_usage.push(stat.mem_usage);
                        self.stats[stat.id].mem_percent.push(stat.mem_percent);
                        self.stats[stat.id].cpu_percent.push(stat.cpu_percent);
                        self.stats[stat.id].netIO_rx.push(stat.netIO.rx);
                        self.stats[stat.id].netIO_tx.push(stat.netIO.tx);
                        self.stats[stat.id].blockIO_rx.push(stat.blockIO.r);
                        self.stats[stat.id].blockIO_wx.push(stat.blockIO.w);
                    }
                    self.isReading = false;
                })
                .catch((err) => {
                    self.isReading = false;
                });
            };

            readContainerStats();   // read stats  immediately
            this.intervalObj = setInterval(readContainerStats, this.interval);
            return Promise.resolve();
        })
        .catch((err) => {
            return Promise.reject(err);
        });
    }

    restart() {
        clearInterval(this.intervalObj);
        for(let key in this.stats) {
            if(key === 'time') {
                this.stats[key] = [];
            }
            else {
                for(let v in this.stats[key]) {
                    this.stats[key][v] = [];
                }
            }
        }

        return this.start(true);
    }

    stop() {
        clearInterval(this.intervalObj);
        this.containers = [];
        this.stats      = null;

        return sleep(100);
    }

    /**
    * Get peer list and predefined readable information
    * @return {Array}, {key, info={...}}
    */
    getBriefPeerInfo() {
        var info = [];
        for(let i in this.containers) {
            let c = this.containers[i];
            if(c.hasOwnProperty('id')) {
                info.push({
                    'key'  : c.id,
                    'info' : {
                        'ID' : c.id,
                        'NAME' : c.name
                    }
                });
            }
        }
        return info;
    }

    /**
    * Get peer's history of memory usage, byte
    * @key {string}, peer's key
    * @return {Array}
    */
    getMemHistory(key) {
        return this.stats[key].mem_usage;
    }

    /**
    * Get peer's history of cpu percent, %
    * @key {string}, peer's key
    * @return {Array}
    */
    getCpuHistory(key) {
        return this.stats[key].cpu_percent;
    }

    /**
    * Get peer's history of network io usage, byte
    * @key {string}, peer's key
    * @return {Array}, [{in: inflow traffic, out: outflow traffic}]
    */
    getNetworkHistory(key) {
        return {'in': this.stats[key].netIO_rx, 'out':this.stats[key].netIO_tx};
    }
};
module.exports = MonitorDocker;

/**
* Find local containers according to searching filters
*/
function findContainers() {
    var filterName = this.filter['name'];
    var all = false;
    if(typeof filterName !== 'undefined' && filterName[0] === 'all') {
        all = true;
    }

    return this.si.dockerContainers('active').then((containers) => {
        var size = containers.length;
        if(size === 0) {
            return Promise.reject(new Error('systeminformation: could not find active container'));
        }

        if(all) {
            for(let i = 0 ; i < size ; i++){
                this.containers.push(containers[i]);
                this.stats[containers[i].id] = newContainerStat();
            }
        }
        else {
            // get containers by name
            if(typeof filterName !== 'undefined') {
                for(let i = 0 ; i < size ; i++){
                    if(filterName.indexOf(containers[i].name) >= 0) {
                        this.containers.push(containers[i]);
                        this.stats[containers[i].id] = newContainerStat();
                    }
                }
            }
            // todo: support other filters
        }

        return Promise.resolve();
    })
    .catch((err) => {
        return Promise.reject(err);
    });
}

function newContainerStat() {
    return {
        mem_usage:   [],
        mem_percent: [],
        cpu_percent: [],
        netIO_rx:    [],
        netIO_tx:    [],
        blockIO_rx:  [],
        blockIO_wx:  []
    };
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}<commit_msg>move container finder from start() to constructor<commit_after>/**
* Copyright 2017 HUAWEI. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* @file, definition of the MonitorDocker class
*        which is used to watch the resource consumption of specific local docker containers
*/

'use strict'

// todo: now we record the performance information in local variable, should use db later
var MonitorDocker = class {
    constructor(filter, interval) {
        this.filter       = filter;
        this.interval     = interval*1000; // ms
        this.si           = require('systeminformation');   // TODO: does si support remote container? Maybe use original docker remote api?
        this.containers   = [];
        this.isReading    = false;
        this.intervalObj  = null;
        this.stats = {'time': []};
        this.hasContainters = findContainers.call(this);
        /* this.stats : record statistics of each container
            {
                'time' : [] // time slot
                'container_id" : {              // refer to https://www.npmjs.com/package/systeminformatioin
                    'mem_usage'   : [],
                    'mem_percent' : [],
                    'cpu_percent' : [],
                    'netIO_rx'    : [],
                    'netIO_tx'    : [],
                    'blockIO_rx'  : [],
                    'blockIO_wx'  : []
                }
                next container
                .....
            }
        */

    }

    /**
    * start monitoring
    * @isRestart {Boolean}, indicate whether it is restarting the monitor
    * @return {Promise}
    */
    start() {
        return this.hasContainters.then( () => {
            var self = this;
            function readContainerStats() {
                if(self.isReading) {
                    return;
                }
                self.isReading = true;
                var statPromises = [];
                for(let i = 0 ;i < self.containers.length ; i++){
                    statPromises.push(self.si.dockerContainerStats(self.containers[i].id));
                }
                Promise.all(statPromises).then((results) => {
                    self.stats.time.push(process.uptime());
                    for(let key in results) {
                        let stat = results[key];
                        self.stats[stat.id].mem_usage.push(stat.mem_usage);
                        self.stats[stat.id].mem_percent.push(stat.mem_percent);
                        self.stats[stat.id].cpu_percent.push(stat.cpu_percent);
                        self.stats[stat.id].netIO_rx.push(stat.netIO.rx);
                        self.stats[stat.id].netIO_tx.push(stat.netIO.tx);
                        self.stats[stat.id].blockIO_rx.push(stat.blockIO.r);
                        self.stats[stat.id].blockIO_wx.push(stat.blockIO.w);
                    }
                    self.isReading = false;
                })
                .catch((err) => {
                    self.isReading = false;
                });
            };

            readContainerStats();   // read stats  immediately
            this.intervalObj = setInterval(readContainerStats, this.interval);
            return Promise.resolve();
        })
        .catch((err) => {
            return Promise.reject(err);
        });
    }

    restart() {
        clearInterval(this.intervalObj);
        for(let key in this.stats) {
            if(key === 'time') {
                this.stats[key] = [];
            }
            else {
                for(let v in this.stats[key]) {
                    this.stats[key][v] = [];
                }
            }
        }

        return this.start();
    }

    stop() {
        clearInterval(this.intervalObj);
        this.containers = [];
        this.stats      = {'time': []};

        return sleep(100);
    }

    /**
    * Get peer list and predefined readable information
    * @return {Array}, {key, info={...}}
    */
    getBriefPeerInfo() {
        var info = [];
        for(let i in this.containers) {
            let c = this.containers[i];
            if(c.hasOwnProperty('id')) {
                info.push({
                    'key'  : c.id,
                    'info' : {
                        'ID' : c.id,
                        'NAME' : c.name
                    }
                });
            }
        }
        return info;
    }

    /**
    * Get peer's history of memory usage, byte
    * @key {string}, peer's key
    * @return {Array}
    */
    getMemHistory(key) {
        return this.stats[key].mem_usage;
    }

    /**
    * Get peer's history of cpu percent, %
    * @key {string}, peer's key
    * @return {Array}
    */
    getCpuHistory(key) {
        return this.stats[key].cpu_percent;
    }

    /**
    * Get peer's history of network io usage, byte
    * @key {string}, peer's key
    * @return {Array}, [{in: inflow traffic, out: outflow traffic}]
    */
    getNetworkHistory(key) {
        return {'in': this.stats[key].netIO_rx, 'out':this.stats[key].netIO_tx};
    }
};
module.exports = MonitorDocker;

/**
* Find local containers according to searching filters
*/
function findContainers() {
    var filterName = this.filter['name'];
    var all = false;
    if(typeof filterName !== 'undefined' && filterName[0] === 'all') {
        all = true;
    }

    return this.si.dockerContainers('active').then((containers) => {
        var size = containers.length;
        if(size === 0) {
            return Promise.reject(new Error('systeminformation: could not find active container'));
        }

        if(all) {
            for(let i = 0 ; i < size ; i++){
                this.containers.push(containers[i]);
                this.stats[containers[i].id] = newContainerStat();
            }
        }
        else {
            // get containers by name
            if(typeof filterName !== 'undefined') {
                for(let i = 0 ; i < size ; i++){
                    if(filterName.indexOf(containers[i].name) >= 0) {
                        this.containers.push(containers[i]);
                        this.stats[containers[i].id] = newContainerStat();
                    }
                }
            }
            // todo: support other filters
        }

        return Promise.resolve();
    })
    .catch((err) => {
        return Promise.reject(err);
    });
}

function newContainerStat() {
    return {
        mem_usage:   [],
        mem_percent: [],
        cpu_percent: [],
        netIO_rx:    [],
        netIO_tx:    [],
        blockIO_rx:  [],
        blockIO_wx:  []
    };
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}<|endoftext|>


<commit_before>const ytdl = require('ytdl-core');

function msToTime(s) {
  let ms = s % 1000;
  s = (s - ms) / 1000;
  let secs = s % 60;
  s = (s - secs) / 60;
  let mins = s % 60;
  s = (s - mins) / 60;
  let hrs = s % 24;
  let days = (s - hrs) / 24;

  let time_str = `${secs} seconds.`;
  if (mins) {
      time_str = `${mins} minutes and ` + time_str;
  }
  if (hrs) {
      time_str = `${hrs} hours ` + time_str;
  }
  if (days) {
      time_str = `${days} days ` + time_str;
  }

  return time_str;
}

let command_data = {
    "uptime": {
        doc: "How much time I have been online for",
        process: (client, message) => {
            return client.createMessage(message.channel_id, `I have been ruling this server for ${msToTime(client.uptime())}`);
        }
    },
    "commands": {
        doc: "List all available commands",
        process: (client, message) => {
            let commands_str = "";
            for (let c in module.exports) {
                let command = module.exports[c];
                if (!command.private) {
                    commands_str += `${command.usage}\n`;
                }
            }
            return client.createMessage(message.channel_id, commands_str);
        }
    },
    "music": {
        args: [
            { type: "subcommand", oneof: [
                { name: "play", args: [ { name: "Youtube link" } ] },
                { name: "stop" },
                { name: "pause" }
            ]},
        ],
        doc: "Music controls",
        process: (client, message, args) => {
            return new Promise((resolve, reject) => {
                switch(args[0]) {
                    case "play":
                        ytdl.getInfo(args[1], (err, info) => {
                            if (err) {
                                console.error("Error in !music:", err);
                            }
                            // `info` is a list of all possible formats this video exists in
                            let audio_formats = info.formats.filter(i => i.type && i.type.indexOf('audio/') > -1);
                            let selection = audio_formats.reduce((pv, cv) => pv.audioBitrate > cv.audioBitrate ? pv : cv);
                            client.voice_connection.play(selection.url);
                        });
                        break;
                    case "stop":
                        client.voice_connection.stop();
                        break;
                    case "pause":
                        break;
                }
                resolve();
            });
        }
    },
    "hots": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on icy-veins.com and heroesfire.com",
        process: (client, message, args) => {
            return new Promise((resolve, reject) => {
                if (args[0].toLowerCase() === "murky") {
                    client.createMessage(message.channel_id, "Fuck Murky", true);
                    return;
                }
                let m1 = client.createMessage(message.channel_id, `http://www.icy-veins.com/heroes/${args.join('-')}-build-guide \n`);
                let m2 = client.createMessage(message.channel_id, `http://www.heroesfire.com/hots/wiki/heroes/${args.join('-')}`);
                return Promise.all([m1, m2]);
            });
        }
    },
    "heroesfire": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on heroesfire.com",
        process: (client, message, args) => {
            return client.createMessage(message.channel_id, `http://www.heroesfire.com/hots/wiki/heroes/${args.join('-')}`);
        }
    },
    "icyveins": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on icy-veins.com",
        process: (client, message, args) => {
            return client.createMessage(message.channel_id, `http://www.icy-veins.com/heroes/${args.join('-')}-build-guide`);
        }
    },
    "test": {
        private: true,
        process: (client, message) => {
            return client.createMessage(message.channel_id);
        }
    }
};

function argsToString(args) {
    if (!args)
        return "";

    let arg_str = "";
    args.forEach(arg => {
        if (arg.type === "subcommand") {
            arg_str += `<${arg.oneof.reduce((pv, cv) => pv + cv.name + "|", "").slice(0,-1)}> `;
            arg.oneof.forEach(a => {
                if (a.args) {
                    arg_str += argsToString(a.args);
                }
            });
        }
        else {
            arg_str += `<${arg.name}>${arg.optional ? '?' : ""}`;
        }
    });

    return arg_str;
}

class Command {
    constructor(name, data) {
        this.name = name;
        this.args = data.args || [];
        this.doc = data.doc || "";
        this.private = data.private || false;
        this.process = data.process;
    }

    get usage() {
        return `**!${this.name}** ${argsToString(this.args)}\n  _${this.doc}_`;
    }
}

let exprt = {};

for (var c in command_data) {
  if (command_data.hasOwnProperty(c)) {
    let command = new Command(c, command_data[c]);

    exprt[c] = command;
  }
}

module.exports = exprt;
<commit_msg>Remove pause from music commands<commit_after>const ytdl = require('ytdl-core');

function msToTime(s) {
  let ms = s % 1000;
  s = (s - ms) / 1000;
  let secs = s % 60;
  s = (s - secs) / 60;
  let mins = s % 60;
  s = (s - mins) / 60;
  let hrs = s % 24;
  let days = (s - hrs) / 24;

  let time_str = `${secs} seconds.`;
  if (mins) {
      time_str = `${mins} minutes and ` + time_str;
  }
  if (hrs) {
      time_str = `${hrs} hours ` + time_str;
  }
  if (days) {
      time_str = `${days} days ` + time_str;
  }

  return time_str;
}

let command_data = {
    "uptime": {
        doc: "How much time I have been online for",
        process: (client, message) => {
            return client.createMessage(message.channel_id, `I have been ruling this server for ${msToTime(client.uptime())}`);
        }
    },
    "commands": {
        doc: "List all available commands",
        process: (client, message) => {
            let commands_str = "";
            for (let c in module.exports) {
                let command = module.exports[c];
                if (!command.private) {
                    commands_str += `${command.usage}\n`;
                }
            }
            return client.createMessage(message.channel_id, commands_str);
        }
    },
    "music": {
        args: [
            { type: "subcommand", oneof: [
                { name: "play", args: [ { name: "Youtube link" } ] },
                { name: "stop" },
            ]},
        ],
        doc: "Music controls",
        process: (client, message, args) => {
            return new Promise((resolve, reject) => {
                switch(args[0]) {
                    case "play":
                        ytdl.getInfo(args[1], (err, info) => {
                            if (err) {
                                console.error("Error in !music:", err);
                            }
                            // `info` is a list of all possible formats this video exists in
                            let audio_formats = info.formats.filter(i => i.type && i.type.indexOf('audio/') > -1);
                            let selection = audio_formats.reduce((pv, cv) => pv.audioBitrate > cv.audioBitrate ? pv : cv);
                            client.voice_connection.play(selection.url);
                        });
                        break;
                    case "stop":
                        client.voice_connection.stop();
                        break;
                    case "pause":
                        break;
                }
                resolve();
            });
        }
    },
    "hots": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on icy-veins.com and heroesfire.com",
        process: (client, message, args) => {
            return new Promise((resolve, reject) => {
                if (args[0].toLowerCase() === "murky") {
                    client.createMessage(message.channel_id, "Fuck Murky", true);
                    return;
                }
                let m1 = client.createMessage(message.channel_id, `http://www.icy-veins.com/heroes/${args.join('-')}-build-guide \n`);
                let m2 = client.createMessage(message.channel_id, `http://www.heroesfire.com/hots/wiki/heroes/${args.join('-')}`);
                return Promise.all([m1, m2]);
            });
        }
    },
    "heroesfire": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on heroesfire.com",
        process: (client, message, args) => {
            return client.createMessage(message.channel_id, `http://www.heroesfire.com/hots/wiki/heroes/${args.join('-')}`);
        }
    },
    "icyveins": {
        args: [
            { name: "hero" }
        ],
        doc: "View HotS build for <hero> on icy-veins.com",
        process: (client, message, args) => {
            return client.createMessage(message.channel_id, `http://www.icy-veins.com/heroes/${args.join('-')}-build-guide`);
        }
    },
    "test": {
        private: true,
        process: (client, message) => {
            return client.createMessage(message.channel_id);
        }
    }
};

function argsToString(args) {
    if (!args)
        return "";

    let arg_str = "";
    args.forEach(arg => {
        if (arg.type === "subcommand") {
            arg_str += `<${arg.oneof.reduce((pv, cv) => pv + cv.name + "|", "").slice(0,-1)}> `;
            arg.oneof.forEach(a => {
                if (a.args) {
                    arg_str += argsToString(a.args);
                }
            });
        }
        else {
            arg_str += `<${arg.name}>${arg.optional ? '?' : ""}`;
        }
    });

    return arg_str;
}

class Command {
    constructor(name, data) {
        this.name = name;
        this.args = data.args || [];
        this.doc = data.doc || "";
        this.private = data.private || false;
        this.process = data.process;
    }

    get usage() {
        return `**!${this.name}** ${argsToString(this.args)}\n  _${this.doc}_`;
    }
}

let exprt = {};

for (var c in command_data) {
  if (command_data.hasOwnProperty(c)) {
    let command = new Command(c, command_data[c]);

    exprt[c] = command;
  }
}

module.exports = exprt;
<|endoftext|>


<commit_before>var program = require("commander");
var child = require("child_process");

var CONFIG_PATH = process.cwd() + "/config.js";

program
	.command("config")
	.description("Edit config: '" + CONFIG_PATH + "'")
	.action(function() {
		child.spawn(
			"sudo",
			["vi", CONFIG_PATH],
			{stdio: "inherit"}
		);
	});
<commit_msg>Change config command to edit config.js in the Shout home directory<commit_after>var fs = require("fs");
var path = require("path");
var program = require("commander");
var mkdirp = require("mkdirp");
var child = require("child_process");
var Helper = require("../helper");

var CONFIG_PATH = process.env.SHOUT_CONFIG;
if(!CONFIG_PATH) {
	CONFIG_PATH = Helper.resolveHomePath("config.js");
}
if(!fs.exists(CONFIG_PATH)) {
	mkdirp.sync(Helper.getHomeDirectory());
	var configFile = fs.readFileSync(path.resolve(__dirname, "..", "..", "config.js"));
	fs.writeFileSync(CONFIG_PATH, configFile);
}

program
	.command("config")
	.description("Edit config: '" + CONFIG_PATH + "'")
	.action(function() {
		child.spawn(
			"sudo",
			["vi", CONFIG_PATH],
			{stdio: "inherit"}
		);
	});
<|endoftext|>