<commit_before>/**
 * # monetize.js
 *
 * MonetizeJS official client-side library.
 *
 * #### Import from CDN
 *
 * ```html
 * <script src="//cdn.monetizejs.com/api/js/latest/monetize.min.js"></script>
 * ```
 *
 * #### Or, install via bower
 *
 * ```bash
 * bower install monetizejs
 * ```
 *
 */
(function() {

	var onReady = (function() {
		// Credit: https://github.com/ded/domready
		var queue = [],
			loaded = /^loaded|c/.test(document.readyState);

		var fn, domContentLoaded = 'DOMContentLoaded';
		document.addEventListener(domContentLoaded, fn = function() {
			document.removeEventListener(domContentLoaded, fn, false);
			loaded = 1;
			while((fn = queue.shift())) {
				fn();
			}
		}, false);

		return function(fn) {
			loaded ? fn() : queue.push(fn);
		};
	})();

	var monetizejsUrl = 'https://monetizejs.com',
		postMsgIframeElt,
		jsonpScriptElt,
		popupWidth = 1000,
		popupHeight = 700,
		timeout = 30000, // 30 sec
		tokenRefreshMargin = 300000, // 5 min
		iframeCb,
		popupCb,
		jsonpCb,
		lastMsg,
		timeoutError = 'Request timeout',
		iframeTimeoutId,
		scriptTimeoutId,
		noResponseError = 'Please check your JS console';

	window.addEventListener('message', function(e) {
		if(e.origin == monetizejsUrl) {
			lastMsg = e.data;
			if(lastMsg.expiresIn) {
				lastMsg.refreshDate = Date.now() + lastMsg.expiresIn - tokenRefreshMargin;
			}
			if(lastMsg.popup) {
				popupCb && popupCb(lastMsg);
			}
			else {
				clearTimeout(iframeTimeoutId);
				iframeCb && iframeCb(lastMsg);
			}
		}
	});

	function getPostMsgIframeElt() {
		if(postMsgIframeElt) {
			return postMsgIframeElt;
		}
		var iframeStyle = {
			width: '1px',
			height: '1px',
			position: 'absolute',
			top: '-100px'
		};
		postMsgIframeElt = document.createElement("iframe");
		postMsgIframeElt.setAttribute("style", Object.keys(iframeStyle).map(function(key) {
			return key + ':' + iframeStyle[key];
		}).join(';'));
		document.body.appendChild(postMsgIframeElt);
		postMsgIframeElt.onerror = postMsgIframeElt.onload = function() {
			setTimeout(function() {
				iframeCb && iframeCb({
					error: noResponseError
				});
			}, 10);
		};
		return postMsgIframeElt;
	}

	function formatUrl(path, qs) {
		var url = monetizejsUrl + path;
		qs.q = Date.now(); // Prevent caching
		qs = qs && Object.keys(qs).map(function(key) {
			return key + '=' + encodeURIComponent(qs[key]);
		}).join('&');
		return qs ? url + '?' + qs : url;
	}

	function postMsgIframe(options, fn) {
		iframeCb = function(msg) {
			iframeCb = undefined;
			fn(msg);
		};
		var qs = {
			immediate: true,
			response_type: 'token',
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		onReady(function() {
			getPostMsgIframeElt().src = formatUrl('/authorize', qs);
			clearTimeout(iframeTimeoutId);
			iframeTimeoutId = setTimeout(function() {
				iframeCb && iframeCb({
					error: timeoutError
				});
			}, timeout);
		});
	}

	function setOptions(qs, options) {
		if(options.pricingOptions && options.pricingOptions.length) {
			qs.pricing_options = options.pricingOptions.join ? options.pricingOptions.join(',') : options.pricingOptions;
		}
		if(options.summary) {
			qs.summary = true;
		}
	}

	function popupWindow(options, fn) {
		popupCb = function(msg) {
			popupCb = undefined;
			fn(msg);
		};
		var qs = {
			popup: true,
			response_type: 'token',
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		setOptions(qs, options);
		var windowFeatures = {
			toolbar: 'no',
			location: 'no',
			directories: 'no',
			status: 'no',
			menubar: 'no',
			scrollbars: 'no',
			resizable: 'no',
			copyhistory: 'no',
			width: popupWidth,
			height: popupHeight,
			left: (screen.width - popupWidth) / 2,
			top: (screen.height - popupHeight) / 2
		};
		window.open(formatUrl('/authorize', qs), undefined,
			Object.keys(windowFeatures).map(function(key) {
				return key + '=' + windowFeatures[key];
			}).join(',')
		);
	}

	window._monetizeJsonpCallback = function jsonpCallback(res) {
		// Check that callback is not proxied
		if(window._monetizeJsonpCallback !== jsonpCallback) {
			return jsonpCb && jsonpCb({
				error: 'Callback replaced!'
			});
		}
		clearTimeout(scriptTimeoutId);
		jsonpCb && jsonpCb({
			payments: res
		});
	};

	function getJsonpScriptElt() {
		if(jsonpScriptElt) {
			document.body.removeChild(jsonpScriptElt);
		}
		jsonpScriptElt = document.createElement("script");
		jsonpScriptElt.onerror = jsonpScriptElt.onload = function() {
			setTimeout(function() {
				jsonpCb && jsonpCb({
					error: noResponseError
				});
			}, 10);
		};

		document.body.appendChild(jsonpScriptElt);
		return jsonpScriptElt;
	}

	function getPaymentsJsonp(fn) {
		jsonpCb = function(msg) {
			jsonpCb = undefined;
			fn(msg);
		};
		var qs = {
			access_token: lastMsg.token,
			callback: '_monetizeJsonpCallback'
		};
		onReady(function() {
			getJsonpScriptElt().src = formatUrl('/api/payments', qs);
			clearTimeout(scriptTimeoutId);
			scriptTimeoutId = setTimeout(function() {
				jsonpCb && jsonpCb({
					error: timeoutError
				});
			}, timeout);
		});
	}

	function redirect(options) {
		var qs = {
			redirect: true,
			response_type: 'token',
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		setOptions(qs, options);
		window.location = formatUrl('/authorize', qs);
	}

	function extend(obj, source) {
		for(var prop in source) {
			obj[prop] = source[prop];
		}
	}

	var defaultOptions = {
		redirectURL: window.location.href
	};

	/**
	 * Create and initialize a MonetizeJS object.
	 *
	 * @example
	 *
	 * var monetize = MonetizeJS(options);
	 *
	 * @param {Object} options optional set of top-level options.
	 *
	 */
	function MonetizeJS(options) {
		var initOptions = {};
		extend(initOptions, defaultOptions);
		extend(initOptions, options || {});

		function paramSanitizer(fn) {
			return function(options, cb) {
				if(typeof options === 'function') {
					cb = options;
					options = {};
				}
				var extendedOptions = {};
				extend(extendedOptions, initOptions);
				extend(extendedOptions, options || {});
				fn(extendedOptions, cb);
			};
		}

		var monetize = {};

		/**
		 * Attempt to get an access token without a redirection.
		 *
		 * @example
		 *
		 * monetize.getTokenImmediate(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **applicationID**: *String*, the application ID.
		 *
		 * @param {Function} cb a callback to be called with the following parameters:
		 *
		 *      - **err**: *Error*, in case of failure.
		 *
		 *      - **token**: *String*, the access token.
		 */
		monetize.getTokenImmediate = paramSanitizer(function(options, cb) {
			if(lastMsg && lastMsg.token && lastMsg.refreshDate > Date.now()) {
				return cb(undefined, lastMsg.token);
			}
			postMsgIframe(options, function(msg) {
				cb(msg.error, msg.token);
			});
		});

		/**
		 * Attempt to get user's payment object without a redirection.
		 *
		 * @example
		 *
		 * monetize.getPaymentsImmediate(options, function(err, payments) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(payments.chargeOption);
		 *         console.log(payments.subscriptionOption);
		 *     }
		 * });
		 *
		 * @param {Object} options same as `getTokenImmediate`
		 *
		 * @param {Function} cb a callback to be called with the following parameters:
		 *
		 *      - **err**: *Error*, in case of failure
		 *
		 *      - **payments**: *Object*, the payment object.
		 *
		 *      > This object contains the fields `chargeOption` and `subscriptionOption` that you have to validate.
		 */
		monetize.getPaymentsImmediate = paramSanitizer(function(options, cb) {
			if(lastMsg && lastMsg.token && lastMsg.refreshDate > Date.now()) {
				return getPaymentsJsonp(function(msg) {
					cb(msg.error, msg.payments);
				});
			}
			postMsgIframe(options, function(msg) {
				cb(msg.error, msg.payments);
			});
		});

		/**
		 * Perform a redirection to the MonetizeJS platform for login and/or payment and get an access token as a result.
		 *
		 * @example
		 *
		 * monetize.getTokenInteractive(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **applicationID**: *String*, the application ID.
		 *
		 *      - **redirectURL**: *String*, in case of full page redirection, MonetizeJS will redirect the user to that URL.
		 *
		 *      > If redirect URL isn't provided, user will be redirected to the current page.
		 *
		 *      - **summary**: *Boolean*, forces the whole list of pricing options to be shown to the user.
		 *
		 *      > This option lets users review their current charge/subscription and manage their payments for your app.
		 *
		 *      - **pricingOptions**: *Array*, a list of pricing option aliases.
		 *
		 *      > Unless "summary" is enabled, the user interface will be limited to the specified pricing options.
		 *      If no pricing option is specified or user already has one of the specified pricing options, only login will be performed.
		 *
		 * @param {Function} cb same as `getTokenImmediate`.
		 *
		 *      > If the callback is provided, the redirection will be performed in a popup window.
		 *      > If no callback is provided, a full page redirection will be performed and you will have to call `getTokenImmediate` once redirected back to your page.
		 */
		monetize.getTokenInteractive = paramSanitizer(function(options, cb) {
			if(!cb) {
				return redirect(options);
			}
			popupWindow(options, function(msg) {
				cb(msg.error, msg.token);
			});
		});

		/**
		 * Perform a redirection to the MonetizeJS platform for login and/or payment and get user's payment object as a result.
		 *
		 * @example
		 *
		 * monetize.getTokenInteractive(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options same as `getTokenInteractive`.
		 *
		 * @param {Function} cb same as `getPaymentsImmediate`.
		 *
		 *      > If the callback is provided, the redirection will be performed in a popup window.
		 *      > If no callback is provided, a full page redirection will be performed and you will have to call `getPaymentsImmediate` once redirected back to your page.
		 */
		monetize.getPaymentsInteractive = paramSanitizer(function(options, cb) {
			if(!cb) {
				return redirect(options);
			}
			popupWindow(options, function(msg) {
				cb(msg.error, msg.payments);
			});
		});

		/**
		 * Shortcut for `getTokenImmediate` and `getTokenInteractive`.
		 *
		 * @example
		 *
		 * monetize.getToken({
		 *     immediate: true
		 * }, cb);
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **immediate**: *Boolean*, whether to call `getTokenImmediate` or `getTokenInteractive`.
		 *
		 * @param {Function} cb same as `getTokenImmediate` or `getTokenInteractive`.
		 *
		 */
		monetize.getToken = paramSanitizer(function(options, cb) {
			return (options.immeditate ? monetize.getTokenImmediate : monetize.getTokenInteractive)(options, cb);
		});

		/**
		 * Shortcut for `getPaymentsImmediate` and `getPaymentsInteractive`.
		 *
		 * @example
		 *
		 * monetize.getPayments({
		 *     immediate: true
		 * }, cb);
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **immediate**: *Boolean*, whether to call `getPaymentsImmediate` or `getPaymentsInteractive`.
		 *
		 * @param {Function} cb same as `getPaymentsImmediate` or `getPaymentsInteractive`.
		 *
		 */
		monetize.getPayments = paramSanitizer(function(options, cb) {
			return (options.immeditate ? monetize.getPaymentsImmediate : monetize.getPaymentsInteractive)(options, cb);
		});

		return monetize;
	}

	window.MonetizeJS = MonetizeJS;

	if(typeof define === "function" && define.amd) {
		define("monetizejs", [], function() {
			return MonetizeJS;
		});
	}
})();<commit_msg>Changed how to perform full page redirect<commit_after>/**
 * # monetize.js
 *
 * MonetizeJS official client-side library.
 *
 * #### Import from CDN
 *
 * ```html
 * <script src="//cdn.monetizejs.com/api/js/latest/monetize.min.js"></script>
 * ```
 *
 * #### Or, install via bower
 *
 * ```bash
 * bower install monetizejs
 * ```
 *
 */
(function() {

	var onReady = (function() {
		// Credit: https://github.com/ded/domready
		var queue = [],
			loaded = /^loaded|c/.test(document.readyState);

		var fn, domContentLoaded = 'DOMContentLoaded';
		document.addEventListener(domContentLoaded, fn = function() {
			document.removeEventListener(domContentLoaded, fn, false);
			loaded = 1;
			while((fn = queue.shift())) {
				fn();
			}
		}, false);

		return function(fn) {
			loaded ? fn() : queue.push(fn);
		};
	})();

	var monetizejsUrl = 'https://monetizejs.com',
		postMsgIframeElt,
		jsonpScriptElt,
		popupWidth = 1000,
		popupHeight = 700,
		timeout = 30000, // 30 sec
		tokenRefreshMargin = 300000, // 5 min
		iframeCb,
		popupCb,
		jsonpCb,
		lastMsg,
		timeoutError = 'Request timeout',
		iframeTimeoutId,
		scriptTimeoutId,
		noResponseError = 'Please check your JS console';

	window.addEventListener('message', function(e) {
		if(e.origin == monetizejsUrl) {
			lastMsg = e.data;
			if(lastMsg.expiresIn) {
				lastMsg.refreshDate = Date.now() + lastMsg.expiresIn - tokenRefreshMargin;
			}
			if(lastMsg.popup) {
				popupCb && popupCb(lastMsg);
			}
			else {
				clearTimeout(iframeTimeoutId);
				iframeCb && iframeCb(lastMsg);
			}
		}
	});

	function getPostMsgIframeElt() {
		if(postMsgIframeElt) {
			return postMsgIframeElt;
		}
		var iframeStyle = {
			width: '1px',
			height: '1px',
			position: 'absolute',
			top: '-100px'
		};
		postMsgIframeElt = document.createElement("iframe");
		postMsgIframeElt.setAttribute("style", Object.keys(iframeStyle).map(function(key) {
			return key + ':' + iframeStyle[key];
		}).join(';'));
		document.body.appendChild(postMsgIframeElt);
		postMsgIframeElt.onerror = postMsgIframeElt.onload = function() {
			setTimeout(function() {
				iframeCb && iframeCb({
					error: noResponseError
				});
			}, 10);
		};
		return postMsgIframeElt;
	}

	function formatUrl(path, qs) {
		var url = monetizejsUrl + path;
		qs.q = Date.now(); // Prevent caching
		qs = qs && Object.keys(qs).map(function(key) {
			return key + '=' + encodeURIComponent(qs[key]);
		}).join('&');
		return qs ? url + '?' + qs : url;
	}

	function postMsgIframe(options, fn) {
		iframeCb = function(msg) {
			iframeCb = undefined;
			fn(msg);
		};
		var qs = {
			immediate: true,
			response_type: 'token',
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		onReady(function() {
			getPostMsgIframeElt().src = formatUrl('/authorize', qs);
			clearTimeout(iframeTimeoutId);
			iframeTimeoutId = setTimeout(function() {
				iframeCb && iframeCb({
					error: timeoutError
				});
			}, timeout);
		});
	}

	function setOptions(qs, options) {
		if(options.pricingOptions && options.pricingOptions.length) {
			qs.pricing_options = options.pricingOptions.join ? options.pricingOptions.join(',') : options.pricingOptions;
		}
		if(options.summary) {
			qs.summary = true;
		}
	}

	function popupWindow(options, fn) {
		popupCb = function(msg) {
			popupCb = undefined;
			fn(msg);
		};
		var qs = {
			popup: true,
			response_type: 'token',
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		setOptions(qs, options);
		var windowFeatures = {
			toolbar: 'no',
			location: 'no',
			directories: 'no',
			status: 'no',
			menubar: 'no',
			scrollbars: 'no',
			resizable: 'no',
			copyhistory: 'no',
			width: popupWidth,
			height: popupHeight,
			left: (screen.width - popupWidth) / 2,
			top: (screen.height - popupHeight) / 2
		};
		window.open(formatUrl('/authorize', qs), undefined,
			Object.keys(windowFeatures).map(function(key) {
				return key + '=' + windowFeatures[key];
			}).join(',')
		);
	}

	window._monetizeJsonpCallback = function jsonpCallback(res) {
		// Check that callback is not proxied
		if(window._monetizeJsonpCallback !== jsonpCallback) {
			return jsonpCb && jsonpCb({
				error: 'Callback replaced!'
			});
		}
		clearTimeout(scriptTimeoutId);
		jsonpCb && jsonpCb({
			payments: res
		});
	};

	function getJsonpScriptElt() {
		if(jsonpScriptElt) {
			document.body.removeChild(jsonpScriptElt);
		}
		jsonpScriptElt = document.createElement("script");
		jsonpScriptElt.onerror = jsonpScriptElt.onload = function() {
			setTimeout(function() {
				jsonpCb && jsonpCb({
					error: noResponseError
				});
			}, 10);
		};

		document.body.appendChild(jsonpScriptElt);
		return jsonpScriptElt;
	}

	function getPaymentsJsonp(fn) {
		jsonpCb = function(msg) {
			jsonpCb = undefined;
			fn(msg);
		};
		var qs = {
			access_token: lastMsg.token,
			callback: '_monetizeJsonpCallback'
		};
		onReady(function() {
			getJsonpScriptElt().src = formatUrl('/api/payments', qs);
			clearTimeout(scriptTimeoutId);
			scriptTimeoutId = setTimeout(function() {
				jsonpCb && jsonpCb({
					error: timeoutError
				});
			}, timeout);
		});
	}

	function redirect(options) {
		var qs = {
			client_id: options.applicationID,
			redirect_uri: options.redirectURL
		};
		setOptions(qs, options);
		window.location = formatUrl('/authorize', qs);
	}

	function extend(obj, source) {
		for(var prop in source) {
			obj[prop] = source[prop];
		}
	}

	var defaultOptions = {
		redirectURL: window.location.href
	};

	/**
	 * Create and initialize a MonetizeJS object.
	 *
	 * @example
	 *
	 * var monetize = MonetizeJS(options);
	 *
	 * @param {Object} options optional set of top-level options.
	 *
	 */
	function MonetizeJS(options) {
		var initOptions = {};
		extend(initOptions, defaultOptions);
		extend(initOptions, options || {});

		function paramSanitizer(fn) {
			return function(options, cb) {
				if(typeof options === 'function') {
					cb = options;
					options = {};
				}
				var extendedOptions = {};
				extend(extendedOptions, initOptions);
				extend(extendedOptions, options || {});
				fn(extendedOptions, cb);
			};
		}

		var monetize = {};

		/**
		 * Attempt to get an access token without a redirection.
		 *
		 * @example
		 *
		 * monetize.getTokenImmediate(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **applicationID**: *String*, the application ID.
		 *
		 * @param {Function} cb a callback to be called with the following parameters:
		 *
		 *      - **err**: *Error*, in case of failure.
		 *
		 *      - **token**: *String*, the access token.
		 */
		monetize.getTokenImmediate = paramSanitizer(function(options, cb) {
			if(lastMsg && lastMsg.token && lastMsg.refreshDate > Date.now()) {
				return cb(undefined, lastMsg.token);
			}
			postMsgIframe(options, function(msg) {
				cb(msg.error, msg.token);
			});
		});

		/**
		 * Attempt to get user's payment object without a redirection.
		 *
		 * @example
		 *
		 * monetize.getPaymentsImmediate(options, function(err, payments) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(payments.chargeOption);
		 *         console.log(payments.subscriptionOption);
		 *     }
		 * });
		 *
		 * @param {Object} options same as `getTokenImmediate`
		 *
		 * @param {Function} cb a callback to be called with the following parameters:
		 *
		 *      - **err**: *Error*, in case of failure
		 *
		 *      - **payments**: *Object*, the payment object.
		 *
		 *      > This object contains the fields `chargeOption` and `subscriptionOption` that you have to validate.
		 */
		monetize.getPaymentsImmediate = paramSanitizer(function(options, cb) {
			if(lastMsg && lastMsg.token && lastMsg.refreshDate > Date.now()) {
				return getPaymentsJsonp(function(msg) {
					cb(msg.error, msg.payments);
				});
			}
			postMsgIframe(options, function(msg) {
				cb(msg.error, msg.payments);
			});
		});

		/**
		 * Perform a redirection to the MonetizeJS platform for login and/or payment and get an access token as a result.
		 *
		 * @example
		 *
		 * monetize.getTokenInteractive(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **applicationID**: *String*, the application ID.
		 *
		 *      - **redirectURL**: *String*, in case of full page redirection, MonetizeJS will redirect the user to that URL.
		 *
		 *      > If redirect URL isn't provided, user will be redirected to the current page.
		 *
		 *      - **summary**: *Boolean*, forces the whole list of pricing options to be shown to the user.
		 *
		 *      > This option lets users review their current charge/subscription and manage their payments for your app.
		 *
		 *      - **pricingOptions**: *Array*, a list of pricing option aliases.
		 *
		 *      > Unless "summary" is enabled, the user interface will be limited to the specified pricing options.
		 *      If no pricing option is specified or user already has one of the specified pricing options, only login will be performed.
		 *
		 * @param {Function} cb same as `getTokenImmediate`.
		 *
		 *      > If the callback is provided, the redirection will be performed in a popup window.
		 *      > If no callback is provided, a full page redirection will be performed and you will have to call `getTokenImmediate` once redirected back to your page.
		 */
		monetize.getTokenInteractive = paramSanitizer(function(options, cb) {
			if(!cb) {
				return redirect(options);
			}
			popupWindow(options, function(msg) {
				cb(msg.error, msg.token);
			});
		});

		/**
		 * Perform a redirection to the MonetizeJS platform for login and/or payment and get user's payment object as a result.
		 *
		 * @example
		 *
		 * monetize.getTokenInteractive(options, function(err, token) {
         *     if(err) {
		 *         console.error(err);
		 *     }
		 *     else if(token) {
		 *         console.log(token);
		 *     }
		 * });
		 *
		 * @param {Object} options same as `getTokenInteractive`.
		 *
		 * @param {Function} cb same as `getPaymentsImmediate`.
		 *
		 *      > If the callback is provided, the redirection will be performed in a popup window.
		 *      > If no callback is provided, a full page redirection will be performed and you will have to call `getPaymentsImmediate` once redirected back to your page.
		 */
		monetize.getPaymentsInteractive = paramSanitizer(function(options, cb) {
			if(!cb) {
				return redirect(options);
			}
			popupWindow(options, function(msg) {
				cb(msg.error, msg.payments);
			});
		});

		/**
		 * Shortcut for `getTokenImmediate` and `getTokenInteractive`.
		 *
		 * @example
		 *
		 * monetize.getToken({
		 *     immediate: true
		 * }, cb);
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **immediate**: *Boolean*, whether to call `getTokenImmediate` or `getTokenInteractive`.
		 *
		 * @param {Function} cb same as `getTokenImmediate` or `getTokenInteractive`.
		 *
		 */
		monetize.getToken = paramSanitizer(function(options, cb) {
			return (options.immeditate ? monetize.getTokenImmediate : monetize.getTokenInteractive)(options, cb);
		});

		/**
		 * Shortcut for `getPaymentsImmediate` and `getPaymentsInteractive`.
		 *
		 * @example
		 *
		 * monetize.getPayments({
		 *     immediate: true
		 * }, cb);
		 *
		 * @param {Object} options optional set of options overriding the init options:
		 *
		 *      - **immediate**: *Boolean*, whether to call `getPaymentsImmediate` or `getPaymentsInteractive`.
		 *
		 * @param {Function} cb same as `getPaymentsImmediate` or `getPaymentsInteractive`.
		 *
		 */
		monetize.getPayments = paramSanitizer(function(options, cb) {
			return (options.immeditate ? monetize.getPaymentsImmediate : monetize.getPaymentsInteractive)(options, cb);
		});

		return monetize;
	}

	window.MonetizeJS = MonetizeJS;

	if(typeof define === "function" && define.amd) {
		define("monetizejs", [], function() {
			return MonetizeJS;
		});
	}
})();<|endoftext|>


<commit_before>const gulp = require( 'gulp' );
const gutil = require( 'gulp-util' );
const path = require( 'path' );

const webpack = require( 'webpack' );
const HtmlWebpackPlugin = require( 'html-webpack-plugin' );
const FriendlyErrorsWebpackPlugin = require( 'friendly-errors-webpack-plugin' );
const ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
const WebpackDevServer = require( 'webpack-dev-server' );
const OptimizeCssPlugin = require( 'optimize-css-assets-webpack-plugin' );
const ImageminPlugin = require( 'imagemin-webpack-plugin' ).default;
const autoprefixer = require( 'autoprefixer' );
const CleanCss = require( 'clean-css' );
const WriteFilePlugin = require( 'write-file-webpack-plugin' );
const BundleAnalyzerPlugin = require( 'webpack-bundle-analyzer' ).BundleAnalyzerPlugin;
const VueSSRPlugin = require( 'vue-ssr-webpack-plugin' );
const CopyWebpackPlugin = require( 'copy-webpack-plugin' );

module.exports = function( config )
{
	let base = path.resolve( config.projectBase );

	let noop = function(){};
	let devNoop = config.production ? undefined : noop;
	let prodNoop = !config.production ? undefined : noop;
	let serverNoop = !config.server ? undefined : noop;

	let externals = {};
	for ( let extern of [ 'nw.gui', 'client-voodoo', 'path', 'os', 'fs' ] ) {
		externals[ extern ] = { commonjs: extern };
	}

	const cleanCssOptions = {
		level: 2,
	};

	let cleanCss = new CleanCss( cleanCssOptions );

	let webpackTarget = 'web';
	if ( config.server ) {
		webpackTarget = 'node';
	}
	else if ( config.client ) {
		webpackTarget = 'node-webkit';
	}

	let libraryTarget = 'var';
	if ( config.server ) {
		libraryTarget = 'commonjs';
	}

	function stylesLoader( loaders, options )
	{
		// Note: style-loader doesn't work on the server.

		if ( config.production ) {
			loaders.push( {
				loader: 'clean-css-loader',
				options: cleanCssOptions,
			} );

			return ExtractTextPlugin.extract( {
				fallback: !config.server ? 'style-loader' : undefined,
				use: loaders,
			} );
		}

		if ( !config.server ) {
			loaders.unshift( 'style-loader' );
		}

		return loaders;
	}

	let webpackSectionConfigs = {};
	let webpackSectionTasks = [];
	config.sections.forEach( function( section )
	{
		let indexHtml = section === 'app' ? 'index.html' : section + '.html';

		let appEntries = [
			path.resolve( base, 'src/' + section + '/main.styl' ),
			path.resolve( base, 'src/' + section + '/main.ts' ),
		];

		if ( !config.production ) {
			appEntries.push( 'webpack-dev-server/client?http://localhost:' + config.port + '/' );
			appEntries.push( 'webpack/hot/dev-server' );
		}

		let entry = {
			app: appEntries,
		};

		if ( config.server ) {
			entry = {
				server: [
					path.resolve( base, 'src/' + section + '/server.ts' ),
				],
			};
		}

		webpackSectionConfigs[ section ] = {
			entry,
			target: webpackTarget,
			devServer: {
				outputPath: path.resolve( base, config.buildDir ),
			},
			output: {
				publicPath: (config.production ? config.staticCdn : '') + '/',
				path: path.resolve( base, config.buildDir ),
				filename: config.production ? section + '.[name].[chunkhash:6].js' : section + '.[name].js',
				chunkFilename: config.production ? section + '.[name].[id].[chunkhash:6].js' : undefined,
				libraryTarget: libraryTarget,
			},
			resolve: {
				extensions: [ '.tsx', '.ts', '.js', '.styl' ],
				alias: {
					// Always "app" base img.
					'img': path.resolve( base, 'src/app/img' ),
					'styles': path.resolve( base, 'src/' + section + '/styles' ),
				}
			},
			externals: externals,
			resolveLoader: {
				alias: {
					'view': 'vue-template-loader?' + JSON.stringify( {
						scoped: true,
						transformToRequire: {
							img: 'src',
						},
					} ),
				}
			},
			module: {
				rules: [
					{
						test: /\.tsx?$/,
						use: [
							{
								// God save us.
								loader: 'string-replace-loader',
								options: {
									search: /\$import\(/g,
									replace: 'import(',
								}
							},
							{
								loader: 'ng-annotate-loader',
								options: {
									add: true,
									map: { inline: true },
								},
							},
							{
								loader: 'ts-loader',
								options: {
									transpileOnly: true,
								}
							},
						],
						exclude: /node_modules/,
					},
					{
						test: /\.js$/,
						use: [
							{
								// God save us.
								loader: 'string-replace-loader',
								options: {
									search: /\$import\(/g,
									replace: 'import(',
								}
							},
							{
								loader: 'ng-annotate-loader',
								options: {
									add: true,
									map: { inline: true },
								},
							},
						],
						exclude: /node_modules/,
					},
					// For vue we use the "view" alias.
					{
						test: /\.html$/,
						use: [
							'file-loader?name=templates/[name].[hash:6].[ext]',
							'extract-loader',
							'html-loader',
						],
					},
					// Gotta split it out for vue, but it would be fine with angular as well.
					{
						enforce: 'pre',
						test: /\.styl$/,
						use: 'stylus-relative-loader?paths[]=src/&resolve url&include css',
					},
					{
						enforce: 'post',
						test: /\.styl$/,
						use: stylesLoader( [
							'css-loader?-minimize',
							'postcss-loader',
						] )
					},
					{
						test: /\.md$/,
						use: [
							'file-loader?name=templates/[name].[hash:6].html',
							'extract-loader',
							'html-loader',
							'markdown-loader',
						],
					},
					{
						test: /\.(png|jpe?g|gif|svg|json|ogg|mp4)(\?.*)?$/,
						loader: 'file-loader?name=assets/[name].[hash:6].[ext]',
						exclude: /node_modules/,
					},
					{
						test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
						loader: 'file-loader?name=assets/[name].[hash:6].[ext]',
					},
				]
			},
			// Inline allows us to debug by setting breakpoints.
			// Eval may be faster, but it doesn't allow setting breakpoints.
			devtool: !config.server ? 'cheap-module-inline-source-map' : '#source-map',
			plugins: [
				new webpack.DefinePlugin({
					GJ_ENVIRONMENT: JSON.stringify( !config.developmentEnv ? 'production' : 'development' ),
					GJ_BUILD_TYPE: JSON.stringify( config.production ? 'production' : 'development' ),
					GJ_IS_ANGULAR: JSON.stringify( config.framework === 'angular' ),
					GJ_IS_VUE: JSON.stringify( config.framework === 'vue' ),
					GJ_IS_CLIENT: JSON.stringify( config.client ),
					GJ_IS_SSR: JSON.stringify( config.server ),

					// This sets vue in production mode.
					'process.env': {
						NODE_ENV: JSON.stringify( config.production ? 'production' : 'development' ),
					},
				}),
				new webpack.LoaderOptionsPlugin({
					options: {
						// Fix extract-loader: https://github.com/peerigon/extract-loader/issues/16
						output: {},
						htmlLoader: {
							minimize: config.production,

							// Fix angular templates.
							removeAttributeQuotes: false,
							ignoreCustomFragments: [ /\{\{.*?}}/ ],
						},
						stylus: {
							preferPathResolver: 'webpack'
						},
						postcss: [
							autoprefixer(),
						],
					}
				}),
				// !config.client ? noop : new CopyWebpackPlugin([
				// 	{
				// 		from: path.resolve( base, 'client-package.json' ),
				// 		to: 'package.json',
				// 	},
				// ]),
				devNoop || new webpack.optimize.UglifyJsPlugin({
					compress: {
						warnings: false,
						screw_ie8: true,
					}
				}),
				devNoop || new ImageminPlugin(),
				prodNoop || serverNoop || new webpack.HotModuleReplacementPlugin(),

				// Pull out vendor code from the main entry point.
				devNoop || new webpack.optimize.CommonsChunkPlugin( {
					name: 'vendor',
					minChunks: function( module )
					{
						return module.context
							&& (
								module.context.indexOf( 'node_modules' ) !== -1
								|| module.context.indexOf( 'bower-lib' ) !== -1
							)
							;
					},
				} ),

				// This generates a manifest file that allows our vendor chunk
				// to be cached longer if it doesn't change.
				// More info: https://webpack.js.org/guides/code-splitting-libraries/#implicit-common-vendor-chunk
				devNoop || new webpack.optimize.CommonsChunkPlugin( {
					name: 'manifest',
				} ),

				serverNoop || new ExtractTextPlugin( '[name].[contenthash:6].css' ),
				devNoop || new OptimizeCssPlugin( {
					cssProcessor: {
						process: function( css )
						{
							return new Promise( function( resolve, reject )
							{
								let output = cleanCss.minify( css );
								if ( output.errors.length ) {
									reject( output.errors );
								}
								else {
									resolve( {
										css: output.styles,
									} );
								}
							} );
						}
					},
				} ),
				serverNoop || new HtmlWebpackPlugin( {
					filename: indexHtml,
					template: '!!html-loader?interpolate=require!src/' + indexHtml,
					favicon: path.resolve( base, 'src/app/img/favicon.png' ),
					inject: true,
					chunksSortMode: 'dependency',
					excludeChunks: [ 'server' ],
				} ),
				prodNoop || new FriendlyErrorsWebpackPlugin(),
				!config.server ? noop : new VueSSRPlugin( {
					entry: 'server',
				} ),
				config.write ? new WriteFilePlugin() : noop,
				config.analyze ? new BundleAnalyzerPlugin() : noop,
			]
		};

		gulp.task( 'compile:' + section, function( cb )
		{
			let compiler = webpack( webpackSectionConfigs[ section ] );
			compiler.run( function( err, stats )
			{
				if ( err ) {
					throw new gutil.PluginError( 'webpack:build', err );
				}

				gutil.log( '[webpack:build]', stats.toString( {
					chunks: false,
					colors: true
				} ) );

				cb();
			} );
		} );

		webpackSectionTasks.push( 'compile:' + section );
	} );

	gulp.task( 'watch', gulp.series( 'clean:pre', function( cb )
	{
		let compiler = webpack( webpackSectionConfigs[ config.buildSection ] );

		let server = new WebpackDevServer( compiler, {
			historyApiFallback: {
				rewrites: [
					{ from: /./, to: (config.buildSection === 'app' ? '/index.html' : '/' + config.buildSection + '.html') },
				],
			},
			quiet: true,
			hot: !config.server,
			watchOptions: {
				aggregateTimeout: 300,
			},
		} );

		if ( !config.server ) {
			server.listen( config.port, 'localhost' );
		}
	} ) );

	gulp.task( 'compile', gulp.series( webpackSectionTasks ) );
	gulp.task( 'default', gulp.series( 'clean:pre', 'translations:compile', 'compile' ) );
};
<commit_msg>no longer exclude TS files in node_modules from getting built by webpack<commit_after>const gulp = require( 'gulp' );
const gutil = require( 'gulp-util' );
const path = require( 'path' );

const webpack = require( 'webpack' );
const HtmlWebpackPlugin = require( 'html-webpack-plugin' );
const FriendlyErrorsWebpackPlugin = require( 'friendly-errors-webpack-plugin' );
const ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
const WebpackDevServer = require( 'webpack-dev-server' );
const OptimizeCssPlugin = require( 'optimize-css-assets-webpack-plugin' );
const ImageminPlugin = require( 'imagemin-webpack-plugin' ).default;
const autoprefixer = require( 'autoprefixer' );
const CleanCss = require( 'clean-css' );
const WriteFilePlugin = require( 'write-file-webpack-plugin' );
const BundleAnalyzerPlugin = require( 'webpack-bundle-analyzer' ).BundleAnalyzerPlugin;
const VueSSRPlugin = require( 'vue-ssr-webpack-plugin' );
const CopyWebpackPlugin = require( 'copy-webpack-plugin' );

module.exports = function( config )
{
	let base = path.resolve( config.projectBase );

	let noop = function(){};
	let devNoop = config.production ? undefined : noop;
	let prodNoop = !config.production ? undefined : noop;
	let serverNoop = !config.server ? undefined : noop;

	let externals = {};
	for ( let extern of [ 'nw.gui', 'client-voodoo', 'path', 'os', 'fs' ] ) {
		externals[ extern ] = { commonjs: extern };
	}

	const cleanCssOptions = {
		level: 2,
	};

	let cleanCss = new CleanCss( cleanCssOptions );

	let webpackTarget = 'web';
	if ( config.server ) {
		webpackTarget = 'node';
	}
	else if ( config.client ) {
		webpackTarget = 'node-webkit';
	}

	let libraryTarget = 'var';
	if ( config.server ) {
		libraryTarget = 'commonjs';
	}

	function stylesLoader( loaders, options )
	{
		// Note: style-loader doesn't work on the server.

		if ( config.production ) {
			loaders.push( {
				loader: 'clean-css-loader',
				options: cleanCssOptions,
			} );

			return ExtractTextPlugin.extract( {
				fallback: !config.server ? 'style-loader' : undefined,
				use: loaders,
			} );
		}

		if ( !config.server ) {
			loaders.unshift( 'style-loader' );
		}

		return loaders;
	}

	let webpackSectionConfigs = {};
	let webpackSectionTasks = [];
	config.sections.forEach( function( section )
	{
		let indexHtml = section === 'app' ? 'index.html' : section + '.html';

		let appEntries = [
			path.resolve( base, 'src/' + section + '/main.styl' ),
			path.resolve( base, 'src/' + section + '/main.ts' ),
		];

		if ( !config.production ) {
			appEntries.push( 'webpack-dev-server/client?http://localhost:' + config.port + '/' );
			appEntries.push( 'webpack/hot/dev-server' );
		}

		let entry = {
			app: appEntries,
		};

		if ( config.server ) {
			entry = {
				server: [
					path.resolve( base, 'src/' + section + '/server.ts' ),
				],
			};
		}

		webpackSectionConfigs[ section ] = {
			entry,
			target: webpackTarget,
			devServer: {
				outputPath: path.resolve( base, config.buildDir ),
			},
			output: {
				publicPath: (config.production ? config.staticCdn : '') + '/',
				path: path.resolve( base, config.buildDir ),
				filename: config.production ? section + '.[name].[chunkhash:6].js' : section + '.[name].js',
				chunkFilename: config.production ? section + '.[name].[id].[chunkhash:6].js' : undefined,
				libraryTarget: libraryTarget,
			},
			resolve: {
				extensions: [ '.tsx', '.ts', '.js', '.styl' ],
				alias: {
					// Always "app" base img.
					'img': path.resolve( base, 'src/app/img' ),
					'styles': path.resolve( base, 'src/' + section + '/styles' ),
				}
			},
			externals: externals,
			resolveLoader: {
				alias: {
					'view': 'vue-template-loader?' + JSON.stringify( {
						scoped: true,
						transformToRequire: {
							img: 'src',
						},
					} ),
				}
			},
			module: {
				rules: [
					{
						test: /\.tsx?$/,
						use: [
							{
								// God save us.
								loader: 'string-replace-loader',
								options: {
									search: /\$import\(/g,
									replace: 'import(',
								}
							},
							{
								loader: 'ng-annotate-loader',
								options: {
									add: true,
									map: { inline: true },
								},
							},
							{
								loader: 'ts-loader',
								options: {
									transpileOnly: true,
								}
							},
						],
					},
					{
						test: /\.js$/,
						use: [
							{
								// God save us.
								loader: 'string-replace-loader',
								options: {
									search: /\$import\(/g,
									replace: 'import(',
								}
							},
							{
								loader: 'ng-annotate-loader',
								options: {
									add: true,
									map: { inline: true },
								},
							},
						],
						exclude: /node_modules/,
					},
					// For vue we use the "view" alias.
					{
						test: /\.html$/,
						use: [
							'file-loader?name=templates/[name].[hash:6].[ext]',
							'extract-loader',
							'html-loader',
						],
					},
					// Gotta split it out for vue, but it would be fine with angular as well.
					{
						enforce: 'pre',
						test: /\.styl$/,
						use: 'stylus-relative-loader?paths[]=src/&resolve url&include css',
					},
					{
						enforce: 'post',
						test: /\.styl$/,
						use: stylesLoader( [
							'css-loader?-minimize',
							'postcss-loader',
						] )
					},
					{
						test: /\.md$/,
						use: [
							'file-loader?name=templates/[name].[hash:6].html',
							'extract-loader',
							'html-loader',
							'markdown-loader',
						],
					},
					{
						test: /\.(png|jpe?g|gif|svg|json|ogg|mp4)(\?.*)?$/,
						loader: 'file-loader?name=assets/[name].[hash:6].[ext]',
						exclude: /node_modules/,
					},
					{
						test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
						loader: 'file-loader?name=assets/[name].[hash:6].[ext]',
					},
				]
			},
			// Inline allows us to debug by setting breakpoints.
			// Eval may be faster, but it doesn't allow setting breakpoints.
			devtool: !config.server ? 'cheap-module-inline-source-map' : '#source-map',
			plugins: [
				new webpack.DefinePlugin({
					GJ_ENVIRONMENT: JSON.stringify( !config.developmentEnv ? 'production' : 'development' ),
					GJ_BUILD_TYPE: JSON.stringify( config.production ? 'production' : 'development' ),
					GJ_IS_ANGULAR: JSON.stringify( config.framework === 'angular' ),
					GJ_IS_VUE: JSON.stringify( config.framework === 'vue' ),
					GJ_IS_CLIENT: JSON.stringify( config.client ),
					GJ_IS_SSR: JSON.stringify( config.server ),

					// This sets vue in production mode.
					'process.env': {
						NODE_ENV: JSON.stringify( config.production ? 'production' : 'development' ),
					},
				}),
				new webpack.LoaderOptionsPlugin({
					options: {
						// Fix extract-loader: https://github.com/peerigon/extract-loader/issues/16
						output: {},
						htmlLoader: {
							minimize: config.production,

							// Fix angular templates.
							removeAttributeQuotes: false,
							ignoreCustomFragments: [ /\{\{.*?}}/ ],
						},
						stylus: {
							preferPathResolver: 'webpack'
						},
						postcss: [
							autoprefixer(),
						],
					}
				}),
				// !config.client ? noop : new CopyWebpackPlugin([
				// 	{
				// 		from: path.resolve( base, 'client-package.json' ),
				// 		to: 'package.json',
				// 	},
				// ]),
				devNoop || new webpack.optimize.UglifyJsPlugin({
					compress: {
						warnings: false,
						screw_ie8: true,
					}
				}),
				devNoop || new ImageminPlugin(),
				prodNoop || serverNoop || new webpack.HotModuleReplacementPlugin(),

				// Pull out vendor code from the main entry point.
				devNoop || new webpack.optimize.CommonsChunkPlugin( {
					name: 'vendor',
					minChunks: function( module )
					{
						return module.context
							&& (
								module.context.indexOf( 'node_modules' ) !== -1
								|| module.context.indexOf( 'bower-lib' ) !== -1
							)
							;
					},
				} ),

				// This generates a manifest file that allows our vendor chunk
				// to be cached longer if it doesn't change.
				// More info: https://webpack.js.org/guides/code-splitting-libraries/#implicit-common-vendor-chunk
				devNoop || new webpack.optimize.CommonsChunkPlugin( {
					name: 'manifest',
				} ),

				serverNoop || new ExtractTextPlugin( '[name].[contenthash:6].css' ),
				devNoop || new OptimizeCssPlugin( {
					cssProcessor: {
						process: function( css )
						{
							return new Promise( function( resolve, reject )
							{
								let output = cleanCss.minify( css );
								if ( output.errors.length ) {
									reject( output.errors );
								}
								else {
									resolve( {
										css: output.styles,
									} );
								}
							} );
						}
					},
				} ),
				serverNoop || new HtmlWebpackPlugin( {
					filename: indexHtml,
					template: '!!html-loader?interpolate=require!src/' + indexHtml,
					favicon: path.resolve( base, 'src/app/img/favicon.png' ),
					inject: true,
					chunksSortMode: 'dependency',
					excludeChunks: [ 'server' ],
				} ),
				prodNoop || new FriendlyErrorsWebpackPlugin(),
				!config.server ? noop : new VueSSRPlugin( {
					entry: 'server',
				} ),
				config.write ? new WriteFilePlugin() : noop,
				config.analyze ? new BundleAnalyzerPlugin() : noop,
			]
		};

		gulp.task( 'compile:' + section, function( cb )
		{
			let compiler = webpack( webpackSectionConfigs[ section ] );
			compiler.run( function( err, stats )
			{
				if ( err ) {
					throw new gutil.PluginError( 'webpack:build', err );
				}

				gutil.log( '[webpack:build]', stats.toString( {
					chunks: false,
					colors: true
				} ) );

				cb();
			} );
		} );

		webpackSectionTasks.push( 'compile:' + section );
	} );

	gulp.task( 'watch', gulp.series( 'clean:pre', function( cb )
	{
		let compiler = webpack( webpackSectionConfigs[ config.buildSection ] );

		let server = new WebpackDevServer( compiler, {
			historyApiFallback: {
				rewrites: [
					{ from: /./, to: (config.buildSection === 'app' ? '/index.html' : '/' + config.buildSection + '.html') },
				],
			},
			quiet: true,
			hot: !config.server,
			watchOptions: {
				aggregateTimeout: 300,
			},
		} );

		if ( !config.server ) {
			server.listen( config.port, 'localhost' );
		}
	} ) );

	gulp.task( 'compile', gulp.series( webpackSectionTasks ) );
	gulp.task( 'default', gulp.series( 'clean:pre', 'translations:compile', 'compile' ) );
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
    Tab,
    Tabs,
} from 'react-bootstrap'
import './InputTabs.css'
import Turtle from './Turtle.js'
import Transforms from './Transforms.js'
import Wiper from './Wiper.js'
import { connect } from 'react-redux'
import {
  chooseInput,
} from '../reducers/Index.js';

class InputTabs extends Component {

  handleSelect( key ) {
    this.props.dispatch(chooseInput(key));
  }

  render() {
    return (
       <Tabs defaultActiveKey={0} onSelect={this.handleSelect.bind(this)} id="inputTabs">
         <Tab eventKey={0} title="Transforms">
           <Transforms/>
         </Tab>
         <Tab eventKey={1} title="Turtle">
           <Turtle/>
         </Tab>
         <Tab eventKey={2} title="Wiper">
           <Wiper/>
         </Tab>
       </Tabs>
    );
  }
}
InputTabs = connect()(InputTabs);

export default InputTabs;
<commit_msg>Disabling the Turtle stuff until I can do it right. Sorry Turtle.<commit_after>import React, { Component } from 'react';
import {
    Tab,
    Tabs,
} from 'react-bootstrap'
import './InputTabs.css'
import Turtle from './Turtle.js'
import Transforms from './Transforms.js'
import Wiper from './Wiper.js'
import { connect } from 'react-redux'
import {
  chooseInput,
} from '../reducers/Index.js';

class InputTabs extends Component {

  handleSelect( key ) {
    this.props.dispatch(chooseInput(key));
  }

  render() {
    return (
       <Tabs defaultActiveKey={0} onSelect={this.handleSelect.bind(this)} id="inputTabs">
         <Tab eventKey={0} title="Shapes">
           <Transforms/>
         </Tab>
         <Tab eventKey={2} title="Wiper">
           <Wiper/>
         </Tab>
       </Tabs>
    );
  }
}
InputTabs = connect()(InputTabs);

export default InputTabs;
<|endoftext|>


<commit_before>/* global angular */

'use strict';

angular.module('yaru22.angular-timeago', [
]).directive('timeAgo', ['timeAgo', 'nowTime', function (timeAgo, nowTime) {
  return {
    restrict: 'EA',
    link: function(scope, elem, attrs) {
      var fromTime;

      // Track the fromTime attribute
      attrs.$observe('fromTime', function (value) {
        fromTime = timeAgo.parse(value);
      });

      // Track changes to time difference
      scope.$watch(function () {
        return nowTime() - fromTime;
      }, function(value) {
        angular.element(elem).text(timeAgo.inWords(value));
      });
    }
  };
}]).factory('nowTime', ['$window', '$rootScope', function ($window, $rootScope) {
  var nowTime = Date.now();
  var updateTime = function() {
    $window.setTimeout(function() {
      $rootScope.$apply(function(){
        nowTime = Date.now();
        updateTime();
      });
    }, 1000);
  };
  updateTime();
  return function() {
    return nowTime;
  };
}]).factory('timeAgo', ['$translate', function ($translate) {
  var service = {};
  service.settings = {
    refreshMillis: 60000,
    allowFuture: false,
    strings: {
      'en': {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: 'ago',
        suffixFromNow: 'from now',
        seconds: 'less than a minute',
        minute: 'about a minute',
        minutes: '%d minutes',
        hour: 'about an hour',
        hours: 'about %d hours',
        day: 'a day',
        days: '%d days',
        month: 'about a month',
        months: '%d months',
        year: 'about a year',
        years: '%d years',
        numbers: []
      },
      'de': {
        prefixAgo: 'vor',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'from now',
        seconds: 'weniger als einer Minute',
        minute: 'ca. einer Minute',
        minutes: '%d Minuten',
        hour: 'ca. einer Stunde',
        hours: 'ca. %d Stunden',
        day: 'einem Tag',
        days: '%d Tagen',
        month: 'ca. einem Monat',
        months: '%d Monaten',
        year: 'ca. einem Jahr',
        years: '%d Jahren',
        numbers: []
      },
      'he': {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: 'לפני',
        suffixFromNow: 'מעכשיו',
        seconds: 'פחות מדקה',
        minute: 'כדקה',
        minutes: '%d דקות',
        hour: 'כשעה',
        hours: 'כ %d שעות',
        day: 'יום',
        days: '%d ימים',
        month: 'כחודש',
        months: '%d חודשים',
        year: 'כשנה',
        years: '%d שנים',
        numbers: []
      },
      'pt': {
        prefixAgo: null,
        prefixFromNow: 'daqui a',
        suffixAgo: 'atrás',
        suffixFromNow: null,
        seconds: 'menos de um minuto',
        minute: 'cerca de um minuto',
        minutes: '%d minutos',
        hour: 'cerca de uma hora',
        hours: 'cerca de %d horas',
        day: 'um dia',
        days: '%d dias',
        month: 'cerca de um mês',
        months: '%d meses',
        year: 'cerca de um ano',
        years: '%d anos',
        numbers: []
      },
      'fr': {
        prefixAgo: 'il y a',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'from now',
        seconds: 'moins d\'une minute',
        minute: 'environ une minute',
        minutes: '%d minutes',
        hour: 'environ une heure',
        hours: 'environ %d heures',
        day: 'un jour',
        days: '%d jours',
        month: 'environ un mois',
        months: '%d mois',
        year: 'environ un an',
        years: '%d ans',
        numbers: []
      },
      'es': {
        prefixAgo: 'hace',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'apartir de ahora',
        seconds: 'menos de un minuto',
        minute: 'un minuto',
        minutes: '%d minutos',
        hour: 'una hora',
        hours: '%d horas',
        day: 'un dia',
        days: '%d dias',
        month: 'un mes',
        months: '%d meses',
        year: 'un año',
        years: '%d años',
        numbers: []
      }
    }
  };

  service.inWords = function (distanceMillis) {
    // var lang = document.documentElement.lang;
    var lang = $translate.use();
    var $l = service.settings.strings[lang];
    if (typeof $l === 'undefined') {
      $l = service.settings.strings['en'];
    }
    var prefix = $l.prefixAgo;
    var suffix = $l.suffixAgo;
    if (service.settings.allowFuture) {
      if (distanceMillis < 0) {
        prefix = $l.prefixFromNow;
        suffix = $l.suffixFromNow;
      }
    }

    var seconds = Math.abs(distanceMillis) / 1000;
    var minutes = seconds / 60;
    var hours = minutes / 60;
    var days = hours / 24;
    var years = days / 365;

    function substitute(stringOrFunction, number) {
      var string = angular.isFunction(stringOrFunction) ?
      stringOrFunction(number, distanceMillis) : stringOrFunction;
      var value = ($l.numbers && $l.numbers[number]) || number;
      return string.replace(/%d/i, value);
    }

    var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 42 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.round(days)) ||
        days < 45 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.round(days / 30)) ||
        years < 1.5 && substitute($l.year, 1) ||
        substitute($l.years, Math.round(years));

    var separator = $l.wordSeparator === undefined ?  ' ' : $l.wordSeparator;
    if(lang === 'he'){
      return [prefix, suffix, words].join(separator).trim();
    } else {
      return [prefix, words, suffix].join(separator).trim();
    }
  };

  service.parse = function (iso8601) {
    if (angular.isNumber(iso8601)) {
      return parseInt(iso8601, 10);
    }
    if (iso8601 instanceof Date){
      return iso8601;
    }
    var s = (iso8601 || '').trim();
    s = s.replace(/\.\d+/, ''); // remove milliseconds
    s = s.replace(/-/, '/').replace(/-/, '/');
    s = s.replace(/T/, ' ').replace(/Z/, ' UTC');
    s = s.replace(/([\+\-]\d\d)\:?(\d\d)/, ' $1$2'); // -04:00 -> -0400
    return new Date(s);
  };

  return service;
}]).filter('timeAgo', ['nowTime', 'timeAgo', function (nowTime, timeAgo) {
  return function (value) {
    var fromTime = timeAgo.parse(value);
    var diff = nowTime() - fromTime;
    return timeAgo.inWords(diff);
  };
}]);<commit_msg>Make sure date strings use correct iso8601 format<commit_after>/* global angular */

'use strict';

angular.module('yaru22.angular-timeago', [
]).directive('timeAgo', ['timeAgo', 'nowTime', function (timeAgo, nowTime) {
  return {
    restrict: 'EA',
    link: function(scope, elem, attrs) {
      var fromTime;

      // Track the fromTime attribute
      attrs.$observe('fromTime', function (value) {
        fromTime = timeAgo.parse(value);
      });

      // Track changes to time difference
      scope.$watch(function () {
        return nowTime() - fromTime;
      }, function(value) {
        angular.element(elem).text(timeAgo.inWords(value));
      });
    }
  };
}]).factory('nowTime', ['$window', '$rootScope', function ($window, $rootScope) {
  var nowTime = Date.now();
  var updateTime = function() {
    $window.setTimeout(function() {
      $rootScope.$apply(function(){
        nowTime = Date.now();
        updateTime();
      });
    }, 1000);
  };
  updateTime();
  return function() {
    return nowTime;
  };
}]).factory('timeAgo', ['$translate', function ($translate) {
  var service = {};
  service.settings = {
    refreshMillis: 60000,
    allowFuture: false,
    strings: {
      'en': {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: 'ago',
        suffixFromNow: 'from now',
        seconds: 'less than a minute',
        minute: 'about a minute',
        minutes: '%d minutes',
        hour: 'about an hour',
        hours: 'about %d hours',
        day: 'a day',
        days: '%d days',
        month: 'about a month',
        months: '%d months',
        year: 'about a year',
        years: '%d years',
        numbers: []
      },
      'de': {
        prefixAgo: 'vor',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'from now',
        seconds: 'weniger als einer Minute',
        minute: 'ca. einer Minute',
        minutes: '%d Minuten',
        hour: 'ca. einer Stunde',
        hours: 'ca. %d Stunden',
        day: 'einem Tag',
        days: '%d Tagen',
        month: 'ca. einem Monat',
        months: '%d Monaten',
        year: 'ca. einem Jahr',
        years: '%d Jahren',
        numbers: []
      },
      'he': {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: 'לפני',
        suffixFromNow: 'מעכשיו',
        seconds: 'פחות מדקה',
        minute: 'כדקה',
        minutes: '%d דקות',
        hour: 'כשעה',
        hours: 'כ %d שעות',
        day: 'יום',
        days: '%d ימים',
        month: 'כחודש',
        months: '%d חודשים',
        year: 'כשנה',
        years: '%d שנים',
        numbers: []
      },
      'pt': {
        prefixAgo: null,
        prefixFromNow: 'daqui a',
        suffixAgo: 'atrás',
        suffixFromNow: null,
        seconds: 'menos de um minuto',
        minute: 'cerca de um minuto',
        minutes: '%d minutos',
        hour: 'cerca de uma hora',
        hours: 'cerca de %d horas',
        day: 'um dia',
        days: '%d dias',
        month: 'cerca de um mês',
        months: '%d meses',
        year: 'cerca de um ano',
        years: '%d anos',
        numbers: []
      },
      'fr': {
        prefixAgo: 'il y a',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'from now',
        seconds: 'moins d\'une minute',
        minute: 'environ une minute',
        minutes: '%d minutes',
        hour: 'environ une heure',
        hours: 'environ %d heures',
        day: 'un jour',
        days: '%d jours',
        month: 'environ un mois',
        months: '%d mois',
        year: 'environ un an',
        years: '%d ans',
        numbers: []
      },
      'es': {
        prefixAgo: 'hace',
        prefixFromNow: null,
        suffixAgo: null,
        suffixFromNow: 'apartir de ahora',
        seconds: 'menos de un minuto',
        minute: 'un minuto',
        minutes: '%d minutos',
        hour: 'una hora',
        hours: '%d horas',
        day: 'un dia',
        days: '%d dias',
        month: 'un mes',
        months: '%d meses',
        year: 'un año',
        years: '%d años',
        numbers: []
      }
    }
  };

  service.inWords = function (distanceMillis) {
    // var lang = document.documentElement.lang;
    var lang = $translate.use();
    var $l = service.settings.strings[lang];
    if (typeof $l === 'undefined') {
      $l = service.settings.strings['en'];
    }
    var prefix = $l.prefixAgo;
    var suffix = $l.suffixAgo;
    if (service.settings.allowFuture) {
      if (distanceMillis < 0) {
        prefix = $l.prefixFromNow;
        suffix = $l.suffixFromNow;
      }
    }

    var seconds = Math.abs(distanceMillis) / 1000;
    var minutes = seconds / 60;
    var hours = minutes / 60;
    var days = hours / 24;
    var years = days / 365;

    function substitute(stringOrFunction, number) {
      var string = angular.isFunction(stringOrFunction) ?
      stringOrFunction(number, distanceMillis) : stringOrFunction;
      var value = ($l.numbers && $l.numbers[number]) || number;
      return string.replace(/%d/i, value);
    }

    var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 42 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.round(days)) ||
        days < 45 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.round(days / 30)) ||
        years < 1.5 && substitute($l.year, 1) ||
        substitute($l.years, Math.round(years));

    var separator = $l.wordSeparator === undefined ?  ' ' : $l.wordSeparator;
    if(lang === 'he'){
      return [prefix, suffix, words].join(separator).trim();
    } else {
      return [prefix, words, suffix].join(separator).trim();
    }
  };

  service.parse = function (iso8601) {
    if (angular.isNumber(iso8601)) {
      return parseInt(iso8601, 10);
    }
    if (iso8601 instanceof Date){
      return iso8601;
    }
    var s = (iso8601 || '').trim();
    if(s[s.length-1] !== "Z") {
      s += "Z";
    }
    s = s.replace(/\.\d+/, ''); // remove milliseconds
    s = s.replace(/-/, '/').replace(/-/, '/');
    s = s.replace(/T/, ' ').replace(/Z/, ' UTC');
    s = s.replace(/([\+\-]\d\d)\:?(\d\d)/, ' $1$2'); // -04:00 -> -0400
    return new Date(s);
  };

  return service;
}]).filter('timeAgo', ['nowTime', 'timeAgo', function (nowTime, timeAgo) {
  return function (value) {
    var fromTime = timeAgo.parse(value);
    var diff = nowTime() - fromTime;
    return timeAgo.inWords(diff);
  };
}]);<|endoftext|>


<commit_before>/* eslint no-var: [0] */

var path = require('path'),
    fs = require('fs'),
    assign = require('object-assign'),
    pdfParser = require('../pdfParser');

module.exports = function(log, settings, browserWindow, done) {
  var pdfDefaults = {
    marginsType: 0,
    pageSize: 'A4',
    printBackground: false,
    landscape: false
  };

  // TODO: support headerHeight, footerHeight when electron support rendering PDF's header/footer
  var pdfSettings = settings.pdf,
      pdfOptions = assign({}, pdfDefaults, pdfSettings, { printSelectionOnly: false });

  log('before printing..');
  log('pdf options:', pdfOptions);

  browserWindow.printToPDF(pdfOptions, function(err, pdfBuf) {
    var dist = path.join(settings.output.tmpDir, settings.output.id + '.pdf');

    if (err) {
      return done(err);
    }

    // don't know why the electron process hangs up if i don't log anything here
    // (probably pdf.js?)
    // anyway this log prevent the conversion to stop
    log('after printing..');
    log('parsing pdf..');

    pdfParser(pdfBuf, function(pdfParseErr, pdfDoc) {
      log('pdf parsing complete..');

      if (pdfParseErr) {
        return done(pdfParseErr);
      }

      fs.writeFile(dist, pdfBuf, function(saveErr) {
        if (saveErr) {
          return done(saveErr);
        }

        done(null, {
          numberOfPages: pdfDoc.numPages,
          output: dist
        });
      });
    });
  });
};
<commit_msg>[update] use webContents.printToPDF<commit_after>/* eslint no-var: [0] */

var path = require('path'),
    fs = require('fs'),
    assign = require('object-assign'),
    pdfParser = require('../pdfParser');

module.exports = function(log, settings, browserWindow, done) {
  var pdfDefaults = {
    marginsType: 0,
    pageSize: 'A4',
    printBackground: false,
    landscape: false
  };

  // TODO: support headerHeight, footerHeight when electron support rendering PDF's header/footer
  var pdfSettings = settings.pdf,
      pdfOptions = assign({}, pdfDefaults, pdfSettings, { printSelectionOnly: false });

  log('before printing..');
  log('pdf options:', pdfOptions);

  browserWindow.webContents.printToPDF(pdfOptions, function(err, pdfBuf) {
    var dist = path.join(settings.output.tmpDir, settings.output.id + '.pdf');

    if (err) {
      return done(err);
    }

    // don't know why the electron process hangs up if i don't log anything here
    // (probably pdf.js?)
    // anyway this log prevent the conversion to stop
    log('after printing..');
    log('parsing pdf..');

    pdfParser(pdfBuf, function(pdfParseErr, pdfDoc) {
      log('pdf parsing complete..');

      if (pdfParseErr) {
        return done(pdfParseErr);
      }

      fs.writeFile(dist, pdfBuf, function(saveErr) {
        if (saveErr) {
          return done(saveErr);
        }

        done(null, {
          numberOfPages: pdfDoc.numPages,
          output: dist
        });
      });
    });
  });
};
<|endoftext|>


<commit_before>'use strict';

const { env } = require('process');
const { spawn } = require('child_process');

const PluginError = require('plugin-error');

// Execute a shell command
const execCommand = function (command) {
  const [commandA, ...args] = command.trim().split(/ +/);
  const envA = getEnv();
  const child = spawn(commandA, args, { stdio: 'inherit', env: envA });

  // eslint-disable-next-line promise/avoid-new
  return new Promise(execCommandPromise.bind(null, child));
};

// Adds local Node modules binary to `$PATH`
const getEnv = function () {
  const PATH = getPath({ env });
  const envA = { ...env, PATH };
  return envA;
};

const getPath = function ({ env: { PATH = '' } }) {
  const hasLocalDir = PATH.split(':').includes(LOCAL_NODE_BIN_DIR);
  if (hasLocalDir) { return PATH; }

  return `${PATH}:${LOCAL_NODE_BIN_DIR}`;
};

const LOCAL_NODE_BIN_DIR = './node_modules/.bin/';

// Check command exit code
const execCommandPromise = function (child, resolve, reject) {
  child.on('exit', execCommandExit.bind(null, resolve, reject));
};

const execCommandExit = function (resolve, reject, exitCode) {
  if (exitCode === 0) { return resolve(); }

  const error = new PluginError('shell', 'Shell command failed');
  reject(error);
};

module.exports = {
  execCommand,
};
<commit_msg>Add support for silent Gulp Bash commands<commit_after>'use strict';

const { env } = require('process');
const { spawn } = require('child_process');

const PluginError = require('plugin-error');

// Execute a shell command
const execCommand = function (command, opts) {
  const [commandA, ...args] = command.trim().split(/ +/);
  const envA = getEnv();
  const stdio = getStdio({ opts });
  const child = spawn(commandA, args, { env: envA, stdio });

  // eslint-disable-next-line promise/avoid-new
  return new Promise(execCommandPromise.bind(null, child));
};

// Adds local Node modules binary to `$PATH`
const getEnv = function () {
  const PATH = getPath({ env });
  const envA = { ...env, PATH };
  return envA;
};

const getPath = function ({ env: { PATH = '' } }) {
  const hasLocalDir = PATH.split(':').includes(LOCAL_NODE_BIN_DIR);
  if (hasLocalDir) { return PATH; }

  return `${PATH}:${LOCAL_NODE_BIN_DIR}`;
};

const LOCAL_NODE_BIN_DIR = './node_modules/.bin/';

// If `opts.quiet` `true`, does not print stdout (but still prints stderr)
const getStdio = function ({ opts: { quiet = false } = {} }) {
  if (quiet) {
    return [0, 'ignore', 2];
  }

  return 'inherit';
};

// Check command exit code
const execCommandPromise = function (child, resolve, reject) {
  child.on('exit', execCommandExit.bind(null, resolve, reject));
};

const execCommandExit = function (resolve, reject, exitCode) {
  if (exitCode === 0) { return resolve(); }

  const error = new PluginError('shell', 'Shell command failed');
  reject(error);
};

module.exports = {
  execCommand,
};
<|endoftext|>


<commit_before>/* ======= Instance Methods ======= */

var hasConsole = typeof window.console !== undefined;

/**
* Logs a Message
* @param {String} msg
*/
Moon.prototype.log = function(msg) {
  if(!config.silent && hasConsole) console.log(msg);
}

/**
* Throws an Error
* @param {String} msg
*/
Moon.prototype.error = function(msg) {
  if(hasConsole) console.error("[Moon] ERR: " + msg);
}

/**
* Gets Value in Data
* @param {String} key
* @return {String} Value of key in data
*/
Moon.prototype.get = function(key) {
  return this.$data[key];
}

/**
* Sets Value in Data
* @param {String} key
* @param {String} val
*/
Moon.prototype.set = function(key, val) {
  this.$data[key] = val;
  if(!this.$destroyed) this.build(this.$dom.children);
  this.$hooks.updated();
}

/**
* Calls a method
* @param {String} method
*/
Moon.prototype.callMethod = function(method, args) {
  args = args || [];
  this.$methods[method].apply(this, args);
}

// Event Emitter, adapted from https://github.com/KingPixil/voke

/**
* Attaches an Event Listener
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.on = function(eventName, action) {
  if(this.$events[eventName]) {
    this.$events[eventName].push(action);
  } else {
    this.$events[eventName] = [action];
  }
}

/**
* Removes an Event Listener
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.off = function(eventName, action) {
  var index = this.$events[eventName].indexOf(action);
  if(index !== -1) {
    this.$events[eventName].splice(index, 1);
  }
}

/**
* Removes All Event Listeners
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.removeEvents = function() {
  for(var evt in this.$events) {
    this.$events[evt] = [];
  }
}

/**
* Emits an Event
* @param {String} eventName
* @param {Object} meta
*/
Moon.prototype.emit = function(eventName, meta) {
  meta = meta || {};
  meta.type = eventName;

  if(this.$events["*"]) {
    for(var i = 0; i < this.$events["*"].length; i++) {
      var globalHandler = this.$events["*"][i];
      globalHandler(meta);
    }
  }

  for(var i = 0; i < this.$events[eventName].length; i++) {
    var handler = this.$events[eventName][i];
    handler(meta);
  }
}

/**
* Mounts Moon Element
*/
Moon.prototype.mount = function(el) {
  this.$el = document.querySelector(el);

  if(!this.$el) {
    this.error("Element " + this.$opts.el + " not found");
  }

  this.$template = this.$opts.template || this.$el.innerHTML;

  setInitialElementValue(this.$el, this.$template);

  this.$dom = this.render();

  this.build(this.$dom.children);
  this.$hooks.mounted();
}

/**
* Renders Virtual DOM
*/
Moon.prototype.render = function() {
  if(this.$opts.render) {
    return this.$opts.render(h);
  } else {
    return createVirtualDOM(this.$el);
  }
}

/**
* Destroys Moon Instance
*/
Moon.prototype.destroy = function() {
  Object.defineProperty(this, '$data', {
    set: function(value) {
      _data = value;
    }
  });
  this.removeEvents();
  this.$destroyed = true;
  this.$hooks.destroyed();
}

/**
* Builds the DOM With Data
* @param {Array} vdom
*/
Moon.prototype.build = function(vdom) {
  //this.render();
  this.buildNodes(vdom);
}

/**
* Builds Nodes With Data
* @param {Array} vdom
*/
Moon.prototype.buildNodes = function(vdom) {
  for(var i = 0; i < vdom.length; i++) {
    var vnode = vdom[i];
    if(vnode.meta.shouldRender) {
      if(vnode.type === "#text") {
        var valueOfVNode = "";
        valueOfVNode = vnode.val(this.$data);
        if(vnode.node.textContent === valueOfVNode) {
          vnode.meta.shouldRender = false;
        }
        vnode.node.textContent = valueOfVNode;
      } else if(vnode.props) {
        for(var attr in vnode.props) {
          var compiledProp = vnode.props[attr](this.$data);
          if(directives[attr]) {
            vnode.node.removeAttribute(attr);
            directives[attr](vnode.node, compiledProp, vnode);
          } else {
            vnode.node.setAttribute(attr, compiledProp);
          }
        }
      }

      this.build(vnode.children);
    }
  }
}

/**
* Initializes Moon
*/
Moon.prototype.init = function() {
  this.log("======= Moon =======");
  this.$hooks.created();

  if(this.$opts.el) {
    this.mount(this.$opts.el);
  }
}
<commit_msg>recursively call build nodes<commit_after>/* ======= Instance Methods ======= */

var hasConsole = typeof window.console !== undefined;

/**
* Logs a Message
* @param {String} msg
*/
Moon.prototype.log = function(msg) {
  if(!config.silent && hasConsole) console.log(msg);
}

/**
* Throws an Error
* @param {String} msg
*/
Moon.prototype.error = function(msg) {
  if(hasConsole) console.error("[Moon] ERR: " + msg);
}

/**
* Gets Value in Data
* @param {String} key
* @return {String} Value of key in data
*/
Moon.prototype.get = function(key) {
  return this.$data[key];
}

/**
* Sets Value in Data
* @param {String} key
* @param {String} val
*/
Moon.prototype.set = function(key, val) {
  this.$data[key] = val;
  if(!this.$destroyed) this.build(this.$dom.children);
  this.$hooks.updated();
}

/**
* Calls a method
* @param {String} method
*/
Moon.prototype.callMethod = function(method, args) {
  args = args || [];
  this.$methods[method].apply(this, args);
}

// Event Emitter, adapted from https://github.com/KingPixil/voke

/**
* Attaches an Event Listener
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.on = function(eventName, action) {
  if(this.$events[eventName]) {
    this.$events[eventName].push(action);
  } else {
    this.$events[eventName] = [action];
  }
}

/**
* Removes an Event Listener
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.off = function(eventName, action) {
  var index = this.$events[eventName].indexOf(action);
  if(index !== -1) {
    this.$events[eventName].splice(index, 1);
  }
}

/**
* Removes All Event Listeners
* @param {String} eventName
* @param {Function} action
*/
Moon.prototype.removeEvents = function() {
  for(var evt in this.$events) {
    this.$events[evt] = [];
  }
}

/**
* Emits an Event
* @param {String} eventName
* @param {Object} meta
*/
Moon.prototype.emit = function(eventName, meta) {
  meta = meta || {};
  meta.type = eventName;

  if(this.$events["*"]) {
    for(var i = 0; i < this.$events["*"].length; i++) {
      var globalHandler = this.$events["*"][i];
      globalHandler(meta);
    }
  }

  for(var i = 0; i < this.$events[eventName].length; i++) {
    var handler = this.$events[eventName][i];
    handler(meta);
  }
}

/**
* Mounts Moon Element
*/
Moon.prototype.mount = function(el) {
  this.$el = document.querySelector(el);

  if(!this.$el) {
    this.error("Element " + this.$opts.el + " not found");
  }

  this.$template = this.$opts.template || this.$el.innerHTML;

  setInitialElementValue(this.$el, this.$template);

  this.$dom = this.render();

  this.build(this.$dom.children);
  this.$hooks.mounted();
}

/**
* Renders Virtual DOM
*/
Moon.prototype.render = function() {
  if(this.$opts.render) {
    return this.$opts.render(h);
  } else {
    return createVirtualDOM(this.$el);
  }
}

/**
* Destroys Moon Instance
*/
Moon.prototype.destroy = function() {
  Object.defineProperty(this, '$data', {
    set: function(value) {
      _data = value;
    }
  });
  this.removeEvents();
  this.$destroyed = true;
  this.$hooks.destroyed();
}

/**
* Builds the DOM With Data
* @param {Array} vdom
*/
Moon.prototype.build = function(vdom) {
  //this.render();
  this.buildNodes(vdom);
}

/**
* Builds Nodes With Data
* @param {Array} vdom
*/
Moon.prototype.buildNodes = function(vdom) {
  for(var i = 0; i < vdom.length; i++) {
    var vnode = vdom[i];
    if(vnode.meta.shouldRender) {
      if(vnode.type === "#text") {
        var valueOfVNode = "";
        valueOfVNode = vnode.val(this.$data);
        if(vnode.node.textContent === valueOfVNode) {
          vnode.meta.shouldRender = false;
        }
        vnode.node.textContent = valueOfVNode;
      } else if(vnode.props) {
        for(var attr in vnode.props) {
          var compiledProp = vnode.props[attr](this.$data);
          if(directives[attr]) {
            vnode.node.removeAttribute(attr);
            directives[attr](vnode.node, compiledProp, vnode);
          } else {
            vnode.node.setAttribute(attr, compiledProp);
          }
        }
      }

      this.buildNodes(vnode.children);
    }
  }
}

/**
* Initializes Moon
*/
Moon.prototype.init = function() {
  this.log("======= Moon =======");
  this.$hooks.created();

  if(this.$opts.el) {
    this.mount(this.$opts.el);
  }
}
<|endoftext|>


<commit_before>// Read, watch and manage servers
const os = require('os')
const fs = require('fs')
const path = require('path')
const util = require('util')
const chokidar = require('chokidar')
const regroup = require('respawn-group')
const extend = require('xtend')
const getPort = require('get-port')
const mkdirp = require('mkdirp')
const unquote = require('unquote')
const common = require('../common')

// Path
const serversDir = common.serversDir

// Create dir
mkdirp.sync(serversDir)

// Return monitor id
function getId (file) {
  return path.basename(file, '.json')
}

// Return cross-platform command
function getCommand (cmd) {
  if (os.platform() === 'win32') {
    return ['cmd', '/c'].concat(cmd.split(' '))
  } else {
    return ['sh', '-c'].concat(unquote(cmd))
  }
}

// Add server to group
function addServer (group, file) {
  let server = JSON.parse(fs.readFileSync(file, 'utf8'))
  let id = getId(file)
  getPort().then(port => {
    util.log(`Add server id: ${id} cmd: ${server.cmd} port: ${port}`)

    process.env.PORT = port
    let opts = {
      cwd: server.cwd,
      env: extend(process.env, server.env)
    }

    let logFile
    if (server.out) {
      logFile = path.resolve(server.cwd, server.out)
    }

    let mon = group.add(id, getCommand(server.cmd), opts)

    // On start reset logfile and mon.tail
    let onStart = () => {
      mon.tail = ''

      if (logFile) {
        fs.unlink(logFile, (e) => { if (e) util.log(e.message) })
      }
    }

    // On output write to logfile and to mon.tail
    let onOutput = (data) => {
      mon.tail = mon.tail
        .concat(data)
        .split('\n')
        .slice(-100)
        .join('\n')

      if (logFile) {
        fs.appendFile(logFile, data, (e) => { if (e) util.log(e.message) })
      }
    }

    mon
      .on('start', onStart)
      .on('stdout', onOutput)
      .on('stderr', onOutput)

    group.emit('change')
  })
}

// Update server
function updateServer (group, file) {
  addServer(group, file)
  group.restart(getId(file))
}

// Remove server
function removeServer (group, file) {
  group.remove(getId(file))
  group.emit('change')
}

module.exports = function () {
  let group = regroup({
    maxRestarts: 0
  })

  // Add change event
  for (let monEvent of ['start', 'restart', 'stop']) {
    group.on(monEvent, () => group.emit('change'))
  }

  // Log monitors events
  group
    .on('start', (mon) => util.log(mon.id, 'has started'))
    .on('restart', (mon) => util.log(mon.id, 'is being restarted'))
    .on('stop', (mon) => util.log(mon.id, 'has stopped'))
    .on('warn', (mon, err) => util.log(mon.id, err))

  // Watch ~/.hotel/servers
  util.log(`Watching ${serversDir}`)

  // During tests don't bother about CPU and make chokidar super fast
  let opts = {}
  if (process.env.NODE_ENV === 'test') {
    opts.usePolling = true
    opts.interval = 25
  }

  chokidar.watch(serversDir, opts)
    .on('add', (file) => {
      util.log(`created ${file}`)
      addServer(group, file)
    })
    .on('change', (file) => {
      util.log(`changed ${file}`)
      updateServer(group, file)
    })
    .on('unlink', (file) => {
      util.log(`removed ${file}`)
      removeServer(group, file)
    })

  // Add servers
  let files = fs.readdirSync(serversDir)
  for (let file of files) {
    addServer(group, `${serversDir}/${file}`)
  }

  return group
}
<commit_msg>Use Object.assign<commit_after>// Read, watch and manage servers
const os = require('os')
const fs = require('fs')
const path = require('path')
const util = require('util')
const chokidar = require('chokidar')
const regroup = require('respawn-group')
const getPort = require('get-port')
const mkdirp = require('mkdirp')
const unquote = require('unquote')
const common = require('../common')

// Path
const serversDir = common.serversDir

// Create dir
mkdirp.sync(serversDir)

// Return monitor id
function getId (file) {
  return path.basename(file, '.json')
}

// Return cross-platform command
function getCommand (cmd) {
  if (os.platform() === 'win32') {
    return ['cmd', '/c'].concat(cmd.split(' '))
  } else {
    return ['sh', '-c'].concat(unquote(cmd))
  }
}

// Add server to group
function addServer (group, file) {
  let server = JSON.parse(fs.readFileSync(file, 'utf8'))
  let id = getId(file)
  getPort().then(port => {
    util.log(`Add server id: ${id} cmd: ${server.cmd} port: ${port}`)

    process.env.PORT = port
    let opts = {
      cwd: server.cwd,
      env: Object.assign({}, process.env, server.env)
    }

    let logFile
    if (server.out) {
      logFile = path.resolve(server.cwd, server.out)
    }

    let mon = group.add(id, getCommand(server.cmd), opts)

    // On start reset logfile and mon.tail
    let onStart = () => {
      mon.tail = ''

      if (logFile) {
        fs.unlink(logFile, (e) => { if (e) util.log(e.message) })
      }
    }

    // On output write to logfile and to mon.tail
    let onOutput = (data) => {
      mon.tail = mon.tail
        .concat(data)
        .split('\n')
        .slice(-100)
        .join('\n')

      if (logFile) {
        fs.appendFile(logFile, data, (e) => { if (e) util.log(e.message) })
      }
    }

    mon
      .on('start', onStart)
      .on('stdout', onOutput)
      .on('stderr', onOutput)

    group.emit('change')
  })
}

// Update server
function updateServer (group, file) {
  addServer(group, file)
  group.restart(getId(file))
}

// Remove server
function removeServer (group, file) {
  group.remove(getId(file))
  group.emit('change')
}

module.exports = function () {
  let group = regroup({
    maxRestarts: 0
  })

  // Add change event
  for (let monEvent of ['start', 'restart', 'stop']) {
    group.on(monEvent, () => group.emit('change'))
  }

  // Log monitors events
  group
    .on('start', (mon) => util.log(mon.id, 'has started'))
    .on('restart', (mon) => util.log(mon.id, 'is being restarted'))
    .on('stop', (mon) => util.log(mon.id, 'has stopped'))
    .on('warn', (mon, err) => util.log(mon.id, err))

  // Watch ~/.hotel/servers
  util.log(`Watching ${serversDir}`)

  // During tests don't bother about CPU and make chokidar super fast
  let opts = {}
  if (process.env.NODE_ENV === 'test') {
    opts.usePolling = true
    opts.interval = 25
  }

  chokidar.watch(serversDir, opts)
    .on('add', (file) => {
      util.log(`created ${file}`)
      addServer(group, file)
    })
    .on('change', (file) => {
      util.log(`changed ${file}`)
      updateServer(group, file)
    })
    .on('unlink', (file) => {
      util.log(`removed ${file}`)
      removeServer(group, file)
    })

  // Add servers
  let files = fs.readdirSync(serversDir)
  for (let file of files) {
    addServer(group, `${serversDir}/${file}`)
  }

  return group
}
<|endoftext|>


<commit_before>var LiteMQ={version:"<version>",debugMode:!1,utils:{convertToArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)?t:[t]},copy:function(t){return t?JSON.parse(JSON.stringify(t)):t},each:function(t,e,n){t=LiteMQ.convertToArray(t);for(var i=0;t.length>i;i++)e.call(n||null,t[i],i)}},logger:{log:function(t){"undefined"!=typeof console&&console.log&&console.log(t)},debug:function(t,e){LiteMQ.debugMode&&(this.log(["# DEBUG MODE ON","# Bus: "+t.bus.name,"# Origin: "+t.name,"# Event: "+e.eventName,"# Body: "].join("\n")),this.log(e.body),this.log("#########################"))}},convertToArray:function(t){return this.utils.convertToArray(t)},copy:function(t){return this.utils.copy(t)},debug:function(t,e){this.logger.debug(t,e)},each:function(t,e,n){this.utils.each(t,e,n)}};LiteMQ.Bus=o.Class({attach:function(t,e,n){var i=this;LiteMQ.each(t,function(t){i._addEventListener(t,[e,n])})},clear:function(){this._resetListeners()},detach:function(t,e,n){var i=this;t?LiteMQ.each(t,function(t){n?i._detachListener(t,e,n):i._detachEvent(t,e)}):this._detachAll(e)},init:function(t){this._super(t),this._listeners={}},trigger:function(t,e,n){var i=this;LiteMQ.each(t,function(t){var s={origin:e.name,eventName:t,body:LiteMQ.copy(n)};LiteMQ.debug(e,s),i._filterEventListener(t,function(t,n){try{return t!==e&&n.call(t,s),!0}catch(i){console.log(i)}})})},_addEventListener:function(t,e){var n=this._getEventListeners(t);n.push(e)},_detachAll:function(t){var e=this._getListeners();for(var n in e)this._detachEvent(n,t)},_detachEvent:function(t,e){this._filterEventListener(t,function(t){return e!==t?!0:void 0})},_detachListener:function(t,e,n){this._filterEventListener(t,function(t,i){return e!==t||n!==i?!0:void 0})},_filterEventListener:function(t,e){var n=this._getEventListeners(t),i=[];LiteMQ.each(n,function(t){e(t[0],t[1])&&i.push([t[0],t[1]])}),this._setEventListeners(t,i)},_getEventListeners:function(t){var e=this._listeners[t]||[];return this._setEventListeners(t,e),this._listeners[t]},_getListeners:function(){return this._listeners},_setEventListeners:function(t,e){this._listeners[t]=e},_resetListeners:function(){this._listeners={}}}),LiteMQ.DefaultBus=new LiteMQ.Bus({name:"DefaultBus"}),LiteMQ.Client=o.Class({disable:function(t){var e=this;LiteMQ.each(this.listeners,function(n){n.enabled&&(n.evt!==t&&t||(n.enabled=!1,e._detach(n.evt,n.fn)))})},enable:function(t){var e=this;LiteMQ.each(this.listeners,function(n){n.enabled||n.evt!==t&&t||(n.enabled=!0,e._attach(n.evt,n.fn))})},init:function(t){this.bus=LiteMQ.DefaultBus,this.name="anonymous",this._super(t),this.listeners=[]},pub:function(t,e){return this.bus.trigger(t,this,e),this},sub:function(t,e){var n=this;return LiteMQ.each(t,function(t){n._attach(t,e),n.listeners.push({evt:t,fn:e,enabled:!0})}),this},unsub:function(t,e){return this._detach(t,e),this},_attach:function(t,e){this.bus.attach(t,this,e)},_detach:function(t,e){this.bus.detach(t,this,e)}});<commit_msg>updating litemq<commit_after>var LiteMQ={version:"<version>",debugMode:!1,utils:{convertToArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)?t:[t]},copy:function(t){return t?JSON.parse(JSON.stringify(t)):t},each:function(t,e,n){t=LiteMQ.convertToArray(t);for(var i=0;t.length>i;i++)e.call(n||null,t[i],i)}},logger:{log:function(t){"undefined"!=typeof console&&console.log&&console.log(t)},debug:function(t,e){LiteMQ.debugMode&&(this.log(["# DEBUG MODE ON","# Bus: "+t.bus.name,"# Origin: "+t.name,"# Event: "+e.eventName,"# Body: "].join("\n")),this.log(e.body),this.log("#########################"))}},convertToArray:function(t){return this.utils.convertToArray(t)},copy:function(t){return this.utils.copy(t)},debug:function(t,e){this.logger.debug(t,e)},each:function(t,e,n){this.utils.each(t,e,n)}};LiteMQ.Bus=o.Class({attach:function(t,e,n){var i=this;LiteMQ.each(t,function(t){i._addEventListener(t,[e,n])})},clear:function(){this._resetListeners()},detach:function(t,e,n){var i=this;t?LiteMQ.each(t,function(t){n?i._detachListener(t,e,n):i._detachEvent(t,e)}):this._detachAll(e)},init:function(t){this._super(t),this._listeners={}},trigger:function(t,e,n){var i=this;LiteMQ.each(t,function(t){var s={origin:e.name,eventName:t,body:LiteMQ.copy(n)};LiteMQ.debug(e,s),i._filterEventListener(t,function(t,n){return t!==e&&n.call(t,s),!0})})},_addEventListener:function(t,e){var n=this._getEventListeners(t);n.push(e)},_detachAll:function(t){var e=this._getListeners();for(var n in e)this._detachEvent(n,t)},_detachEvent:function(t,e){this._filterEventListener(t,function(t){return e!==t?!0:void 0})},_detachListener:function(t,e,n){this._filterEventListener(t,function(t,i){return e!==t||n!==i?!0:void 0})},_filterEventListener:function(t,e){var n=this._getEventListeners(t),i=[];LiteMQ.each(n,function(t){e(t[0],t[1])&&i.push([t[0],t[1]])}),this._setEventListeners(t,i)},_getEventListeners:function(t){var e=this._listeners[t]||[];return this._setEventListeners(t,e),this._listeners[t]},_getListeners:function(){return this._listeners},_setEventListeners:function(t,e){this._listeners[t]=e},_resetListeners:function(){this._listeners={}}}),LiteMQ.DefaultBus=new LiteMQ.Bus({name:"DefaultBus"}),LiteMQ.Client=o.Class({disable:function(t){var e=this;LiteMQ.each(this.listeners,function(n){n.enabled&&(n.evt!==t&&t||(n.enabled=!1,e._detach(n.evt,n.fn)))})},enable:function(t){var e=this;LiteMQ.each(this.listeners,function(n){n.enabled||n.evt!==t&&t||(n.enabled=!0,e._attach(n.evt,n.fn))})},init:function(t){this.bus=LiteMQ.DefaultBus,this.name="anonymous",this._super(t),this.listeners=[]},pub:function(t,e){return this.bus.trigger(t,this,e),this},sub:function(t,e){var n=this;return LiteMQ.each(t,function(t){n._attach(t,e),n.listeners.push({evt:t,fn:e,enabled:!0})}),this},unsub:function(t,e){return this._detach(t,e),this},_attach:function(t,e){this.bus.attach(t,this,e)},_detach:function(t,e){this.bus.detach(t,this,e)}});<|endoftext|>


<commit_before>require(['config'], function(config) {
    require(['jquery', 'utils', 'acsSlider', 'acsPopup'], function($, utils, acsSlider, acsPopup) {
        $(function() {
            //init header
            utils.init();

            $('.sliderShow').acsSlider({
                startwidth : 700,
                startheight : 350,
                sliderPagerMethod : 'num'
            });

            $("#sltCountry").bind("change", loadCitiesByCountry);

            $('.jQ-regbtn').on('click', function() {
                $(this).acsPopup({
                    popupSrc : $(this).attr("data-popupSrc"),
                    callBack : function() {
                        $("#btnRegisterSubmit").unbind('click').bind('click', function(e) {
                            e.preventDefault();
                            $(".errorMessage").html(" ");
                            $.ajax({
                                type : "POST",
                                dataType : "json",
                                url : ctx + "/user/asynRegister.html",
                                data : {
                                    login : $("#iptLogin").val(),
                                    password : $("#iptPassword").val()
                                },
                                success : function(data) {
                                    if (data.result) {
                                        window.location.href = ctx + "/navigation/home.html?login=" + data.login
                                    } else {
                                        $(".errorMessage").html(data.message);
                                    }
                                },
                                error : function(e) {
                                    alert(e);
                                }
                            })
                        });
                    }
                });
            });

            $('.jQ-loginbtn').on('click', function() {
                $(this).acsPopup({
                    popupSrc : $(this).attr("data-popupSrc"),
                    callBack : function() {
                        $("#btnLoginSubmit").unbind('click').bind('click', function(e) {
                            e.preventDefault();
                            $(".errorMessage").html(" ");
                            $.ajax({
                                type : "POST",
                                dataType : "json",
                                url : ctx + "/user/asynLogin.html",
                                data : {
                                    login : $("#iptLogin").val(),
                                    password : $("#iptPassword").val()
                                },
                                success : function(data) {
                                    if (data.result) {
                                        window.location.href = ctx + "/navigation/home.html?login=" + data.login
                                    } else {
                                        $(".errorMessage").html(data.message);
                                    }
                                },
                                error : function(e) {
                                    alert(e);
                                }
                            })
                        });
                    }
                });
            });

        });
    });
});

function loadCitiesByCountry() {
    $.ajax({
        type : "POST",
        url : ctx + "/navigation/getCity.html",
        data : {
            countryId : this.value
        },
        success : function(data) {
            renderOption("sltCity", data);
        }
    });

}

function renderOption(selectId, data) {
    var select = $("#" + selectId).empty();
    var jsonObject = $.parseJSON(data);
    if (jsonObject != null) {
        $.each(jsonObject, function(i, e) {
            select.append("<option value='" + e.id + "'>" + e.name + "</option>");
        })
        if (select.find("option").length <= 0) {
            select.append("<option value='0'>no valid result</option>");
        }
    }
}<commit_msg>Finished added the js validation for email when customer tried to register.<commit_after>require(['config'], function(config) {
	require(['jquery', 'utils', 'acsSlider', 'acsPopup'], function($, utils, acsSlider, acsPopup) {
		$(function() {
			//init header
			utils.init();

			$('.sliderShow').acsSlider({
				startwidth : 700,
				startheight : 350,
				sliderPagerMethod : 'num'
			});

			$("#sltCountry").bind("change", loadCitiesByCountry);

			$('.jQ-regbtn').on('click', function() {
				$(this).acsPopup({
					popupSrc : $(this).attr("data-popupSrc"),
					callBack : function() {
						$("#btnRegisterSubmit").unbind('click').bind('click', function(e) {
							e.preventDefault();
							if (validateEmail($("#iptLogin").val())) {
								$(".errorMessage").html(" ");
								$.ajax({
									type : "POST",
									dataType : "json",
									url : ctx + "/user/asynRegister.html",
									data : {
										login : $("#iptLogin").val(),
										password : $("#iptPassword").val()
									},
									success : function(data) {
										if (data.result) {
											window.location.href = ctx + "/navigation/home.html?login=" + data.login
										} else {
											$(".errorMessage").html(data.message);
										}
									},
									error : function(e) {
										alert(e);
									}
								});
							} else {
								$(".errorMessage").html("请输入合法的邮箱地址。");
							}
						});
					}
				});
			});

			$('.jQ-loginbtn').on('click', function() {
				$(this).acsPopup({
					popupSrc : $(this).attr("data-popupSrc"),
					callBack : function() {
						$("#btnLoginSubmit").unbind('click').bind('click', function(e) {
							e.preventDefault();
							$(".errorMessage").html(" ");
							$.ajax({
								type : "POST",
								dataType : "json",
								url : ctx + "/user/asynLogin.html",
								data : {
									login : $("#iptLogin").val(),
									password : $("#iptPassword").val()
								},
								success : function(data) {
									if (data.result) {
										window.location.href = ctx + "/navigation/home.html?login=" + data.login
									} else {
										$(".errorMessage").html(data.message);
									}
								},
								error : function(e) {
									alert(e);
								}
							});
						});
					}
				});
			});

		});
	});
});

function loadCitiesByCountry() {
	$.ajax({
		type : "POST",
		url : ctx + "/navigation/getCity.html",
		data : {
			countryId : this.value
		},
		success : function(data) {
			renderOption("sltCity", data);
		}
	});

}

function renderOption(selectId, data) {
	var select = $("#" + selectId).empty();
	var jsonObject = $.parseJSON(data);
	if (jsonObject != null) {
		$.each(jsonObject, function(i, e) {
			select.append("<option value='" + e.id + "'>" + e.name + "</option>");
		})
		if (select.find("option").length <= 0) {
			select.append("<option value='0'>no valid result</option>");
		}
	}
}

function validateEmail(email) {
	var patten = new RegExp(/^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$/);
	return patten.test(email);
}<|endoftext|>