<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";
let nextIdent = 0;
class CommonsChunkPlugin {
	constructor(options) {
		if(arguments.length > 1) {
			throw new Error(`Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options
object *or* the name of the chunk.
Example: if your old code looked like this:
	new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')
You would change it to:
	new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })
The available options are:
	name: string
	names: string[]
	filename: string
	minChunks: number
	chunks: string[]
	children: boolean
	async: boolean
	minSize: number`);
		}

		const normalizedOptions = this.normalizeOptions(options);

		this.chunkNames = normalizedOptions.chunkNames;
		this.filenameTemplate = normalizedOptions.filenameTemplate;
		this.minChunks = normalizedOptions.minChunks;
		this.selectedChunks = normalizedOptions.selectedChunks;
		this.children = normalizedOptions.children;
		this.async = normalizedOptions.async;
		this.minSize = normalizedOptions.minSize;
		this.ident = __filename + (nextIdent++);
	}

	normalizeOptions(options) {
		if(Array.isArray(options)) {
			return {
				chunkNames: options,
			};
		}

		if(typeof options === "string") {
			return {
				chunkNames: [options],
			};
		}

		// options.children and options.chunk may not be used together
		if(options.children && options.chunks) {
			throw new Error("You can't and it does not make any sense to use \"children\" and \"chunk\" options together.");
		}

		/**
		 * options.async and options.filename are also not possible together
		 * as filename specifies how the chunk is called but "async" implies
		 * that webpack will take care of loading this file.
		 */
		if(options.async && options.filename) {
			throw new Error(`You can not specify a filename if you use the \"async\" option.
You can however specify the name of the async chunk by passing the desired string as the \"async\" option.`);
		}

		/**
		 * Make sure this is either an array or undefined.
		 * "name" can be a string and
		 * "names" a string or an array
		 */
		const chunkNames = options.name || options.names ? [].concat(options.name || options.names) : undefined;
		return {
			chunkNames: chunkNames,
			filenameTemplate: options.filename,
			minChunks: options.minChunks,
			selectedChunks: options.chunks,
			children: options.children,
			async: options.async,
			minSize: options.minSize
		};
	}

	apply(compiler) {
		compiler.plugin("this-compilation", (compilation) => {
			compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
				// only optimize once
				if(compilation[this.ident]) return;
				compilation[this.ident] = true;

				/**
				 * Creates a list of "common"" chunks based on the options.
				 * The list is made up of preexisting or newly created chunks.
				 * - If chunk has the name as specified in the chunkNames it is put in the list
				 * - If no chunk with the name as given in chunkNames exists a new chunk is created and added to the list
				 *
				 * These chunks are the "targets" for extracted modules.
				 */
				const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async);

				// iterate over all our new chunks
				targetChunks.forEach((targetChunk, idx) => {

					/**
					 * These chunks are subject to get "common" modules extracted and moved to the common chunk
					 */
					const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children);

					// bail if no chunk is affected
					if(!affectedChunks) {
						return;
					}

					// If we are async create an async chunk now
					// override the "commonChunk" with the newly created async one and use it as commonChunk from now on
					let asyncChunk;
					if(this.async) {
						asyncChunk = this.createAsyncChunk(compilation, this.async, targetChunk);
						targetChunk = asyncChunk;
					}

					/**
					 * Check which modules are "common" and could be extracted to a "common" chunk
					 */
					const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk);

					// If the minSize option is set check if the size extracted from the chunk is reached
					// else bail out here.
					// As all modules/commons are interlinked with each other, common modules would be extracted
					// if we reach this mark at a later common chunk. (quirky I guess).
					if(this.minSize) {
						const modulesSize = this.calculateModulesSize(extractableModules);
						// if too small, bail
						if(modulesSize < this.minSize)
							return;
					}

					// Remove modules that are moved to commons chunk from their original chunks
					// return all chunks that are affected by having modules removed - we need them later (apparently)
					const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks);

					// connect all extracted modules with the common chunk
					this.addExtractedModulesToTargetChunk(targetChunk, extractableModules);

					// set filenameTemplate for chunk
					if(this.filenameTemplate)
						targetChunk.filenameTemplate = this.filenameTemplate;

					// if we are async connect the blocks of the "reallyUsedChunk" - the ones that had modules removed -
					// with the commonChunk and get the origins for the asyncChunk (remember "asyncChunk === commonChunk" at this moment).
					// bail out
					if(this.async) {
						this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk);
						asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules);
						return;
					}

					// we are not in "async" mode
					// connect used chunks with commonChunk - shouldnt this be reallyUsedChunks here?
					this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk);
				});
				return true;
			});
		});
	}

	getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		// we have specified chunk names
		if(chunkNames) {
			// map chunks by chunkName for quick access
			const allChunksNameMap = allChunks.reduce((map, chunk) => {
				if(chunk.name) {
					map.set(chunk.name, chunk);
				}
				return map;
			}, new Map());

			// Ensure we have a chunk per specified chunk name.
			// Reuse existing chunks if possible
			return chunkNames.map(chunkName => {
				if(allChunksNameMap.has(chunkName)) {
					return allChunksNameMap.get(chunkName);
				}
				// add the filtered chunks to the compilation
				return compilation.addChunk(chunkName);
			});
		}

		// we dont have named chunks specified, so we just take all of them
		if(asyncOrNoSelectedChunk) {
			return allChunks;
		}

		/**
		 * No chunk name(s) was specified nor is this an async/children commons chunk
		 */
		throw new Error(`You did not specify any valid target chunk settings.
Take a look at the "name"/"names" or async/children option.`);
	}

	getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, children) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		if(Array.isArray(selectedChunks)) {
			return allChunks.filter(chunk => {
				const notCommmonChunk = chunk !== targetChunk;
				const isSelectedChunk = selectedChunks.indexOf(chunk.name) > -1;
				return notCommmonChunk && isSelectedChunk;
			});
		}

		if(asyncOrNoSelectedChunk) {
			// nothing to do here
			if(!targetChunk.chunks) {
				return [];
			}

			return targetChunk.chunks.filter((chunk) => {
				// we can only move modules from this chunk if the "commonChunk" is the only parent
				return asyncOption || chunk.parents.length === 1;
			});
		}

		/**
		 * past this point only entry chunks are allowed to become commonChunks
		 */
		if(targetChunk.parents.length > 0) {
			compilation.errors.push(new Error("CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + targetChunk.name + ")"));
			return;
		}

		/**
		 * If we find a "targetchunk" that is also a normal chunk (meaning it is probably specified as an entry)
		 * and the current target chunk comes after that and the found chunk has a runtime*
		 * make that chunk be an 'affected' chunk of the current target chunk.
		 *
		 * To understand what that means take a look at the "examples/chunkhash", this basically will
		 * result in the runtime to be extracted to the current target chunk.
		 *
		 * *runtime: the "runtime" is the "webpack"-block you may have seen in the bundles that resolves modules etc.
		 */
		return allChunks.filter((chunk) => {
			const found = targetChunks.indexOf(chunk);
			if(found >= currentIndex) return false;
			return chunk.hasRuntime();
		});
	}

	createAsyncChunk(compilation, asyncOption, targetChunk) {
		const asyncChunk = compilation.addChunk(typeof asyncOption === "string" ? asyncOption : undefined);
		asyncChunk.chunkReason = "async commons chunk";
		asyncChunk.extraAsync = true;
		asyncChunk.addParent(targetChunk);
		targetChunk.addChunk(asyncChunk);
		return asyncChunk;
	}

	// If minChunks is a function use that
	// otherwhise check if a module is used at least minChunks or 2 or usedChunks.length time
	getModuleFilter(minChunks, targetChunk, usedChunksLength) {
		if(typeof minChunks === "function") {
			return minChunks;
		}
		const minCount = (minChunks || Math.max(2, usedChunksLength));
		const isUsedAtLeastMinTimes = (module, count) => count >= minCount;
		return isUsedAtLeastMinTimes;
	}

	getExtractableModules(minChunks, usedChunks, targetChunk) {
		if(minChunks === Infinity) {
			return [];
		}

		// count how many chunks contain a module
		const commonModulesToCountMap = usedChunks.reduce((map, chunk) => {
			for(let module of chunk.modules) {
				const count = map.has(module) ? map.get(module) : 0;
				map.set(module, count + 1);
			}
			return map;
		}, new Map());

		// filter by minChunks
		const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length);
		// filter by condition
		const moduleFilterCondition = (module, chunk) => {
			if(!module.chunkCondition) {
				return true;
			}
			return module.chunkCondition(chunk);
		};

		return Array.from(commonModulesToCountMap).filter(entry => {
			const module = entry[0];
			const count = entry[1];
			// if the module passes both filters, keep it.
			return moduleFilterCount(module, count) && moduleFilterCondition(module, targetChunk);
		}).map(entry => entry[0]);
	}

	calculateModulesSize(modules) {
		return modules.reduce((totalSize, module) => totalSize + module.size(), 0);
	}

	extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) {
		return reallyUsedModules.reduce((affectedChunksSet, module) => {
			for(let chunk of usedChunks) {
				// removeChunk returns true if the chunk was contained and succesfully removed
				// false if the module did not have a connection to the chunk in question
				if(module.removeChunk(chunk)) {
					affectedChunksSet.add(chunk);
				}
			}
			return affectedChunksSet;
		}, new Set());
	}

	addExtractedModulesToTargetChunk(chunk, modules) {
		for(let module of modules) {
			chunk.addModule(module);
			module.addChunk(chunk);
		}
	}

	makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) {
		for(let chunk of usedChunks) {
			// set commonChunk as new sole parent
			chunk.parents = [commonChunk];
			// add chunk to commonChunk
			commonChunk.addChunk(chunk);

			for(let entrypoint of chunk.entrypoints) {
				entrypoint.insertChunk(commonChunk, chunk);
			}
		}
	}

	moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) {
		for(let chunk of chunks) {
			for(let block of chunk.blocks) {
				block.chunks.unshift(targetChunk);
				targetChunk.addBlock(block);
			}
		}
	}

	extractOriginsOfChunksWithExtractedModules(chunks) {
		const origins = [];
		for(let chunk of chunks) {
			for(let origin of chunk.origins) {
				const newOrigin = Object.create(origin);
				newOrigin.reasons = (origin.reasons || []).concat("async commons");
				origins.push(newOrigin);
			}
		}
		return origins;
	}
}

module.exports = CommonsChunkPlugin;
<commit_msg>replace `chunk.hasRuntime` with `chunk.parents.length === 0`<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";
let nextIdent = 0;
class CommonsChunkPlugin {
	constructor(options) {
		if(arguments.length > 1) {
			throw new Error(`Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options
object *or* the name of the chunk.
Example: if your old code looked like this:
	new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')
You would change it to:
	new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })
The available options are:
	name: string
	names: string[]
	filename: string
	minChunks: number
	chunks: string[]
	children: boolean
	async: boolean
	minSize: number`);
		}

		const normalizedOptions = this.normalizeOptions(options);

		this.chunkNames = normalizedOptions.chunkNames;
		this.filenameTemplate = normalizedOptions.filenameTemplate;
		this.minChunks = normalizedOptions.minChunks;
		this.selectedChunks = normalizedOptions.selectedChunks;
		this.children = normalizedOptions.children;
		this.async = normalizedOptions.async;
		this.minSize = normalizedOptions.minSize;
		this.ident = __filename + (nextIdent++);
	}

	normalizeOptions(options) {
		if(Array.isArray(options)) {
			return {
				chunkNames: options,
			};
		}

		if(typeof options === "string") {
			return {
				chunkNames: [options],
			};
		}

		// options.children and options.chunk may not be used together
		if(options.children && options.chunks) {
			throw new Error("You can't and it does not make any sense to use \"children\" and \"chunk\" options together.");
		}

		/**
		 * options.async and options.filename are also not possible together
		 * as filename specifies how the chunk is called but "async" implies
		 * that webpack will take care of loading this file.
		 */
		if(options.async && options.filename) {
			throw new Error(`You can not specify a filename if you use the \"async\" option.
You can however specify the name of the async chunk by passing the desired string as the \"async\" option.`);
		}

		/**
		 * Make sure this is either an array or undefined.
		 * "name" can be a string and
		 * "names" a string or an array
		 */
		const chunkNames = options.name || options.names ? [].concat(options.name || options.names) : undefined;
		return {
			chunkNames: chunkNames,
			filenameTemplate: options.filename,
			minChunks: options.minChunks,
			selectedChunks: options.chunks,
			children: options.children,
			async: options.async,
			minSize: options.minSize
		};
	}

	apply(compiler) {
		compiler.plugin("this-compilation", (compilation) => {
			compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
				// only optimize once
				if(compilation[this.ident]) return;
				compilation[this.ident] = true;

				/**
				 * Creates a list of "common"" chunks based on the options.
				 * The list is made up of preexisting or newly created chunks.
				 * - If chunk has the name as specified in the chunkNames it is put in the list
				 * - If no chunk with the name as given in chunkNames exists a new chunk is created and added to the list
				 *
				 * These chunks are the "targets" for extracted modules.
				 */
				const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async);

				// iterate over all our new chunks
				targetChunks.forEach((targetChunk, idx) => {

					/**
					 * These chunks are subject to get "common" modules extracted and moved to the common chunk
					 */
					const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children);

					// bail if no chunk is affected
					if(!affectedChunks) {
						return;
					}

					// If we are async create an async chunk now
					// override the "commonChunk" with the newly created async one and use it as commonChunk from now on
					let asyncChunk;
					if(this.async) {
						asyncChunk = this.createAsyncChunk(compilation, this.async, targetChunk);
						targetChunk = asyncChunk;
					}

					/**
					 * Check which modules are "common" and could be extracted to a "common" chunk
					 */
					const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk);

					// If the minSize option is set check if the size extracted from the chunk is reached
					// else bail out here.
					// As all modules/commons are interlinked with each other, common modules would be extracted
					// if we reach this mark at a later common chunk. (quirky I guess).
					if(this.minSize) {
						const modulesSize = this.calculateModulesSize(extractableModules);
						// if too small, bail
						if(modulesSize < this.minSize)
							return;
					}

					// Remove modules that are moved to commons chunk from their original chunks
					// return all chunks that are affected by having modules removed - we need them later (apparently)
					const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks);

					// connect all extracted modules with the common chunk
					this.addExtractedModulesToTargetChunk(targetChunk, extractableModules);

					// set filenameTemplate for chunk
					if(this.filenameTemplate)
						targetChunk.filenameTemplate = this.filenameTemplate;

					// if we are async connect the blocks of the "reallyUsedChunk" - the ones that had modules removed -
					// with the commonChunk and get the origins for the asyncChunk (remember "asyncChunk === commonChunk" at this moment).
					// bail out
					if(this.async) {
						this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk);
						asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules);
						return;
					}

					// we are not in "async" mode
					// connect used chunks with commonChunk - shouldnt this be reallyUsedChunks here?
					this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk);
				});
				return true;
			});
		});
	}

	getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		// we have specified chunk names
		if(chunkNames) {
			// map chunks by chunkName for quick access
			const allChunksNameMap = allChunks.reduce((map, chunk) => {
				if(chunk.name) {
					map.set(chunk.name, chunk);
				}
				return map;
			}, new Map());

			// Ensure we have a chunk per specified chunk name.
			// Reuse existing chunks if possible
			return chunkNames.map(chunkName => {
				if(allChunksNameMap.has(chunkName)) {
					return allChunksNameMap.get(chunkName);
				}
				// add the filtered chunks to the compilation
				return compilation.addChunk(chunkName);
			});
		}

		// we dont have named chunks specified, so we just take all of them
		if(asyncOrNoSelectedChunk) {
			return allChunks;
		}

		/**
		 * No chunk name(s) was specified nor is this an async/children commons chunk
		 */
		throw new Error(`You did not specify any valid target chunk settings.
Take a look at the "name"/"names" or async/children option.`);
	}

	getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, children) {
		const asyncOrNoSelectedChunk = children || asyncOption;

		if(Array.isArray(selectedChunks)) {
			return allChunks.filter(chunk => {
				const notCommmonChunk = chunk !== targetChunk;
				const isSelectedChunk = selectedChunks.indexOf(chunk.name) > -1;
				return notCommmonChunk && isSelectedChunk;
			});
		}

		if(asyncOrNoSelectedChunk) {
			// nothing to do here
			if(!targetChunk.chunks) {
				return [];
			}

			return targetChunk.chunks.filter((chunk) => {
				// we can only move modules from this chunk if the "commonChunk" is the only parent
				return asyncOption || chunk.parents.length === 1;
			});
		}

		/**
		 * past this point only entry chunks are allowed to become commonChunks
		 */
		if(targetChunk.parents.length > 0) {
			compilation.errors.push(new Error("CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + targetChunk.name + ")"));
			return;
		}

		/**
		 * If we find a "targetchunk" that is also a normal chunk (meaning it is probably specified as an entry)
		 * and the current target chunk comes after that and the found chunk has a runtime*
		 * make that chunk be an 'affected' chunk of the current target chunk.
		 *
		 * To understand what that means take a look at the "examples/chunkhash", this basically will
		 * result in the runtime to be extracted to the current target chunk.
		 *
		 * *runtime: the "runtime" is the "webpack"-block you may have seen in the bundles that resolves modules etc.
		 */
		return allChunks.filter((chunk) => {
			const found = targetChunks.indexOf(chunk);
			if(found >= currentIndex) return false;
			return chunk.parents.length === 0;
		});
	}

	createAsyncChunk(compilation, asyncOption, targetChunk) {
		const asyncChunk = compilation.addChunk(typeof asyncOption === "string" ? asyncOption : undefined);
		asyncChunk.chunkReason = "async commons chunk";
		asyncChunk.extraAsync = true;
		asyncChunk.addParent(targetChunk);
		targetChunk.addChunk(asyncChunk);
		return asyncChunk;
	}

	// If minChunks is a function use that
	// otherwhise check if a module is used at least minChunks or 2 or usedChunks.length time
	getModuleFilter(minChunks, targetChunk, usedChunksLength) {
		if(typeof minChunks === "function") {
			return minChunks;
		}
		const minCount = (minChunks || Math.max(2, usedChunksLength));
		const isUsedAtLeastMinTimes = (module, count) => count >= minCount;
		return isUsedAtLeastMinTimes;
	}

	getExtractableModules(minChunks, usedChunks, targetChunk) {
		if(minChunks === Infinity) {
			return [];
		}

		// count how many chunks contain a module
		const commonModulesToCountMap = usedChunks.reduce((map, chunk) => {
			for(let module of chunk.modules) {
				const count = map.has(module) ? map.get(module) : 0;
				map.set(module, count + 1);
			}
			return map;
		}, new Map());

		// filter by minChunks
		const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length);
		// filter by condition
		const moduleFilterCondition = (module, chunk) => {
			if(!module.chunkCondition) {
				return true;
			}
			return module.chunkCondition(chunk);
		};

		return Array.from(commonModulesToCountMap).filter(entry => {
			const module = entry[0];
			const count = entry[1];
			// if the module passes both filters, keep it.
			return moduleFilterCount(module, count) && moduleFilterCondition(module, targetChunk);
		}).map(entry => entry[0]);
	}

	calculateModulesSize(modules) {
		return modules.reduce((totalSize, module) => totalSize + module.size(), 0);
	}

	extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) {
		return reallyUsedModules.reduce((affectedChunksSet, module) => {
			for(let chunk of usedChunks) {
				// removeChunk returns true if the chunk was contained and succesfully removed
				// false if the module did not have a connection to the chunk in question
				if(module.removeChunk(chunk)) {
					affectedChunksSet.add(chunk);
				}
			}
			return affectedChunksSet;
		}, new Set());
	}

	addExtractedModulesToTargetChunk(chunk, modules) {
		for(let module of modules) {
			chunk.addModule(module);
			module.addChunk(chunk);
		}
	}

	makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) {
		for(let chunk of usedChunks) {
			// set commonChunk as new sole parent
			chunk.parents = [commonChunk];
			// add chunk to commonChunk
			commonChunk.addChunk(chunk);

			for(let entrypoint of chunk.entrypoints) {
				entrypoint.insertChunk(commonChunk, chunk);
			}
		}
	}

	moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) {
		for(let chunk of chunks) {
			for(let block of chunk.blocks) {
				block.chunks.unshift(targetChunk);
				targetChunk.addBlock(block);
			}
		}
	}

	extractOriginsOfChunksWithExtractedModules(chunks) {
		const origins = [];
		for(let chunk of chunks) {
			for(let origin of chunk.origins) {
				const newOrigin = Object.create(origin);
				newOrigin.reasons = (origin.reasons || []).concat("async commons");
				origins.push(newOrigin);
			}
		}
		return origins;
	}
}

module.exports = CommonsChunkPlugin;
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth2')
  , Profile = require('./profile')
  , InternalOAuthError = require('passport-oauth2').InternalOAuthError;

/**
 * `Strategy` constructor.
 *
 * The Bitbucket authentication strategy authenticates requests by delegating to
 * Bitbucket using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      identifies client to Bitbucket
 *   - `clientSecret`   secret used to esablish ownership of the client key
 *   - `callbackURL`      URL to which Bitbucket will redirect the user after granting authorization
 *   - `scope`         array of permission scopes to request.  valid scopes include:
 *                     (see https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket#OAuthonBitbucket-Scopes for more info)
 *
 * Examples:
 *
 *     passport.use(new BitbucketStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/bitbucket/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://bitbucket.org/site/oauth2/authorize';
  options.tokenURL = options.tokenURL || 'https://bitbucket.org/site/oauth2/access_token';
  options.customHeaders = options.customHeaders || {};

  if (!options.customHeaders['User-Agent']) {
    options.customHeaders['User-Agent'] = options.userAgent || 'passport-bitbucket';
    //HACK: requests need to fall back to Basic Auth (for access_token call)
    options.customHeaders.Authorization = 'Basic ' + new Buffer(options.clientID + ':' + options.clientSecret).toString('base64');
  }

  OAuth2Strategy.call(this, options, verify);
  this.name = 'bitbucket';
  this._userProfileURL = options.userProfileURL || 'https://api.bitbucket.org/2.0/user';
  this._oauth2.useAuthorizationHeaderforGET(true);
  console.log(this);
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from Bitbucket.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `bitbucket`
 *   - `id`               the user's Bitbucket uuid
 *   - `username`         the user's Bitbucket username
 *   - `displayName`      the user's full name
 *   - `profileUrl`       the URL of the profile for the user on Bitbucket
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.get(this._userProfileURL, accessToken, function (err, body, res) {
    var json;

    if (err) {
      return done(new InternalOAuthError('Failed to fetch user profile', err));
    }

    try {
      json = JSON.parse(body);
    } catch (ex) {
      return done(new Error('Failed to parse user profile'));
    }

    var profile = Profile.parse(json);
    profile.provider  = 'bitbucket';
    profile._raw = body;
    profile._json = json;

    done(null, profile);
  });
};

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<commit_msg>Remove some overly verbose logging<commit_after>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth2')
  , Profile = require('./profile')
  , InternalOAuthError = require('passport-oauth2').InternalOAuthError;

/**
 * `Strategy` constructor.
 *
 * The Bitbucket authentication strategy authenticates requests by delegating to
 * Bitbucket using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      identifies client to Bitbucket
 *   - `clientSecret`   secret used to esablish ownership of the client key
 *   - `callbackURL`      URL to which Bitbucket will redirect the user after granting authorization
 *   - `scope`         array of permission scopes to request.  valid scopes include:
 *                     (see https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket#OAuthonBitbucket-Scopes for more info)
 *
 * Examples:
 *
 *     passport.use(new BitbucketStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/bitbucket/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://bitbucket.org/site/oauth2/authorize';
  options.tokenURL = options.tokenURL || 'https://bitbucket.org/site/oauth2/access_token';
  options.customHeaders = options.customHeaders || {};

  if (!options.customHeaders['User-Agent']) {
    options.customHeaders['User-Agent'] = options.userAgent || 'passport-bitbucket';
    //HACK: requests need to fall back to Basic Auth (for access_token call)
    options.customHeaders.Authorization = 'Basic ' + new Buffer(options.clientID + ':' + options.clientSecret).toString('base64');
  }

  OAuth2Strategy.call(this, options, verify);
  this.name = 'bitbucket';
  this._userProfileURL = options.userProfileURL || 'https://api.bitbucket.org/2.0/user';
  this._oauth2.useAuthorizationHeaderforGET(true);
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from Bitbucket.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `bitbucket`
 *   - `id`               the user's Bitbucket uuid
 *   - `username`         the user's Bitbucket username
 *   - `displayName`      the user's full name
 *   - `profileUrl`       the URL of the profile for the user on Bitbucket
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.get(this._userProfileURL, accessToken, function (err, body, res) {
    var json;

    if (err) {
      return done(new InternalOAuthError('Failed to fetch user profile', err));
    }

    try {
      json = JSON.parse(body);
    } catch (ex) {
      return done(new Error('Failed to parse user profile'));
    }

    var profile = Profile.parse(json);
    profile.provider  = 'bitbucket';
    profile._raw = body;
    profile._json = json;

    done(null, profile);
  });
};

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<|endoftext|>


<commit_before>'use strict';

function relativeUrlHelper(from, to) {
  from = from || '';
  to = to || '';

  var fromParts = from.split('/');
  var toParts = to.split('/');
  var length = Math.min(fromParts.length, toParts.length);
  var i = 0;

  for (; i < length; i++) {
    if (fromParts[i] !== toParts[i]) break;
  }

  var out = toParts.slice(i);

  for (var j = fromParts.length - i - 1; j > 0; j--) {
    out.unshift('..');
  }

  var outLength = out.length;

  // If the last 2 elements of `out` is empty strings, replace them with `index.html`.
  if (outLength > 1 && !out[outLength - 1] && !out[outLength] - 2) {
    out = out.slice(0, outLength - 2).concat('index.html');
  }

  return out.join('/').replace(/\/{2,}/g, '/');
}

module.exports = relativeUrlHelper;
<commit_msg>fix relative_url<commit_after>'use strict';

function relativeUrlHelper(from, to) {
  from = from || '';
  to = to || '';

  var fromParts = from.split('/');
  var toParts = to.split('/');
  var length = Math.min(fromParts.length, toParts.length);
  var i = 0;

  for (; i < length; i++) {
    if (fromParts[i] !== toParts[i]) break;
  }

  var out = toParts.slice(i);

  for (var j = fromParts.length - i - 1; j > 0; j--) {
    out.unshift('..');
  }

  var outLength = out.length;

  // If the last 2 elements of `out` is empty strings, replace them with `index.html`.
  if (outLength > 1 && !out[outLength - 1] && !out[outLength - 2]) {
    out = out.slice(0, outLength - 2).concat('index.html');
  }

  return out.join('/').replace(/\/{2,}/g, '/');
}

module.exports = relativeUrlHelper;
<|endoftext|>


<commit_before>var moment = require('moment');
var _ = require('underscore');
var im = require('./im-utils.cs.js');

var pow   = Math.pow;
var floor = Math.floor;
var log   = Math.log;
var min   = Math.min;
var max   = Math.max;
var abs   = Math.abs;
var LN10  = Math.LN10;

// period = {
//	years : ,
//	months : ,
//	weeks : ,
//	days : ,
//  total: *nb days*
// }
var processPeriod = function(period){

  if(im.isImm(period)){return period;}

	if(typeof period === 'number'){ // ms
		period = makePeriod(moment.duration(period));
	}

	for(var t in {years: true, months: true, weeks: true, days: true}){
		if(period[t] === null || period[t] === undefined){
			period[t] = 0;
		}
	}
	if(period.total === null || period.total === undefined){
		period.total = moment.duration(period).asDays();
	}

	if(period.total > 15 && !period.offset){
		period.offset = true;
	}

	return period;
};

var makePeriod = function(msOrDur){
	var dur = ( !!msOrDur.years ) ? msOrDur : moment.duration(msOrDur);
	return {
		years: dur.years(),
		months: dur.months(),
		weeks: dur.weeks(),
		days: dur.days() - 7 * dur.weeks(),
		total: dur.asDays()
	};
};

var fetchFormat = function(p){
	p = processPeriod(p);
	if(p.years !== 0){
		return {
			string: 'YYYY',
			pref: ''
		};
	}else if(p.months >= 6){
		return {
			string: 'S/YY', // ce format n'existe pas, il est géré par la fonction qui appelle
			pref: 'S'
		};
	}else if(p.months >= 3){
		return {
			string: 'Q/YY',
			pref: 'T'
		};
	}else if(p.months !== 0){
		return {
			string: 'MM/YY',
			pref: ''
		};
	}else if(p.weeks !== 0){
		return {
			string: 'DD/MM/YY',
			pref: ''
		};
	}else{
		return {
			string: 'DD/MM/YY',
			pref: ''
		};
	}
};

var roundDownPeriod = function(p){

	var make = (lab,val) => {
		return {
			label: lab,
			val: val
		};
	};

	var out = {};
	if(p.years > 2){
		out = make('years',max(floor(p.years)/10,1));
	}else if(p.total >= moment.duration({months: 6}).asDays()){
		out = make('months', 6);
	}else if(p.total >= moment.duration({months: 3}).asDays()){
		out = make('months', 3);
	}else if(p.total >= moment.duration({months: 1}).asDays()){
		out = make('months', 1);
	}else if(p.total >= moment.duration({weeks: 2}).asDays()){
		out = make('weeks', 2);
	}else if(p.total >= moment.duration({weeks: 1}).asDays()){
		out = make('weeks', 1);
	}else{
		out = make('days', 1);
	}

	return out;
};

var roundUpPeriod = function(p){

	var make = (lab,val) => {
		return {
			label: lab,
			val: val
		};
	};

	var out = {};
	if(p.years !== 0){
		out = make('years',floor(p.years) + 1);
	}else if(p.months >= 6){
		out = make('years', 1);
	}else if(p.months >= 3){
		out = make('months', 6);
	}else if(p.months >= 1){
		out = make('months', 3);
	}else if(p.weeks >= 2){
		out = make('months', 1);
	}else if(p.weeks >= 1){
		out = make('weeks', 2);
	}else if(p.days >= 1){
		out = make('weeks', 1);
	}else{
		out = make('days', 1);
	}

	return out;
};

// round period of sale order of magnitude
// down by default
var roundPeriod = function(per,type){

  var p = {
    years: per.years,
    months: per.months,
    weeks: per.weeks,
    days: per.days,
    total: per.total
  };

	type = type || 'down';

	var types = ['years','months','weeks','days'];

	var makeThis = (type,n) => {
		for(var t = 0; t < types.length; t++){
			if(type === types[t]){
				continue;
			}
			p[types[t]] = 0;
		}
		p[type] = n;
	};

	// 1/10 of years or 1
	// 6, 3 or 1 month(s)
	// 2 or 1 week(s)
	// 1 day
	var round = ( type === 'up' ) ? roundUpPeriod(p) : roundDownPeriod(p);
	makeThis(round.label,round.val);

	p.total = moment.duration(p).asDays();

	return p;
};

var closestUp = function(date,per){
	var out = closestDown(date,per);
	while(out.getTime() <= date.getTime()){
		out = m.add(out,per);
	}

	return out;
};

// beginning of period
var closestDown = function(date,per){
	// day
	if(per.days !== 0){
		return moment(date).subtract(per.days,'days').startOf('day').toDate();
	}
	// start of week: Sunday
	if(per.weeks !== 0){
		 return moment(date).subtract(per.weeks,'weeks').startOf("week").toDate();
	}
	// start of month
	if(per.months !== 0){
		var month = 0;
		while(month < date.getMonth()){
			month += per.months;
		}
		month -= per.months;
		return new Date(date.getFullYear(),month,1);
	}
	// start of year
	if(per.months !== 0){
		return new Date(date.getFullYear(),0,1);
	}
};

var sameDoP = function(dop1,dop2){
	var b1 = dop1 instanceof Date;
	var b2 = dop2 instanceof Date;
	if(b1 !== b2){
		return null;
	}

	return (b1)?'date':'period';
};

var dateGT = function(d1,d2){
	return d1.getTime() > d2.getTime();
};

var dateLT = function(d1,d2){
	return d1.getTime() < d2.getTime();
};

var periodGT = function(p1,p2){
	return p1.total > p2.total;
};

var periodLT = function(p1,p2){
	return p1.total < p2.total;
};

var greaterThan = function(v1,v2,type){
	return (type === 'date')?dateGT(v1,v2):periodGT(v1,v2);
};

var lowerThan = function(v1,v2,type){
	return (type === 'date')?dateLT(v1,v2):periodLT(v1,v2);
};

var addPer = function(p1,p2){
	p1 = processPeriod(p1);
	return makePeriod(moment.duration(p1).add(moment.duration(p2)));
};

var subPer = function(p1,p2){
	p1 = processPeriod(p1);
	return makePeriod(moment.duration(p1).subtract(moment.duration(p2)));
};

var m = {};

// date / distance methods
m.orderMag = function(dop){
	var ms = (dop instanceof Date) ? dop.getTime() : moment.duration({days: processPeriod(dop).total}).asMilliseconds();

	return floor( log(ms) / LN10);
};

m.orderMagValue = function(last,first){
	// start of next year
	var nextfst = new Date(first.getFullYear() + 1,0,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next semester
	if(first.getMonth() < 7){
		nextfst = new Date(first.getFullYear(),7,1);
		if(m.lowerThan(nextfst,last)){
			return nextfst;
		}
	}

	// start of next trimester
	var mm = first.getMonth() + 3 - first.getMonth() % 3;
	nextfst = new Date(first.getFullYear(),mm,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next month
	nextfst = new Date(first.getFullYear(),first.getMonth() + 1,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next half-month
	if(first.getDate() < 15){
		nextfst = new Date(first.getFullYear(),first.getMonth(),15);
		if(m.lowerThan(nextfst,last)){
			return nextfst;
		}
	}

	// start of next quarter-month (as 7 days)
	var dd = first.getDate() + 7 - first.getDate() % 7;
	nextfst = new Date(first.getFullYear(),first.getMonth(),dd);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// next day
	return new Date(first.getFullYear(),first.getMonth(),first.getDate() + 1);
};

m.orderMagDist = function(r){
	return makePeriod(pow(10,m.orderMag(r)));
};

m.roundUp = function(p){
	return roundPeriod(p,'up');
};

m.roundDown = function(p){
	return roundPeriod(p,'down');
};

m.multiply = function(p,f){
	return makePeriod(moment.duration({days: processPeriod(p).total * f}));
};

m.divide = function(p,f){
	return makePeriod(moment.duration({days: processPeriod(p).total / f}));
};

m.increase = function(p1,p2){
	return makePeriod(moment.duration({days: processPeriod(p1).total + processPeriod(p2).total}));
};

m.offset = function(p){
	p = processPeriod(p);

	var offsetMe = (per) => {
		if(per.years !== 0){
			return makePeriod(moment.duration({months: 6}));
		}else{
			return m.divide(p,2);
		}
	};

	return (p.offset )? offsetMe(p) : makePeriod(0) ;
};

// date methods
m.closestRoundUp = function(ref,per){
	return closestUp(ref, roundPeriod(per) );
};

m.closestRoundDown = function(ref,per){
	return closestDown(ref, roundPeriod(per) );
};

m.closestRound = function(ref,om,type){
	return (type === 'up')? m.closestRoundUp(ref,om):m.closestRoundDown(ref,om);
};

m.min = function(dates){
	return new Date(min.apply(null,_.map(dates, (date) => {return date.getTime();})));
};

m.max = function(dates){
	return new Date(max.apply(null,_.map(dates, (date) => {return date.getTime();})));
};

m.label = function(date,period){
	var format = fetchFormat(period);
	var out = '';
	if(format.pref === 'S'){
		out = (date.getMonth() > 5)? '2/' : '1/';
		out += moment(date).format('YY');
	}else{
		out = moment(date).format(format.string);
	}
	return format.pref + out;
};

// date & period methods
m.add = function(dop,p){
	// preprocess period
	p = processPeriod(p);

	return (dop instanceof Date) ? moment(dop)
		.add(p.years,'years')
		.add(p.months,'months')
		.add(p.weeks,'weeks')
		.add(p.days,'days').toDate():
		addPer(dop,p);
};

m.subtract = function(dop,p){
	// preprocess period
	p = processPeriod(p);

	return (dop instanceof Date) ? moment(dop)
		.subtract(p.years,'years')
		.subtract(p.months,'months')
		.subtract(p.weeks,'weeks')
		.subtract(p.days,'days').toDate():
		subPer(dop,p);
};

m.distance = function(d1,d2){
	return makePeriod(abs(d1.getTime() - d2.getTime()));
};

m.greaterThan = function(dop1,dop2){
	var sd = sameDoP(dop1,dop2);
	if(sd === null){
		throw 'Error in dateMgr: trying to compare a Date with a Period';
	}
	return greaterThan(dop1,dop2,sd);
};

m.lowerThan = function(dop1,dop2){
	var sd = sameDoP(dop1,dop2);
	if(sd === null){
		throw 'Error in dateMgr: trying to compare a Date with a Period';
	}
	return lowerThan(dop1,dop2,sd);
};

// managements
m.getValue = function(dop){
	return (dop instanceof Date) ? dop.getTime() : moment.duration(dop).asMilliseconds();
};

m.extraTicks = function(step,start,end){
	var out = [];
	var startYear = start.getFullYear();
	var lastYear = end.getFullYear();
	// every year, whatever happens
	for(var ye = startYear; ye <= lastYear; ye++){
		var dat = new Date(ye,0,1);
		if(m.lowerThan(start,dat) && m.lowerThan(dat,end)){
			out.push({
				position: dat,
				offset: {
					along: 0,
					perp: 0
				},
				label: '',
				show: false,
				extra: true,
				grid: {
					show: true,
					color: 'LightGray',
					width: 0.5
				}
			});
		}
	}
	return out;
};

m.smallestStep = function(){
	return makePeriod(moment.duration({days: 1}));
};

m.makePeriod = function(per){
	return processPeriod(per);
};

// in years
m.value = function(num){
	return new Date(num * 1000 * 3600 * 24 * 365);
};

// in years
m.step = function(num){
	return makePeriod({years: num});
};

module.exports = m;
<commit_msg>circular reference<commit_after>var moment = require('moment');
var _ = require('underscore');
var im = {
	isImm: (p) => typeof p === 'object' ? Object.isFrozen(p) : true
};

var pow   = Math.pow;
var floor = Math.floor;
var log   = Math.log;
var min   = Math.min;
var max   = Math.max;
var abs   = Math.abs;
var LN10  = Math.LN10;

// period = {
//	years : ,
//	months : ,
//	weeks : ,
//	days : ,
//  total: *nb days*
// }
var processPeriod = function(period){

  if(im.isImm(period)){return period;}

	if(typeof period === 'number'){ // ms
		period = makePeriod(moment.duration(period));
	}

	for(var t in {years: true, months: true, weeks: true, days: true}){
		if(period[t] === null || period[t] === undefined){
			period[t] = 0;
		}
	}
	if(period.total === null || period.total === undefined){
		period.total = moment.duration(period).asDays();
	}

	if(period.total > 15 && !period.offset){
		period.offset = true;
	}

	return period;
};

var makePeriod = function(msOrDur){
	var dur = ( !!msOrDur.years ) ? msOrDur : moment.duration(msOrDur);
	return {
		years: dur.years(),
		months: dur.months(),
		weeks: dur.weeks(),
		days: dur.days() - 7 * dur.weeks(),
		total: dur.asDays()
	};
};

var fetchFormat = function(p){
	p = processPeriod(p);
	if(p.years !== 0){
		return {
			string: 'YYYY',
			pref: ''
		};
	}else if(p.months >= 6){
		return {
			string: 'S/YY', // ce format n'existe pas, il est géré par la fonction qui appelle
			pref: 'S'
		};
	}else if(p.months >= 3){
		return {
			string: 'Q/YY',
			pref: 'T'
		};
	}else if(p.months !== 0){
		return {
			string: 'MM/YY',
			pref: ''
		};
	}else if(p.weeks !== 0){
		return {
			string: 'DD/MM/YY',
			pref: ''
		};
	}else{
		return {
			string: 'DD/MM/YY',
			pref: ''
		};
	}
};

var roundDownPeriod = function(p){

	var make = (lab,val) => {
		return {
			label: lab,
			val: val
		};
	};

	var out = {};
	if(p.years > 2){
		out = make('years',max(floor(p.years)/10,1));
	}else if(p.total >= moment.duration({months: 6}).asDays()){
		out = make('months', 6);
	}else if(p.total >= moment.duration({months: 3}).asDays()){
		out = make('months', 3);
	}else if(p.total >= moment.duration({months: 1}).asDays()){
		out = make('months', 1);
	}else if(p.total >= moment.duration({weeks: 2}).asDays()){
		out = make('weeks', 2);
	}else if(p.total >= moment.duration({weeks: 1}).asDays()){
		out = make('weeks', 1);
	}else{
		out = make('days', 1);
	}

	return out;
};

var roundUpPeriod = function(p){

	var make = (lab,val) => {
		return {
			label: lab,
			val: val
		};
	};

	var out = {};
	if(p.years !== 0){
		out = make('years',floor(p.years) + 1);
	}else if(p.months >= 6){
		out = make('years', 1);
	}else if(p.months >= 3){
		out = make('months', 6);
	}else if(p.months >= 1){
		out = make('months', 3);
	}else if(p.weeks >= 2){
		out = make('months', 1);
	}else if(p.weeks >= 1){
		out = make('weeks', 2);
	}else if(p.days >= 1){
		out = make('weeks', 1);
	}else{
		out = make('days', 1);
	}

	return out;
};

// round period of sale order of magnitude
// down by default
var roundPeriod = function(per,type){

  var p = {
    years: per.years,
    months: per.months,
    weeks: per.weeks,
    days: per.days,
    total: per.total
  };

	type = type || 'down';

	var types = ['years','months','weeks','days'];

	var makeThis = (type,n) => {
		for(var t = 0; t < types.length; t++){
			if(type === types[t]){
				continue;
			}
			p[types[t]] = 0;
		}
		p[type] = n;
	};

	// 1/10 of years or 1
	// 6, 3 or 1 month(s)
	// 2 or 1 week(s)
	// 1 day
	var round = ( type === 'up' ) ? roundUpPeriod(p) : roundDownPeriod(p);
	makeThis(round.label,round.val);

	p.total = moment.duration(p).asDays();

	return p;
};

var closestUp = function(date,per){
	var out = closestDown(date,per);
	while(out.getTime() <= date.getTime()){
		out = m.add(out,per);
	}

	return out;
};

// beginning of period
var closestDown = function(date,per){
	// day
	if(per.days !== 0){
		return moment(date).subtract(per.days,'days').startOf('day').toDate();
	}
	// start of week: Sunday
	if(per.weeks !== 0){
		 return moment(date).subtract(per.weeks,'weeks').startOf("week").toDate();
	}
	// start of month
	if(per.months !== 0){
		var month = 0;
		while(month < date.getMonth()){
			month += per.months;
		}
		month -= per.months;
		return new Date(date.getFullYear(),month,1);
	}
	// start of year
	if(per.months !== 0){
		return new Date(date.getFullYear(),0,1);
	}
};

var sameDoP = function(dop1,dop2){
	var b1 = dop1 instanceof Date;
	var b2 = dop2 instanceof Date;
	if(b1 !== b2){
		return null;
	}

	return (b1)?'date':'period';
};

var dateGT = function(d1,d2){
	return d1.getTime() > d2.getTime();
};

var dateLT = function(d1,d2){
	return d1.getTime() < d2.getTime();
};

var periodGT = function(p1,p2){
	return p1.total > p2.total;
};

var periodLT = function(p1,p2){
	return p1.total < p2.total;
};

var greaterThan = function(v1,v2,type){
	return (type === 'date')?dateGT(v1,v2):periodGT(v1,v2);
};

var lowerThan = function(v1,v2,type){
	return (type === 'date')?dateLT(v1,v2):periodLT(v1,v2);
};

var addPer = function(p1,p2){
	p1 = processPeriod(p1);
	return makePeriod(moment.duration(p1).add(moment.duration(p2)));
};

var subPer = function(p1,p2){
	p1 = processPeriod(p1);
	return makePeriod(moment.duration(p1).subtract(moment.duration(p2)));
};

var m = {};

// date / distance methods
m.orderMag = function(dop){
	var ms = (dop instanceof Date) ? dop.getTime() : moment.duration({days: processPeriod(dop).total}).asMilliseconds();

	return floor( log(ms) / LN10);
};

m.orderMagValue = function(last,first){
	// start of next year
	var nextfst = new Date(first.getFullYear() + 1,0,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next semester
	if(first.getMonth() < 7){
		nextfst = new Date(first.getFullYear(),7,1);
		if(m.lowerThan(nextfst,last)){
			return nextfst;
		}
	}

	// start of next trimester
	var mm = first.getMonth() + 3 - first.getMonth() % 3;
	nextfst = new Date(first.getFullYear(),mm,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next month
	nextfst = new Date(first.getFullYear(),first.getMonth() + 1,1);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// start of next half-month
	if(first.getDate() < 15){
		nextfst = new Date(first.getFullYear(),first.getMonth(),15);
		if(m.lowerThan(nextfst,last)){
			return nextfst;
		}
	}

	// start of next quarter-month (as 7 days)
	var dd = first.getDate() + 7 - first.getDate() % 7;
	nextfst = new Date(first.getFullYear(),first.getMonth(),dd);
	if(m.lowerThan(nextfst,last)){
		return nextfst;
	}

	// next day
	return new Date(first.getFullYear(),first.getMonth(),first.getDate() + 1);
};

m.orderMagDist = function(r){
	return makePeriod(pow(10,m.orderMag(r)));
};

m.roundUp = function(p){
	return roundPeriod(p,'up');
};

m.roundDown = function(p){
	return roundPeriod(p,'down');
};

m.multiply = function(p,f){
	return makePeriod(moment.duration({days: processPeriod(p).total * f}));
};

m.divide = function(p,f){
	return makePeriod(moment.duration({days: processPeriod(p).total / f}));
};

m.increase = function(p1,p2){
	return makePeriod(moment.duration({days: processPeriod(p1).total + processPeriod(p2).total}));
};

m.offset = function(p){
	p = processPeriod(p);

	var offsetMe = (per) => {
		if(per.years !== 0){
			return makePeriod(moment.duration({months: 6}));
		}else{
			return m.divide(p,2);
		}
	};

	return (p.offset )? offsetMe(p) : makePeriod(0) ;
};

// date methods
m.closestRoundUp = function(ref,per){
	return closestUp(ref, roundPeriod(per) );
};

m.closestRoundDown = function(ref,per){
	return closestDown(ref, roundPeriod(per) );
};

m.closestRound = function(ref,om,type){
	return (type === 'up')? m.closestRoundUp(ref,om):m.closestRoundDown(ref,om);
};

m.min = function(dates){
	return new Date(min.apply(null,_.map(dates, (date) => {return date.getTime();})));
};

m.max = function(dates){
	return new Date(max.apply(null,_.map(dates, (date) => {return date.getTime();})));
};

m.label = function(date,period){
	var format = fetchFormat(period);
	var out = '';
	if(format.pref === 'S'){
		out = (date.getMonth() > 5)? '2/' : '1/';
		out += moment(date).format('YY');
	}else{
		out = moment(date).format(format.string);
	}
	return format.pref + out;
};

// date & period methods
m.add = function(dop,p){
	// preprocess period
	p = processPeriod(p);

	return (dop instanceof Date) ? moment(dop)
		.add(p.years,'years')
		.add(p.months,'months')
		.add(p.weeks,'weeks')
		.add(p.days,'days').toDate():
		addPer(dop,p);
};

m.subtract = function(dop,p){
	// preprocess period
	p = processPeriod(p);

	return (dop instanceof Date) ? moment(dop)
		.subtract(p.years,'years')
		.subtract(p.months,'months')
		.subtract(p.weeks,'weeks')
		.subtract(p.days,'days').toDate():
		subPer(dop,p);
};

m.distance = function(d1,d2){
	return makePeriod(abs(d1.getTime() - d2.getTime()));
};

m.greaterThan = function(dop1,dop2){
	var sd = sameDoP(dop1,dop2);
	if(sd === null){
		throw 'Error in dateMgr: trying to compare a Date with a Period';
	}
	return greaterThan(dop1,dop2,sd);
};

m.lowerThan = function(dop1,dop2){
	var sd = sameDoP(dop1,dop2);
	if(sd === null){
		throw 'Error in dateMgr: trying to compare a Date with a Period';
	}
	return lowerThan(dop1,dop2,sd);
};

// managements
m.getValue = function(dop){
	return (dop instanceof Date) ? dop.getTime() : moment.duration(dop).asMilliseconds();
};

m.extraTicks = function(step,start,end){
	var out = [];
	var startYear = start.getFullYear();
	var lastYear = end.getFullYear();
	// every year, whatever happens
	for(var ye = startYear; ye <= lastYear; ye++){
		var dat = new Date(ye,0,1);
		if(m.lowerThan(start,dat) && m.lowerThan(dat,end)){
			out.push({
				position: dat,
				offset: {
					along: 0,
					perp: 0
				},
				label: '',
				show: false,
				extra: true,
				grid: {
					show: true,
					color: 'LightGray',
					width: 0.5
				}
			});
		}
	}
	return out;
};

m.smallestStep = function(){
	return makePeriod(moment.duration({days: 1}));
};

m.makePeriod = function(per){
	return processPeriod(per);
};

// in years
m.value = function(num){
	return new Date(num * 1000 * 3600 * 24 * 365);
};

// in years
m.step = function(num){
	return makePeriod({years: num});
};

module.exports = m;
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const { remote } = require('electron')
const { app } = remote

const getChromeStoragePath = (storageType, extensionId) => {
  return path.join(
    app.getPath('userData'), `/Chrome Storage/${extensionId}-${storageType}.json`)
}
const readChromeStorageFile = (storageType, extensionId) => {
  const filePath = getChromeStoragePath(storageType, extensionId)
  if (!fs.existsSync(filePath)) return null
  return fs.readFileSync(filePath, 'utf8')
}

const writeChromeStorageFile = (storageType, extensionId, data) => {
  const filePath = getChromeStoragePath(storageType, extensionId)
  try {
    fs.mkdirSync(path.dirname(filePath))
  } catch (error) {
    // Ignore error
  }
  return fs.writeFileSync(filePath, data)
}

const getStorage = (storageType, extensionId) => {
  const data = readChromeStorageFile(storageType, extensionId)
  if (data != null) {
    return JSON.parse(data)
  } else {
    return {}
  }
}

const setStorage = (storageType, extensionId, storage) => {
  const json = JSON.stringify(storage)
  writeChromeStorageFile(storageType, extensionId, json)
}

const scheduleCallback = (items, callback) => {
  setTimeout(function () {
    callback(items)
  })
}

const getStorageManager = (storageType, extensionId) => {
  return {
    get (keys, callback) {
      const storage = getStorage(storageType, extensionId)
      if (keys == null) return scheduleCallback(storage, callback)

      let defaults = {}
      switch (typeof keys) {
        case 'string':
          keys = [keys]
          break
        case 'object':
          if (!Array.isArray(keys)) {
            defaults = keys
            keys = Object.keys(keys)
          }
          break
      }
      if (keys.length === 0) return scheduleCallback({}, callback)

      let items = {}
      keys.forEach(function (key) {
        var value = storage[key]
        if (value == null) value = defaults[key]
        items[key] = value
      })
      scheduleCallback(items, callback)
    },

    set (items, callback) {
      const storage = getStorage(storageType, extensionId)

      Object.keys(items).forEach(function (name) {
        storage[name] = items[name]
      })

      setStorage(storageType, extensionId, storage)

      setTimeout(callback)
    },

    remove (keys, callback) {
      const storage = getStorage(storageType, extensionId)

      if (!Array.isArray(keys)) {
        keys = [keys]
      }
      keys.forEach(function (key) {
        delete storage[key]
      })

      setStorage(storageType, extensionId, storage)

      setTimeout(callback)
    },

    clear (callback) {
      setStorage(storageType, extensionId, {})

      setTimeout(callback)
    }
  }
}

module.exports = {
  setup: extensionId => ({
    sync: getStorageManager('sync', extensionId),
    local: getStorageManager('local', extensionId)
  })
}
<commit_msg>Change storage implementation to async<commit_after>const fs = require('fs')
const path = require('path')
const { remote } = require('electron')
const { app } = remote

const getChromeStoragePath = (storageType, extensionId) => {
  return path.join(
    app.getPath('userData'), `/Chrome Storage/${extensionId}-${storageType}.json`)
}

const readChromeStorageFile = (storageType, extensionId, cb) => {
  const filePath = getChromeStoragePath(storageType, extensionId)
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err && err.code === 'ENOENT') {
      return cb(null, null)
    }
    cb(err, data)
  })
}

const writeChromeStorageFile = (storageType, extensionId, data, cb) => {
  const filePath = getChromeStoragePath(storageType, extensionId)

  fs.mkdir(path.dirname(filePath), err => {
    if (err) { /* we just ignore the errors of mkdir */ }
    fs.writeFile(filePath, data, cb)
  })
}

const getStorage = (storageType, extensionId, cb) => {
  readChromeStorageFile(storageType, extensionId, (err, data) => {
    if (err) throw err
    if (!cb) throw new TypeError('No callback provided')

    if (data !== null) {
      cb(JSON.parse(data))
    } else {
      cb({})
    }
  })
}

const setStorage = (storageType, extensionId, storage, cb) => {
  const json = JSON.stringify(storage)
  writeChromeStorageFile(storageType, extensionId, json, err => {
    if (err) throw err
    if (cb) cb()
  })
}

const getStorageManager = (storageType, extensionId) => {
  return {
    get (keys, callback) {
      getStorage(storageType, extensionId, storage => {
        if (keys == null) return callback(storage)

        let defaults = {}
        switch (typeof keys) {
          case 'string':
            keys = [keys]
            break
          case 'object':
            if (!Array.isArray(keys)) {
              defaults = keys
              keys = Object.keys(keys)
            }
            break
        }
        if (keys.length === 0) return callback({})

        let items = {}
        keys.forEach(function (key) {
          var value = storage[key]
          if (value == null) value = defaults[key]
          items[key] = value
        })
        callback(items)
      })
    },

    set (items, callback) {
      getStorage(storageType, extensionId, storage => {
        Object.keys(items).forEach(function (name) {
          storage[name] = items[name]
        })

        setStorage(storageType, extensionId, storage, callback)
      })
    },

    remove (keys, callback) {
      getStorage(storageType, extensionId, storage => {
        if (!Array.isArray(keys)) {
          keys = [keys]
        }
        keys.forEach(function (key) {
          delete storage[key]
        })

        setStorage(storageType, extensionId, storage, callback)
      })
    },

    clear (callback) {
      setStorage(storageType, extensionId, {}, callback)
    }
  }
}

module.exports = {
  setup: extensionId => ({
    sync: getStorageManager('sync', extensionId),
    local: getStorageManager('local', extensionId)
  })
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 resin.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * This work is heavily based on https://github.com/raspberrypi/usbboot
 * Copyright 2016 Raspberry Pi Foundation
 */

'use strict'

const _ = require('lodash')
const Bluebird = require('bluebird')
const usb = require('./usb')

// The equivalent of a NULL buffer, given that node-usb complains
// if the data argument is not an instance of Buffer
const NULL_BUFFER_SIZE = 0
const NULL_BUFFER = Buffer.alloc(NULL_BUFFER_SIZE)

/**
 * @summary The size of the boot message bootcode length section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_BOOTCODE_LENGTH_SIZE = 4

/**
 * @summary The offset of the boot message bootcode length section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_BOOTCODE_LENGTH_OFFSET = 0

/**
 * @summary The size of the boot message signature section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_SIGNATURE_SIZE = 20

/**
 * @summary The offset of the file message command section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_COMMAND_OFFSET = 0

/**
 * @summary The size of the file message command section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_COMMAND_SIZE = 4

/**
 * @summary The offset of the file message file name section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_FILE_NAME_OFFSET = FILE_MESSAGE_COMMAND_SIZE

/**
 * @summary The size of the file message file name section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_FILE_NAME_SIZE = 256

/**
 * @summary The GET_STATUS usb control transfer request code
 * @type {Number}
 * @constant
 * @description
 * See http://www.jungo.com/st/support/documentation/windriver/811/wdusb_man_mhtml/node55.html#usb_standard_dev_req_codes
 */
const USB_REQUEST_CODE_GET_STATUS = 0

/**
 * @summary The maximum buffer length of a usbboot message
 * @type {Number}
 * @constant
 */
const USBBOOT_MESSAGE_MAX_BUFFER_LENGTH = 0xffff

/**
 * @summary The delay to wait between each USB read/write operation
 * @type {Number}
 * @constant
 * @description
 * The USB bus seems to hang if we execute many operations at
 * the same time.
 */
const USB_REQUEST_DELAY_MS = 1000

/**
 * @summary The timeout for USB bulk transfers, in milliseconds
 * @type {Number}
 * @constant
 */
const USB_BULK_TRANSFER_TIMEOUT_MS = 1000

/**
 * @summary The amount of bits to shift to the right on a control transfer index
 * @type {Number}
 * @constant
 */
const CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT = 16

/**
 * @summary The size of the usbboot file message
 * @type {Number}
 * @constant
 */
exports.FILE_MESSAGE_SIZE = FILE_MESSAGE_COMMAND_SIZE + FILE_MESSAGE_FILE_NAME_SIZE

/**
 * @summary File message command display names
 * @namespace FILE_MESSAGE_COMMANDS
 * @public
 */
exports.FILE_MESSAGE_COMMANDS = {

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "get file size" file message command name.
   */
  GET_FILE_SIZE: 'GetFileSize',

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "read file" file message command name.
   */
  READ_FILE: 'ReadFile',

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "done" file message command name.
   */
  DONE: 'Done'
}

/**
 * @summary The usbboot return code that represents success
 * @type {Number}
 * @constant
 */
exports.RETURN_CODE_SUCCESS = 0

/**
 * @summary The buffer length of the return code message
 * @type {Number}
 * @constant
 */
exports.RETURN_CODE_LENGTH = 4

/**
 * @summary Send a buffer size to a device as a control transfer
 * @function
 * @public
 *
 * @param {Object} device - node-usb device
 * @param {Number} size - buffer size
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * protocol.sendBufferSize(device, 512).then(() => {
 *   console.log('Done!')
 * })
 */
exports.sendBufferSize = (device, size) => {
  return usb.performControlTransfer(device, {
    bmRequestType: usb.LIBUSB_REQUEST_TYPE_VENDOR,
    bRequest: USB_REQUEST_CODE_GET_STATUS,
    data: NULL_BUFFER,

    /* eslint-disable no-bitwise */
    wValue: size & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH,
    wIndex: size >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT
    /* eslint-enable no-bitwise */
  })
}

/**
 * @summary Write a buffer to an OUT endpoint
 * @function
 * @private
 *
 * @param {Object} device - device
 * @param {Object} endpoint - endpoint
 * @param {Buffer} buffer - buffer
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 * return protocol.write(device, device.interface(0).endpoint(1), Buffer.alloc(1)).then(() => {
 *   console.log('Done!')
 * })
 */
exports.write = (device, endpoint, buffer) => {
  return exports.sendBufferSize(device, buffer.length)

    // We get LIBUSB_TRANSFER_STALL sometimes
    // in future bulk transfers without this
    .delay(USB_REQUEST_DELAY_MS)

    .then(() => {
      return Bluebird.fromCallback((callback) => {
        endpoint.timeout = USB_BULK_TRANSFER_TIMEOUT_MS
        endpoint.transfer(buffer, callback)
      })
    })
}

/**
 * @summary Send an error signal to a device
 * @function
 * @public
 *
 * @param {Object} device - node-usb device
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * protocol.sendErrorSignal(device).then(() => {
 *   console.log('Done!')
 * })
 */
exports.sendErrorSignal = (device) => {
  return exports.sendBufferSize(device, NULL_BUFFER_SIZE)
}

/**
 * @summary Read a buffer from a device
 * @function
 * @private
 *
 * @param {Object} device - device
 * @param {Number} bytesToRead - bytes to read
 * @fulfil {Buffer} - data
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 * protocol.read(device, 4).then((data) => {
 *   console.log(data.readInt32BE())
 * })
 */
exports.read = (device, bytesToRead) => {
  return usb.performControlTransfer(device, {
    /* eslint-disable no-bitwise */
    bmRequestType: usb.LIBUSB_REQUEST_TYPE_VENDOR | usb.LIBUSB_ENDPOINT_IN,
    wValue: bytesToRead & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH,
    wIndex: bytesToRead >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT,
    /* eslint-enable no-bitwise */

    bRequest: USB_REQUEST_CODE_GET_STATUS,
    length: bytesToRead
  })
}

/**
 * @summary Create a boot message buffer
 * @function
 * @private
 *
 * @description
 * This is based on the following data structure:
 *
 * typedef struct MESSAGE_S {
 *   int length;
 *   unsigned char signature[20];
 * } boot_message_t;
 *
 * This needs to be sent to the out endpoint of the USB device
 * as a 24 bytes big-endian buffer where:
 *
 * - The first 4 bytes contain the size of the bootcode.bin buffer
 * - The remaining 20 bytes contain the boot signature, which
 *   we don't make use of in this implementation
 *
 * @param {Number} bootCodeBufferLength - bootcode.bin buffer length
 * @returns {Buffer} boot message buffer
 *
 * @example
 * const bootMessageBuffer = protocol.createBootMessageBuffer(50216)
 */
exports.createBootMessageBuffer = (bootCodeBufferLength) => {
  const bootMessageBufferSize = BOOT_MESSAGE_BOOTCODE_LENGTH_SIZE + BOOT_MESSAGE_SIGNATURE_SIZE

  // Buffers are automatically filled with zero bytes
  const bootMessageBuffer = Buffer.alloc(bootMessageBufferSize)

  // The bootcode length should be stored in 4 big-endian bytes
  bootMessageBuffer.writeInt32BE(bootCodeBufferLength, BOOT_MESSAGE_BOOTCODE_LENGTH_OFFSET)

  return bootMessageBuffer
}

/**
 * @summary Parse a file message buffer from a device
 * @function
 * @public
 *
 * @param {Buffer} fileMessageBuffer - file message buffer
 * @returns {Object} parsed file message
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * return protocol.read(device, protocol.FILE_MESSAGE_SIZE).then((fileMessageBuffer) => {
 *   return protocol.parseFileMessageBuffer(fileMessageBuffer)
 * }).then((fileMessage) => {
 *   console.log(fileMessage.command)
 *   console.log(fileMessage.fileName)
 * })
 */
exports.parseFileMessageBuffer = (fileMessageBuffer) => {
  const commandCode = fileMessageBuffer.readInt32LE(FILE_MESSAGE_COMMAND_OFFSET)
  const command = _.nth([
    exports.FILE_MESSAGE_COMMANDS.GET_FILE_SIZE,
    exports.FILE_MESSAGE_COMMANDS.READ_FILE,
    exports.FILE_MESSAGE_COMMANDS.DONE
  ], commandCode)

  if (_.isNil(command)) {
    throw new Error(`Invalid file message command code: ${commandCode}`)
  }

  const fileName = _.chain(fileMessageBuffer.toString('ascii', FILE_MESSAGE_FILE_NAME_OFFSET))

    // The parsed string will likely contain tons of trailing
    // null bytes that we should get rid of for convenience
    // See https://github.com/nodejs/node/issues/4775
    .takeWhile((character) => {
      return character !== '\0'
    })
    .join('')
    .value()

  // A blank file name can also mean "done"
  if (_.isEmpty(fileName)) {
    return {
      command: exports.FILE_MESSAGE_COMMANDS.DONE
    }
  }

  return {
    command,
    fileName
  }
}
<commit_msg>fix(sdk): increase bulk transfer usb timeouts (#1759)<commit_after>/*
 * Copyright 2017 resin.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * This work is heavily based on https://github.com/raspberrypi/usbboot
 * Copyright 2016 Raspberry Pi Foundation
 */

'use strict'

const _ = require('lodash')
const Bluebird = require('bluebird')
const usb = require('./usb')

// The equivalent of a NULL buffer, given that node-usb complains
// if the data argument is not an instance of Buffer
const NULL_BUFFER_SIZE = 0
const NULL_BUFFER = Buffer.alloc(NULL_BUFFER_SIZE)

/**
 * @summary The size of the boot message bootcode length section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_BOOTCODE_LENGTH_SIZE = 4

/**
 * @summary The offset of the boot message bootcode length section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_BOOTCODE_LENGTH_OFFSET = 0

/**
 * @summary The size of the boot message signature section
 * @type {Number}
 * @constant
 */
const BOOT_MESSAGE_SIGNATURE_SIZE = 20

/**
 * @summary The offset of the file message command section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_COMMAND_OFFSET = 0

/**
 * @summary The size of the file message command section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_COMMAND_SIZE = 4

/**
 * @summary The offset of the file message file name section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_FILE_NAME_OFFSET = FILE_MESSAGE_COMMAND_SIZE

/**
 * @summary The size of the file message file name section
 * @type {Number}
 * @constant
 */
const FILE_MESSAGE_FILE_NAME_SIZE = 256

/**
 * @summary The GET_STATUS usb control transfer request code
 * @type {Number}
 * @constant
 * @description
 * See http://www.jungo.com/st/support/documentation/windriver/811/wdusb_man_mhtml/node55.html#usb_standard_dev_req_codes
 */
const USB_REQUEST_CODE_GET_STATUS = 0

/**
 * @summary The maximum buffer length of a usbboot message
 * @type {Number}
 * @constant
 */
const USBBOOT_MESSAGE_MAX_BUFFER_LENGTH = 0xffff

/**
 * @summary The delay to wait between each USB read/write operation
 * @type {Number}
 * @constant
 * @description
 * The USB bus seems to hang if we execute many operations at
 * the same time.
 */
const USB_REQUEST_DELAY_MS = 1000

/**
 * @summary The timeout for USB bulk transfers, in milliseconds
 * @type {Number}
 * @constant
 */
// In node-usb, 0 means "infinite" timeout
const USB_BULK_TRANSFER_TIMEOUT_MS = 0

/**
 * @summary The amount of bits to shift to the right on a control transfer index
 * @type {Number}
 * @constant
 */
const CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT = 16

/**
 * @summary The size of the usbboot file message
 * @type {Number}
 * @constant
 */
exports.FILE_MESSAGE_SIZE = FILE_MESSAGE_COMMAND_SIZE + FILE_MESSAGE_FILE_NAME_SIZE

/**
 * @summary File message command display names
 * @namespace FILE_MESSAGE_COMMANDS
 * @public
 */
exports.FILE_MESSAGE_COMMANDS = {

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "get file size" file message command name.
   */
  GET_FILE_SIZE: 'GetFileSize',

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "read file" file message command name.
   */
  READ_FILE: 'ReadFile',

  /**
   * @property {String}
   * @memberof FILE_MESSAGE_COMMANDS
   *
   * @description
   * The "done" file message command name.
   */
  DONE: 'Done'
}

/**
 * @summary The usbboot return code that represents success
 * @type {Number}
 * @constant
 */
exports.RETURN_CODE_SUCCESS = 0

/**
 * @summary The buffer length of the return code message
 * @type {Number}
 * @constant
 */
exports.RETURN_CODE_LENGTH = 4

/**
 * @summary Send a buffer size to a device as a control transfer
 * @function
 * @public
 *
 * @param {Object} device - node-usb device
 * @param {Number} size - buffer size
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * protocol.sendBufferSize(device, 512).then(() => {
 *   console.log('Done!')
 * })
 */
exports.sendBufferSize = (device, size) => {
  return usb.performControlTransfer(device, {
    bmRequestType: usb.LIBUSB_REQUEST_TYPE_VENDOR,
    bRequest: USB_REQUEST_CODE_GET_STATUS,
    data: NULL_BUFFER,

    /* eslint-disable no-bitwise */
    wValue: size & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH,
    wIndex: size >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT
    /* eslint-enable no-bitwise */
  })
}

/**
 * @summary Write a buffer to an OUT endpoint
 * @function
 * @private
 *
 * @param {Object} device - device
 * @param {Object} endpoint - endpoint
 * @param {Buffer} buffer - buffer
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 * return protocol.write(device, device.interface(0).endpoint(1), Buffer.alloc(1)).then(() => {
 *   console.log('Done!')
 * })
 */
exports.write = (device, endpoint, buffer) => {
  return exports.sendBufferSize(device, buffer.length)

    // We get LIBUSB_TRANSFER_STALL sometimes
    // in future bulk transfers without this
    .delay(USB_REQUEST_DELAY_MS)

    .then(() => {
      return Bluebird.fromCallback((callback) => {
        endpoint.timeout = USB_BULK_TRANSFER_TIMEOUT_MS
        endpoint.transfer(buffer, callback)
      })
    })
}

/**
 * @summary Send an error signal to a device
 * @function
 * @public
 *
 * @param {Object} device - node-usb device
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * protocol.sendErrorSignal(device).then(() => {
 *   console.log('Done!')
 * })
 */
exports.sendErrorSignal = (device) => {
  return exports.sendBufferSize(device, NULL_BUFFER_SIZE)
}

/**
 * @summary Read a buffer from a device
 * @function
 * @private
 *
 * @param {Object} device - device
 * @param {Number} bytesToRead - bytes to read
 * @fulfil {Buffer} - data
 * @returns {Promise}
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 * protocol.read(device, 4).then((data) => {
 *   console.log(data.readInt32BE())
 * })
 */
exports.read = (device, bytesToRead) => {
  return usb.performControlTransfer(device, {
    /* eslint-disable no-bitwise */
    bmRequestType: usb.LIBUSB_REQUEST_TYPE_VENDOR | usb.LIBUSB_ENDPOINT_IN,
    wValue: bytesToRead & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH,
    wIndex: bytesToRead >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT,
    /* eslint-enable no-bitwise */

    bRequest: USB_REQUEST_CODE_GET_STATUS,
    length: bytesToRead
  })
}

/**
 * @summary Create a boot message buffer
 * @function
 * @private
 *
 * @description
 * This is based on the following data structure:
 *
 * typedef struct MESSAGE_S {
 *   int length;
 *   unsigned char signature[20];
 * } boot_message_t;
 *
 * This needs to be sent to the out endpoint of the USB device
 * as a 24 bytes big-endian buffer where:
 *
 * - The first 4 bytes contain the size of the bootcode.bin buffer
 * - The remaining 20 bytes contain the boot signature, which
 *   we don't make use of in this implementation
 *
 * @param {Number} bootCodeBufferLength - bootcode.bin buffer length
 * @returns {Buffer} boot message buffer
 *
 * @example
 * const bootMessageBuffer = protocol.createBootMessageBuffer(50216)
 */
exports.createBootMessageBuffer = (bootCodeBufferLength) => {
  const bootMessageBufferSize = BOOT_MESSAGE_BOOTCODE_LENGTH_SIZE + BOOT_MESSAGE_SIGNATURE_SIZE

  // Buffers are automatically filled with zero bytes
  const bootMessageBuffer = Buffer.alloc(bootMessageBufferSize)

  // The bootcode length should be stored in 4 big-endian bytes
  bootMessageBuffer.writeInt32BE(bootCodeBufferLength, BOOT_MESSAGE_BOOTCODE_LENGTH_OFFSET)

  return bootMessageBuffer
}

/**
 * @summary Parse a file message buffer from a device
 * @function
 * @public
 *
 * @param {Buffer} fileMessageBuffer - file message buffer
 * @returns {Object} parsed file message
 *
 * @example
 * const usb = require('usb')
 * const device = usb.findByIds(0x0a5c, 0x2763)
 *
 * return protocol.read(device, protocol.FILE_MESSAGE_SIZE).then((fileMessageBuffer) => {
 *   return protocol.parseFileMessageBuffer(fileMessageBuffer)
 * }).then((fileMessage) => {
 *   console.log(fileMessage.command)
 *   console.log(fileMessage.fileName)
 * })
 */
exports.parseFileMessageBuffer = (fileMessageBuffer) => {
  const commandCode = fileMessageBuffer.readInt32LE(FILE_MESSAGE_COMMAND_OFFSET)
  const command = _.nth([
    exports.FILE_MESSAGE_COMMANDS.GET_FILE_SIZE,
    exports.FILE_MESSAGE_COMMANDS.READ_FILE,
    exports.FILE_MESSAGE_COMMANDS.DONE
  ], commandCode)

  if (_.isNil(command)) {
    throw new Error(`Invalid file message command code: ${commandCode}`)
  }

  const fileName = _.chain(fileMessageBuffer.toString('ascii', FILE_MESSAGE_FILE_NAME_OFFSET))

    // The parsed string will likely contain tons of trailing
    // null bytes that we should get rid of for convenience
    // See https://github.com/nodejs/node/issues/4775
    .takeWhile((character) => {
      return character !== '\0'
    })
    .join('')
    .value()

  // A blank file name can also mean "done"
  if (_.isEmpty(fileName)) {
    return {
      command: exports.FILE_MESSAGE_COMMANDS.DONE
    }
  }

  return {
    command,
    fileName
  }
}
<|endoftext|>


<commit_before>'use strict';
'browser-only';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var util = skit.platform.util;
var zest = skit.thirdparty.zest;

var ELEMENT_NODE_TYPE = 1;

var ElementWrapper = function(element) {
  this.element = element;
};

ElementWrapper.elementsFromHtml = function(html) {
  var div = document.createElement('div');
  div.innerHTML = html;
  return (new ElementWrapper(div)).children();
};

ElementWrapper.fromHtml = function(html) {
  return ElementWrapper.elementsFromHtml(html)[0];
};

ElementWrapper.prototype.children = function() {
  var filtered;
  if (this.element.children) {
    filtered = util.toArray(this.element.children);
  } else {
    filtered = util.filter(this.element.childNodes, function(node) {
      return node.nodeType == ELEMENT_NODE_TYPE;
    });
  }

  return util.map(filtered, function(element) {
    return new ElementWrapper(element);
  });
};

ElementWrapper.prototype.contains = function(otherEl) {
  var current = otherEl.element || otherEl;
  while (current) {
    if (current == this.element) {
      return true;
    }
    current = current.parentNode;
  }
  return false;
};

ElementWrapper.prototype.parent = function() {
  if (this.element.parentNode && this.element.parentNode.nodeType == ELEMENT_NODE_TYPE) {
    return new ElementWrapper(this.element.parentNode);
  }
  return null;
};

ElementWrapper.prototype.matches = function(selector) {
  return zest.matches(this.element, selector);
};

ElementWrapper.prototype.find = function(selector) {
  return util.map(zest(selector, this.element), function(el) {
    return new ElementWrapper(el);
  });
};

ElementWrapper.prototype.get = function(selector) {
  var found = this.find(selector);
  return found.length ? found[0] : null;
};

ElementWrapper.prototype.$ = ElementWrapper.prototype.find;

ElementWrapper.prototype.first = function(selector) {
  var children = this.children();
  return children.length ? children[0] : null;
};

ElementWrapper.prototype.up = function(selector) {
  var current = this;
  while (current && !current.matches(selector)) {
    current = current.parent();
  }
  return current;
};

ElementWrapper.prototype.remove = function() {
  this.element.parentNode.removeChild(this.element);
};

ElementWrapper.prototype.replaceWith = function(htmlOrElement) {
  var replacement;
  if (typeof htmlOrElement == 'string') {
    replacement = ElementWrapper.fromHtml(htmlOrElement).element;
  } else {
    replacement = htmlOrElement.element || htmlOrElement;
  }

  this.element.parentNode.insertBefore(replacement, this.element);
  this.element.parentNode.removeChild(this.element);
  this.element = replacement;
};

ElementWrapper.prototype.removeChildren = function() {
  for (var i = this.element.childNodes.length - 1; i >= 0; i--) {
    this.element.removeChild(this.element.childNodes[i]);
  }
};

ElementWrapper.prototype.replaceChildren = function(htmlOrElement, opt_withChildren) {
  var replacement;
  if (typeof htmlOrElement == 'string') {
    replacement = ElementWrapper.fromHtml(htmlOrElement).element;
  } else {
    replacement = htmlOrElement.element || htmlOrElement;
  }

  this.removeChildren();

  if (!opt_withChildren) {
    this.element.appendChild(replacement);
  } else {
    for (var i = 0, len = replacement.childNodes.length; i < len; i++) {
      var child = replacement.childNodes[0];
      replacement.removeChild(child);
      this.element.appendChild(child);
    }
  }
};

ElementWrapper.prototype.classes = function() {
  return util.trim(this.element.className).split(/\s+/);
};

ElementWrapper.prototype.hasClass = function(className) {
  var classes = this.classes();
  for (var i = 0; i < classes.length; i++) {
    if (classes[i] == className) {
      return true;
    }
  }
  return false;
};

ElementWrapper.prototype.addClass = function(className) {
  if (!this.hasClass(className)) {
    this.element.className = util.trim(this.element.className + ' ' + className);
  }
};

ElementWrapper.prototype.removeClass = function(classToRemove) {
  var classes = util.filter(this.classes(), function(className) {
    return className != classToRemove;
  });

  this.element.className = classes.join(' ');
};

ElementWrapper.prototype.toggleClass = function(className) {
  if (this.hasClass(className)) {
    this.removeClass(className);
  } else {
    this.addClass(className);
  }
};

ElementWrapper.prototype.getData = function(key) {
  if (this.element.dataset) {
    return this.element.dataset[util.camelCase(key)];
  }
  return this.element.getAttribute('data-' + key);
};

ElementWrapper.prototype.setData = function(key, value) {
  if (this.element.dataset) {
    this.element.dataset[util.camelCase(key)] = value;
  } else {
    this.element.setAttribute('data-' + key, value);
  }
};

ElementWrapper.prototype.getText = function() {
  if (typeof this.element.textContent !== 'undefined') {
    return this.element.textContent;
  } else if (typeof this.element.innerText !== 'undefined') {
    return this.element.innerText;
  } else {
    return this.element.innerHTML;
  }
};

ElementWrapper.prototype.setText = function(value) {
  this.element.innerHTML = util.escapeHtml(value);
};

ElementWrapper.prototype.value = function() {
  // TODO(Taylor): Implement for textareas.
  return this.element.value;
};

ElementWrapper.prototype.disable = function() {
  this.element.disabled = true;
};
ElementWrapper.prototype.enable = function() {
  this.element.disabled = false;
};

ElementWrapper.prototype.appendTo = function(toElement) {
  (toElement.element || toElement).appendChild(this.element);
};

ElementWrapper.prototype.append = function(htmlOrElement) {
  var elements;
  if (typeof htmlOrElement == 'string') {
    elements = ElementWrapper.elementsFromHtml(htmlOrElement);
  } else if (htmlOrElement.length) {
    elements = htmlOrElement;
  } else {
    elements = [htmlOrElement];
  }

  util.forEach(elements, function(element) {
    this.element.appendChild(element.element || element);
  }, this);
};

return ElementWrapper;
<commit_msg>Behave better with detached nodes.<commit_after>'use strict';
'browser-only';

/**
 * @license
 * (c) 2014 Cluster Labs, Inc. https://cluster.co/
 * License: MIT
 */

var util = skit.platform.util;
var zest = skit.thirdparty.zest;

var ELEMENT_NODE_TYPE = 1;

var ElementWrapper = function(element) {
  this.element = element;
};

ElementWrapper.elementsFromHtml = function(html) {
  var div = document.createElement('div');
  div.innerHTML = html;
  return (new ElementWrapper(div)).children();
};

ElementWrapper.fromHtml = function(html) {
  return ElementWrapper.elementsFromHtml(html)[0];
};

ElementWrapper.prototype.children = function() {
  var filtered;
  if (this.element.children) {
    filtered = util.toArray(this.element.children);
  } else {
    filtered = util.filter(this.element.childNodes, function(node) {
      return node.nodeType == ELEMENT_NODE_TYPE;
    });
  }

  return util.map(filtered, function(element) {
    return new ElementWrapper(element);
  });
};

ElementWrapper.prototype.contains = function(otherEl) {
  var current = otherEl.element || otherEl;
  while (current) {
    if (current == this.element) {
      return true;
    }
    current = current.parentNode;
  }
  return false;
};

ElementWrapper.prototype.parent = function() {
  if (this.element.parentNode && this.element.parentNode.nodeType == ELEMENT_NODE_TYPE) {
    return new ElementWrapper(this.element.parentNode);
  }
  return null;
};

ElementWrapper.prototype.matches = function(selector) {
  return zest.matches(this.element, selector);
};

ElementWrapper.prototype.find = function(selector) {
  return util.map(zest(selector, this.element), function(el) {
    return new ElementWrapper(el);
  });
};

ElementWrapper.prototype.get = function(selector) {
  var found = this.find(selector);
  return found.length ? found[0] : null;
};

ElementWrapper.prototype.$ = ElementWrapper.prototype.find;

ElementWrapper.prototype.first = function(selector) {
  var children = this.children();
  return children.length ? children[0] : null;
};

ElementWrapper.prototype.up = function(selector) {
  var current = this;
  while (current && !current.matches(selector)) {
    current = current.parent();
  }
  return current;
};

ElementWrapper.prototype.remove = function() {
  if (this.element.parentNode) {
    this.element.parentNode.removeChild(this.element);
  }
};

ElementWrapper.prototype.replaceWith = function(htmlOrElement) {
  var replacement;
  if (typeof htmlOrElement == 'string') {
    replacement = ElementWrapper.fromHtml(htmlOrElement).element;
  } else {
    replacement = htmlOrElement.element || htmlOrElement;
  }

  if (this.element.parentNode) {
    this.element.parentNode.insertBefore(replacement, this.element);
    this.element.parentNode.removeChild(this.element);
  }
  this.element = replacement;
};

ElementWrapper.prototype.removeChildren = function() {
  for (var i = this.element.childNodes.length - 1; i >= 0; i--) {
    this.element.removeChild(this.element.childNodes[i]);
  }
};

ElementWrapper.prototype.replaceChildren = function(htmlOrElement, opt_withChildren) {
  var replacement;
  if (typeof htmlOrElement == 'string') {
    replacement = ElementWrapper.fromHtml(htmlOrElement).element;
  } else {
    replacement = htmlOrElement.element || htmlOrElement;
  }

  this.removeChildren();

  if (!opt_withChildren) {
    this.element.appendChild(replacement);
  } else {
    for (var i = 0, len = replacement.childNodes.length; i < len; i++) {
      var child = replacement.childNodes[0];
      replacement.removeChild(child);
      this.element.appendChild(child);
    }
  }
};

ElementWrapper.prototype.classes = function() {
  return util.trim(this.element.className).split(/\s+/);
};

ElementWrapper.prototype.hasClass = function(className) {
  var classes = this.classes();
  for (var i = 0; i < classes.length; i++) {
    if (classes[i] == className) {
      return true;
    }
  }
  return false;
};

ElementWrapper.prototype.addClass = function(className) {
  if (!this.hasClass(className)) {
    this.element.className = util.trim(this.element.className + ' ' + className);
  }
};

ElementWrapper.prototype.removeClass = function(classToRemove) {
  var classes = util.filter(this.classes(), function(className) {
    return className != classToRemove;
  });

  this.element.className = classes.join(' ');
};

ElementWrapper.prototype.toggleClass = function(className) {
  if (this.hasClass(className)) {
    this.removeClass(className);
  } else {
    this.addClass(className);
  }
};

ElementWrapper.prototype.getData = function(key) {
  if (this.element.dataset) {
    return this.element.dataset[util.camelCase(key)];
  }
  return this.element.getAttribute('data-' + key);
};

ElementWrapper.prototype.setData = function(key, value) {
  if (this.element.dataset) {
    this.element.dataset[util.camelCase(key)] = value;
  } else {
    this.element.setAttribute('data-' + key, value);
  }
};

ElementWrapper.prototype.getText = function() {
  if (typeof this.element.textContent !== 'undefined') {
    return this.element.textContent;
  } else if (typeof this.element.innerText !== 'undefined') {
    return this.element.innerText;
  } else {
    return this.element.innerHTML;
  }
};

ElementWrapper.prototype.setText = function(value) {
  this.element.innerHTML = util.escapeHtml(value);
};

ElementWrapper.prototype.value = function() {
  // TODO(Taylor): Implement for textareas.
  return this.element.value;
};

ElementWrapper.prototype.disable = function() {
  this.element.disabled = true;
};
ElementWrapper.prototype.enable = function() {
  this.element.disabled = false;
};

ElementWrapper.prototype.appendTo = function(toElement) {
  (toElement.element || toElement).appendChild(this.element);
};

ElementWrapper.prototype.append = function(htmlOrElement) {
  var elements;
  if (typeof htmlOrElement == 'string') {
    elements = ElementWrapper.elementsFromHtml(htmlOrElement);
  } else if (htmlOrElement.length) {
    elements = htmlOrElement;
  } else {
    elements = [htmlOrElement];
  }

  util.forEach(elements, function(element) {
    this.element.appendChild(element.element || element);
  }, this);
};

return ElementWrapper;
<|endoftext|>


<commit_before>/**
 * This file is part of the NovaeCalc project.
 *
 * It is permitted to use, redistribute and/or modify this software
 * under the terms of the MIT License
 *
 * @author Felix Maier <maier.felix96@gmail.com>
 * @copyright (c) 2015 Felix Maier, @felixmaier
 *
 * You may not change or remove these lines
 *
 */

"use strict";

  /** Create Event Object */
  CORE.Event = {
    /** Save last mouse click to identify single and double clicks */
    lastMoseDown: 0,
    /** Save last clicked cell */
    lastMouseDownCell: {
      Letter: 0,
      Number: 0
    },
    /** Save latest action to prevent unnecessary grid redrawing */
    lastAction: {
      scrollY: false,
      scrollX: false
    }
  };

  /**
   * Initialize event listeners
   *
   * @method init
   * @static
   */
  CORE.Event.init = function() {

    /** Mobile platform */
    if (CORE.Settings.Mobile) {

      window.addEventListener("resize", CORE.Event.resize, false);

      window.addEventListener("touchstart", CORE.Event.mouseDown, false);

      window.addEventListener("touchend", CORE.Event.mouseUp, false);

      window.addEventListener("touchmove", CORE.Event.mouseWipe, false);

      window.addEventListener("mousewheel", CORE.Event.scroll, false);
      window.addEventListener("scroll", CORE.Event.scroll, false);

      window.addEventListener("keydown", CORE.Event.keyPress, false);

    /** Desktop */
    } else {

      window.addEventListener("resize", CORE.Event.resize, false);

      window.addEventListener("mousedown", CORE.Event.mouseDown, false);

      window.addEventListener("mouseup", CORE.Event.mouseUp, false);

      window.addEventListener("mousemove", CORE.Event.mouseWipe, false);

      window.addEventListener("mousewheel", CORE.Event.scroll, false);
      window.addEventListener("DOMMouseScroll", CORE.Event.scroll, false);

      window.addEventListener("keydown", CORE.Event.keyPress, false);

      window.addEventListener("keyup", CORE.Event.keyUp, false);

    }

  };

  /**
   * Listen for window resizing
   *
   * @method resize
   * @static
   */
  CORE.Event.resize = function () {

    CORE.Settings.Width = window.innerWidth;

    CORE.Settings.Height = window.innerHeight;

    CORE.Settings.Scroll.Vertical = CORE.$.calculateScrollAmount();

    CORE.Event.lastAction.scrollY = false;

    CORE.Grid.calculateGrid();

    CORE.Grid.generateCells();

    CORE.Grid.updateWidth("right");

    CORE.Awakener.reset();

    CORE.Awakener.evalLive();

    CORE.eval();

  };<commit_msg>Resizing bug fix<commit_after>/**
 * This file is part of the NovaeCalc project.
 *
 * It is permitted to use, redistribute and/or modify this software
 * under the terms of the MIT License
 *
 * @author Felix Maier <maier.felix96@gmail.com>
 * @copyright (c) 2015 Felix Maier, @felixmaier
 *
 * You may not change or remove these lines
 *
 */

"use strict";

  /** Create Event Object */
  CORE.Event = {
    /** Save last mouse click to identify single and double clicks */
    lastMoseDown: 0,
    /** Save last clicked cell */
    lastMouseDownCell: {
      Letter: 0,
      Number: 0
    },
    /** Save latest action to prevent unnecessary grid redrawing */
    lastAction: {
      scrollY: false,
      scrollX: false
    }
  };

  /**
   * Initialize event listeners
   *
   * @method init
   * @static
   */
  CORE.Event.init = function() {

    /** Mobile platform */
    if (CORE.Settings.Mobile) {

      window.addEventListener("resize", CORE.Event.resize, false);

      window.addEventListener("touchstart", CORE.Event.mouseDown, false);

      window.addEventListener("touchend", CORE.Event.mouseUp, false);

      window.addEventListener("touchmove", CORE.Event.mouseWipe, false);

      window.addEventListener("mousewheel", CORE.Event.scroll, false);
      window.addEventListener("scroll", CORE.Event.scroll, false);

      window.addEventListener("keydown", CORE.Event.keyPress, false);

    /** Desktop */
    } else {

      window.addEventListener("resize", CORE.Event.resize, false);

      window.addEventListener("mousedown", CORE.Event.mouseDown, false);

      window.addEventListener("mouseup", CORE.Event.mouseUp, false);

      window.addEventListener("mousemove", CORE.Event.mouseWipe, false);

      window.addEventListener("mousewheel", CORE.Event.scroll, false);
      window.addEventListener("DOMMouseScroll", CORE.Event.scroll, false);

      window.addEventListener("keydown", CORE.Event.keyPress, false);

      window.addEventListener("keyup", CORE.Event.keyUp, false);

    }

  };

  /**
   * Listen for window resizing
   *
   * @method resize
   * @static
   */
  CORE.Event.resize = function () {

    CORE.Settings.Width = window.innerWidth;

    CORE.Settings.Height = window.innerHeight;

    CORE.Settings.Scroll.OriginalVertical = CORE.Settings.Scroll.Vertical = CORE.$.calculateScrollAmount();

    CORE.Event.lastAction.scrollY = false;

    CORE.Grid.calculateGrid();

    CORE.Grid.generateCells();

    CORE.Grid.updateWidth("right");

    CORE.Awakener.reset();

    CORE.Awakener.evalLive();

    CORE.eval();

  };<|endoftext|>