<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { validate } = require("schema-utils");
const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json");
const { STAGE_ADVANCED } = require("../OptimizationStages");
const LazyBucketSortedSet = require("../util/LazyBucketSortedSet");
const { compareChunks } = require("../util/comparators");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */

/** @typedef {import("../../declarations/plugins/optimize/LimitChunkCountPlugin").LimitChunkCountPluginOptions} LimitChunkCountPluginOptions */

/**
 * @typedef {Object} ChunkCombination
 * @property {boolean} deleted this is set to true when combination was removed
 * @property {number} sizeDiff
 * @property {number} integratedSize
 * @property {Chunk} a
 * @property {Chunk} b
 * @property {number} aIdx
 * @property {number} bIdx
 * @property {number} aSize
 * @property {number} bSize
 */

const addToSetMap = (map, key, value) => {
	const set = map.get(key);
	if (set === undefined) {
		map.set(key, new Set([value]));
	} else {
		set.add(value);
	}
};

class LimitChunkCountPlugin {
	/**
	 * @param {LimitChunkCountPluginOptions=} options options object
	 */
	constructor(options) {
		validate(schema, options, {
			name: "Limit Chunk Count Plugin",
			baseDataPath: "options"
		});
		this.options = options;
	}

	/**
	 * @param {Compiler} compiler the webpack compiler
	 * @returns {void}
	 */
	apply(compiler) {
		const options = this.options;
		compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
			compilation.hooks.optimizeChunks.tap(
				{
					name: "LimitChunkCountPlugin",
					stage: STAGE_ADVANCED
				},
				chunks => {
					const chunkGraph = compilation.chunkGraph;
					const maxChunks = options.maxChunks;
					if (!maxChunks) return;
					if (maxChunks < 1) return;
					if (compilation.chunks.size <= maxChunks) return;

					let remainingChunksToMerge = compilation.chunks.size - maxChunks;

					// order chunks in a deterministic way
					const compareChunksWithGraph = compareChunks(chunkGraph);
					const orderedChunks = Array.from(chunks).sort(compareChunksWithGraph);

					// create a lazy sorted data structure to keep all combinations
					// this is large. Size = chunks * (chunks - 1) / 2
					// It uses a multi layer bucket sort plus normal sort in the last layer
					// It's also lazy so only accessed buckets are sorted
					const combinations = new LazyBucketSortedSet(
						// Layer 1: ordered by largest size benefit
						c => c.sizeDiff,
						(a, b) => b - a,
						// Layer 2: ordered by smallest combined size
						c => c.integratedSize,
						(a, b) => a - b,
						// Layer 3: ordered by position difference in orderedChunk (-> to be deterministic)
						c => c.bIdx - c.aIdx,
						(a, b) => a - b,
						// Layer 4: ordered by position in orderedChunk (-> to be deterministic)
						(a, b) => a.bIdx - b.bIdx
					);

					// we keep a mapping from chunk to all combinations
					// but this mapping is not kept up-to-date with deletions
					// so `deleted` flag need to be considered when iterating this
					/** @type {Map<Chunk, Set<ChunkCombination>>} */
					const combinationsByChunk = new Map();

					orderedChunks.forEach((b, bIdx) => {
						// create combination pairs with size and integrated size
						for (let aIdx = 0; aIdx < bIdx; aIdx++) {
							const a = orderedChunks[aIdx];
							// filter pairs that can not be integrated!
							if (!chunkGraph.canChunksBeIntegrated(a, b)) continue;

							const integratedSize = chunkGraph.getIntegratedChunksSize(
								a,
								b,
								options
							);

							const aSize = chunkGraph.getChunkSize(a, options);
							const bSize = chunkGraph.getChunkSize(b, options);
							const c = {
								deleted: false,
								sizeDiff: aSize + bSize - integratedSize,
								integratedSize,
								a,
								b,
								aIdx,
								bIdx,
								aSize,
								bSize
							};
							combinations.add(c);
							addToSetMap(combinationsByChunk, a, c);
							addToSetMap(combinationsByChunk, b, c);
						}
						return combinations;
					});

					// list of modified chunks during this run
					// combinations affected by this change are skipped to allow
					// further optimizations
					/** @type {Set<Chunk>} */
					const modifiedChunks = new Set();

					let changed = false;
					// eslint-disable-next-line no-constant-condition
					loop: while (true) {
						const combination = combinations.popFirst();
						if (combination === undefined) break;

						combination.deleted = true;
						const { a, b, integratedSize } = combination;

						// skip over pair when
						// one of the already merged chunks is a parent of one of the chunks
						if (modifiedChunks.size > 0) {
							const queue = new Set(a.groupsIterable);
							for (const group of b.groupsIterable) {
								queue.add(group);
							}
							for (const group of queue) {
								for (const mChunk of modifiedChunks) {
									if (mChunk !== a && mChunk !== b && mChunk.isInGroup(group)) {
										// This is a potential pair which needs recalculation
										// We can't do that now, but it merge before following pairs
										// so we leave space for it, and consider chunks as modified
										// just for the worse case
										remainingChunksToMerge--;
										if (remainingChunksToMerge <= 0) break loop;
										modifiedChunks.add(a);
										modifiedChunks.add(b);
										continue loop;
									}
								}
								for (const parent of group.parentsIterable) {
									queue.add(parent);
								}
							}
						}

						// merge the chunks
						if (a.integrate(b, "limit")) {
							compilation.chunks.delete(b);

							// flag chunk a as modified as further optimization are possible for all children here
							modifiedChunks.add(a);

							changed = true;
							remainingChunksToMerge--;
							if (remainingChunksToMerge <= 0) break;

							// Update all affected combinations
							// delete all combination with the removed chunk
							// we will use combinations with the kept chunk instead
							for (const combination of combinationsByChunk.get(a)) {
								if (combination.deleted) continue;
								combination.deleted = true;
								combinations.delete(combination);
							}

							// Update combinations with the kept chunk with new sizes
							for (const combination of combinationsByChunk.get(b)) {
								if (combination.deleted) continue;
								if (combination.a === b) {
									if (!chunkGraph.canChunksBeIntegrated(a, combination.b)) {
										combination.deleted = true;
										combinations.delete(combination);
										continue;
									}
									// Update size
									const newIntegratedSize = a.integratedSize(
										combination.b,
										options
									);
									const finishUpdate = combinations.startUpdate(combination);
									combination.a = a;
									combination.integratedSize = newIntegratedSize;
									combination.aSize = integratedSize;
									combination.sizeDiff =
										combination.bSize + integratedSize - newIntegratedSize;
									finishUpdate();
								} else if (combination.b === b) {
									if (!chunkGraph.canChunksBeIntegrated(combination.a, a)) {
										combination.deleted = true;
										combinations.delete(combination);
										continue;
									}
									// Update size
									const newIntegratedSize = combination.a.integratedSize(
										a,
										options
									);
									const finishUpdate = combinations.startUpdate(combination);
									combination.b = a;
									combination.integratedSize = newIntegratedSize;
									combination.bSize = integratedSize;
									combination.sizeDiff =
										integratedSize + combination.aSize - newIntegratedSize;
									finishUpdate();
								}
							}
							combinationsByChunk.set(a, combinationsByChunk.get(b));
							combinationsByChunk.delete(b);
						}
					}
					if (changed) return true;
				}
			);
		});
	}
}
module.exports = LimitChunkCountPlugin;
<commit_msg>Fix deprecation message for LimitChunkCountPlugin<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { validate } = require("schema-utils");
const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json");
const { STAGE_ADVANCED } = require("../OptimizationStages");
const LazyBucketSortedSet = require("../util/LazyBucketSortedSet");
const { compareChunks } = require("../util/comparators");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */

/** @typedef {import("../../declarations/plugins/optimize/LimitChunkCountPlugin").LimitChunkCountPluginOptions} LimitChunkCountPluginOptions */

/**
 * @typedef {Object} ChunkCombination
 * @property {boolean} deleted this is set to true when combination was removed
 * @property {number} sizeDiff
 * @property {number} integratedSize
 * @property {Chunk} a
 * @property {Chunk} b
 * @property {number} aIdx
 * @property {number} bIdx
 * @property {number} aSize
 * @property {number} bSize
 */

const addToSetMap = (map, key, value) => {
	const set = map.get(key);
	if (set === undefined) {
		map.set(key, new Set([value]));
	} else {
		set.add(value);
	}
};

class LimitChunkCountPlugin {
	/**
	 * @param {LimitChunkCountPluginOptions=} options options object
	 */
	constructor(options) {
		validate(schema, options, {
			name: "Limit Chunk Count Plugin",
			baseDataPath: "options"
		});
		this.options = options;
	}

	/**
	 * @param {Compiler} compiler the webpack compiler
	 * @returns {void}
	 */
	apply(compiler) {
		const options = this.options;
		compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
			compilation.hooks.optimizeChunks.tap(
				{
					name: "LimitChunkCountPlugin",
					stage: STAGE_ADVANCED
				},
				chunks => {
					const chunkGraph = compilation.chunkGraph;
					const maxChunks = options.maxChunks;
					if (!maxChunks) return;
					if (maxChunks < 1) return;
					if (compilation.chunks.size <= maxChunks) return;

					let remainingChunksToMerge = compilation.chunks.size - maxChunks;

					// order chunks in a deterministic way
					const compareChunksWithGraph = compareChunks(chunkGraph);
					const orderedChunks = Array.from(chunks).sort(compareChunksWithGraph);

					// create a lazy sorted data structure to keep all combinations
					// this is large. Size = chunks * (chunks - 1) / 2
					// It uses a multi layer bucket sort plus normal sort in the last layer
					// It's also lazy so only accessed buckets are sorted
					const combinations = new LazyBucketSortedSet(
						// Layer 1: ordered by largest size benefit
						c => c.sizeDiff,
						(a, b) => b - a,
						// Layer 2: ordered by smallest combined size
						c => c.integratedSize,
						(a, b) => a - b,
						// Layer 3: ordered by position difference in orderedChunk (-> to be deterministic)
						c => c.bIdx - c.aIdx,
						(a, b) => a - b,
						// Layer 4: ordered by position in orderedChunk (-> to be deterministic)
						(a, b) => a.bIdx - b.bIdx
					);

					// we keep a mapping from chunk to all combinations
					// but this mapping is not kept up-to-date with deletions
					// so `deleted` flag need to be considered when iterating this
					/** @type {Map<Chunk, Set<ChunkCombination>>} */
					const combinationsByChunk = new Map();

					orderedChunks.forEach((b, bIdx) => {
						// create combination pairs with size and integrated size
						for (let aIdx = 0; aIdx < bIdx; aIdx++) {
							const a = orderedChunks[aIdx];
							// filter pairs that can not be integrated!
							if (!chunkGraph.canChunksBeIntegrated(a, b)) continue;

							const integratedSize = chunkGraph.getIntegratedChunksSize(
								a,
								b,
								options
							);

							const aSize = chunkGraph.getChunkSize(a, options);
							const bSize = chunkGraph.getChunkSize(b, options);
							const c = {
								deleted: false,
								sizeDiff: aSize + bSize - integratedSize,
								integratedSize,
								a,
								b,
								aIdx,
								bIdx,
								aSize,
								bSize
							};
							combinations.add(c);
							addToSetMap(combinationsByChunk, a, c);
							addToSetMap(combinationsByChunk, b, c);
						}
						return combinations;
					});

					// list of modified chunks during this run
					// combinations affected by this change are skipped to allow
					// further optimizations
					/** @type {Set<Chunk>} */
					const modifiedChunks = new Set();

					let changed = false;
					// eslint-disable-next-line no-constant-condition
					loop: while (true) {
						const combination = combinations.popFirst();
						if (combination === undefined) break;

						combination.deleted = true;
						const { a, b, integratedSize } = combination;

						// skip over pair when
						// one of the already merged chunks is a parent of one of the chunks
						if (modifiedChunks.size > 0) {
							const queue = new Set(a.groupsIterable);
							for (const group of b.groupsIterable) {
								queue.add(group);
							}
							for (const group of queue) {
								for (const mChunk of modifiedChunks) {
									if (mChunk !== a && mChunk !== b && mChunk.isInGroup(group)) {
										// This is a potential pair which needs recalculation
										// We can't do that now, but it merge before following pairs
										// so we leave space for it, and consider chunks as modified
										// just for the worse case
										remainingChunksToMerge--;
										if (remainingChunksToMerge <= 0) break loop;
										modifiedChunks.add(a);
										modifiedChunks.add(b);
										continue loop;
									}
								}
								for (const parent of group.parentsIterable) {
									queue.add(parent);
								}
							}
						}

						// merge the chunks
						if (chunkGraph.canChunksBeIntegrated(a, b)) {
							chunkGraph.integrateChunks(a, b);
							compilation.chunks.delete(b);

							// flag chunk a as modified as further optimization are possible for all children here
							modifiedChunks.add(a);

							changed = true;
							remainingChunksToMerge--;
							if (remainingChunksToMerge <= 0) break;

							// Update all affected combinations
							// delete all combination with the removed chunk
							// we will use combinations with the kept chunk instead
							for (const combination of combinationsByChunk.get(a)) {
								if (combination.deleted) continue;
								combination.deleted = true;
								combinations.delete(combination);
							}

							// Update combinations with the kept chunk with new sizes
							for (const combination of combinationsByChunk.get(b)) {
								if (combination.deleted) continue;
								if (combination.a === b) {
									if (!chunkGraph.canChunksBeIntegrated(a, combination.b)) {
										combination.deleted = true;
										combinations.delete(combination);
										continue;
									}
									// Update size
									const newIntegratedSize = chunkGraph.getIntegratedChunksSize(
										a,
										combination.b,
										options
									);
									const finishUpdate = combinations.startUpdate(combination);
									combination.a = a;
									combination.integratedSize = newIntegratedSize;
									combination.aSize = integratedSize;
									combination.sizeDiff =
										combination.bSize + integratedSize - newIntegratedSize;
									finishUpdate();
								} else if (combination.b === b) {
									if (!chunkGraph.canChunksBeIntegrated(combination.a, a)) {
										combination.deleted = true;
										combinations.delete(combination);
										continue;
									}
									// Update size
									const newIntegratedSize = chunkGraph.getIntegratedChunksSize(
										combination.a,
										a,
										options
									);

									const finishUpdate = combinations.startUpdate(combination);
									combination.b = a;
									combination.integratedSize = newIntegratedSize;
									combination.bSize = integratedSize;
									combination.sizeDiff =
										integratedSize + combination.aSize - newIntegratedSize;
									finishUpdate();
								}
							}
							combinationsByChunk.set(a, combinationsByChunk.get(b));
							combinationsByChunk.delete(b);
						}
					}
					if (changed) return true;
				}
			);
		});
	}
}
module.exports = LimitChunkCountPlugin;
<|endoftext|>


<commit_before>const _ = require('lodash/fp')

const namespaces = {
  WALLETS: 'wallets',
  OPERATOR_INFO: 'operatorInfo',
  NOTIFICATIONS: 'notifications',
  LOCALE: 'locale',
  COMMISSIONS: 'commissions',
  RECEIPT: 'receipt',
  COIN_ATM_RADAR: 'coinAtmRadar',
  TERMS_CONDITIONS: 'termsConditions',
  CASH_OUT: 'cashOut',
  CASH_IN: 'cashIn',
  COMPLIANCE: 'compliance'
}

const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str)
const filter = namespace => _.pickBy((value, key) => _.startsWith(`${namespace}_`)(key))
const strip = key => _.mapKeys(stripl(`${key}_`))

const fromNamespace = _.curry((key, config) => _.compose(strip(key), filter(key))(config))

const getCommissions = (cryptoCode, deviceId, config) => {
  const commissions = fromNamespace(namespaces.COMMISSIONS)(config)
  const overrides = commissions.overrides

  if (_.isEmpty(overrides)) return _.omit('overrides', commissions)

  const specificFilter = it => it.machine === deviceId && _.includes(cryptoCode)(it.cryptoCurrencies)
  const specificAllCoinsFilter = it => it.machine === deviceId && _.includes('ALL_COINS')(it.cryptoCurrencies)
  const allMachinesFilter = it => it.machine === 'ALL_MACHINES' && _.includes(cryptoCode)(it.cryptoCurrencies)

  const specificOverrides = _.filter(specificFilter)(overrides)
  const specificAllCoinsOverrides = _.filter(specificAllCoinsFilter)(overrides)
  const allMachinesOverrides = _.filter(allMachinesFilter)(overrides)

  const priorityOrderOverrides = [
    commissions,
    ...allMachinesOverrides,
    ...specificAllCoinsOverrides,
    ...specificOverrides
  ]

  return _.omit('overrides', _.assignAll(priorityOrderOverrides))
}

const getLocale = (deviceId, it) => {
  const locale = fromNamespace(namespaces.LOCALE)(it)

  const filter = _.matches({ machine: deviceId })
  return _.omit('overrides', _.assignAll([locale, ..._.filter(filter)(locale.overrides)]))
}

const getGlobalLocale = it => getLocale(null, it)

const getWalletSettings = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.WALLETS))(it)
const getCashOut = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.CASH_OUT))(it)
const getOperatorInfo = fromNamespace(namespaces.OPERATOR_INFO)
const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR)
const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS)
const getReceipt = fromNamespace(namespaces.RECEIPT)
const getCompliance = fromNamespace(namespaces.COMPLIANCE)

const getAllCryptoCurrencies = (config) => {
  const locale = fromNamespace(namespaces.LOCALE)(config)
  const cryptos = locale.cryptoCurrencies
  const overridesCryptos = _.map(_.get('cryptoCurrencies'))(locale.overrides)
  return _.uniq(_.flatten([cryptos, ...overridesCryptos]))
}

const getNotifications = (cryptoCurrency, machine, config) => {
  const notifications = fromNamespace(namespaces.NOTIFICATIONS)(config)

  const smsSettings = fromNamespace('sms', notifications)
  const emailSettings = fromNamespace('email', notifications)
  const notificationCenterSettings = fromNamespace('notificationCenter', notifications)

  const notifNoOverrides = _.omit(['cryptoBalanceOverrides', 'fiatBalanceOverrides'], notifications)

  const findByCryptoCurrency = _.find(_.matches({ cryptoCurrency }))
  const findByMachine = _.find(_.matches({ machine }))

  const cryptoFields = ['cryptoHighBalance', 'cryptoLowBalance', 'highBalance', 'lowBalance']
  const fiatFields = ['fiatBalanceCassette1', 'fiatBalanceCassette2']

  const getCryptoSettings = _.compose(_.pick(cryptoFields), _.defaultTo(notifications), findByCryptoCurrency)
  const cryptoSettings = getCryptoSettings(notifications.cryptoBalanceOverrides)

  if (cryptoSettings.highBalance) {
    cryptoSettings['cryptoHighBalance'] = cryptoSettings.highBalance
    delete cryptoSettings.highBalance
  }

  if (cryptoSettings.lowBalance) {
    cryptoSettings['cryptoLowBalance'] = cryptoSettings.lowBalance
    delete cryptoSettings.lowBalance
  }

  const getFiatSettings = _.compose(_.pick(fiatFields), _.defaultTo(notifications), findByMachine)
  const fiatSettings = getFiatSettings(notifications.fiatBalanceOverrides)
  return { ...notifNoOverrides, sms: smsSettings, email: emailSettings, ...cryptoSettings, ...fiatSettings, notificationCenter: notificationCenterSettings }
}

const getGlobalNotifications = config => getNotifications(null, null, config)

const getTriggers = _.get('triggers')

const getTriggersAutomation = config => {
  const defaultAutomation = _.get('triggersConfig_automation')(config)
  const requirements = {
    sms: defaultAutomation,
    idCardPhoto: defaultAutomation,
    idCardData: defaultAutomation,
    facephoto: defaultAutomation,
    usSsn: defaultAutomation
  }

  const overrides = _.get('triggersConfig_overrides')(config)

  const requirementsOverrides = _.reduce((acc, override) => {
    return _.assign(acc, { [override.requirement]: override.automation })
  }, {}, overrides)

  return _.assign(requirements, requirementsOverrides)
}

const splitGetFirst = _.compose(_.head, _.split('_'))

const getCryptosFromWalletNamespace = config => {
  return _.uniq(_.map(splitGetFirst, _.keys(fromNamespace('wallets', config))))
}

const getCashInSettings = config => fromNamespace(namespaces.CASH_IN)(config)

module.exports = {
  getWalletSettings,
  getCashInSettings,
  getOperatorInfo,
  getNotifications,
  getGlobalNotifications,
  getLocale,
  getGlobalLocale,
  getCommissions,
  getReceipt,
  getCompliance,
  getCoinAtmRadar,
  getTermsConditions,
  getAllCryptoCurrencies,
  getTriggers,
  getTriggersAutomation,
  getCashOut,
  getCryptosFromWalletNamespace
}
<commit_msg>fix: replace sms requirement with sanctions<commit_after>const _ = require('lodash/fp')

const namespaces = {
  WALLETS: 'wallets',
  OPERATOR_INFO: 'operatorInfo',
  NOTIFICATIONS: 'notifications',
  LOCALE: 'locale',
  COMMISSIONS: 'commissions',
  RECEIPT: 'receipt',
  COIN_ATM_RADAR: 'coinAtmRadar',
  TERMS_CONDITIONS: 'termsConditions',
  CASH_OUT: 'cashOut',
  CASH_IN: 'cashIn',
  COMPLIANCE: 'compliance'
}

const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str)
const filter = namespace => _.pickBy((value, key) => _.startsWith(`${namespace}_`)(key))
const strip = key => _.mapKeys(stripl(`${key}_`))

const fromNamespace = _.curry((key, config) => _.compose(strip(key), filter(key))(config))

const getCommissions = (cryptoCode, deviceId, config) => {
  const commissions = fromNamespace(namespaces.COMMISSIONS)(config)
  const overrides = commissions.overrides

  if (_.isEmpty(overrides)) return _.omit('overrides', commissions)

  const specificFilter = it => it.machine === deviceId && _.includes(cryptoCode)(it.cryptoCurrencies)
  const specificAllCoinsFilter = it => it.machine === deviceId && _.includes('ALL_COINS')(it.cryptoCurrencies)
  const allMachinesFilter = it => it.machine === 'ALL_MACHINES' && _.includes(cryptoCode)(it.cryptoCurrencies)

  const specificOverrides = _.filter(specificFilter)(overrides)
  const specificAllCoinsOverrides = _.filter(specificAllCoinsFilter)(overrides)
  const allMachinesOverrides = _.filter(allMachinesFilter)(overrides)

  const priorityOrderOverrides = [
    commissions,
    ...allMachinesOverrides,
    ...specificAllCoinsOverrides,
    ...specificOverrides
  ]

  return _.omit('overrides', _.assignAll(priorityOrderOverrides))
}

const getLocale = (deviceId, it) => {
  const locale = fromNamespace(namespaces.LOCALE)(it)

  const filter = _.matches({ machine: deviceId })
  return _.omit('overrides', _.assignAll([locale, ..._.filter(filter)(locale.overrides)]))
}

const getGlobalLocale = it => getLocale(null, it)

const getWalletSettings = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.WALLETS))(it)
const getCashOut = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.CASH_OUT))(it)
const getOperatorInfo = fromNamespace(namespaces.OPERATOR_INFO)
const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR)
const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS)
const getReceipt = fromNamespace(namespaces.RECEIPT)
const getCompliance = fromNamespace(namespaces.COMPLIANCE)

const getAllCryptoCurrencies = (config) => {
  const locale = fromNamespace(namespaces.LOCALE)(config)
  const cryptos = locale.cryptoCurrencies
  const overridesCryptos = _.map(_.get('cryptoCurrencies'))(locale.overrides)
  return _.uniq(_.flatten([cryptos, ...overridesCryptos]))
}

const getNotifications = (cryptoCurrency, machine, config) => {
  const notifications = fromNamespace(namespaces.NOTIFICATIONS)(config)

  const smsSettings = fromNamespace('sms', notifications)
  const emailSettings = fromNamespace('email', notifications)
  const notificationCenterSettings = fromNamespace('notificationCenter', notifications)

  const notifNoOverrides = _.omit(['cryptoBalanceOverrides', 'fiatBalanceOverrides'], notifications)

  const findByCryptoCurrency = _.find(_.matches({ cryptoCurrency }))
  const findByMachine = _.find(_.matches({ machine }))

  const cryptoFields = ['cryptoHighBalance', 'cryptoLowBalance', 'highBalance', 'lowBalance']
  const fiatFields = ['fiatBalanceCassette1', 'fiatBalanceCassette2']

  const getCryptoSettings = _.compose(_.pick(cryptoFields), _.defaultTo(notifications), findByCryptoCurrency)
  const cryptoSettings = getCryptoSettings(notifications.cryptoBalanceOverrides)

  if (cryptoSettings.highBalance) {
    cryptoSettings['cryptoHighBalance'] = cryptoSettings.highBalance
    delete cryptoSettings.highBalance
  }

  if (cryptoSettings.lowBalance) {
    cryptoSettings['cryptoLowBalance'] = cryptoSettings.lowBalance
    delete cryptoSettings.lowBalance
  }

  const getFiatSettings = _.compose(_.pick(fiatFields), _.defaultTo(notifications), findByMachine)
  const fiatSettings = getFiatSettings(notifications.fiatBalanceOverrides)
  return { ...notifNoOverrides, sms: smsSettings, email: emailSettings, ...cryptoSettings, ...fiatSettings, notificationCenter: notificationCenterSettings }
}

const getGlobalNotifications = config => getNotifications(null, null, config)

const getTriggers = _.get('triggers')

const getTriggersAutomation = config => {
  const defaultAutomation = _.get('triggersConfig_automation')(config)
  const requirements = {
    sanctions: defaultAutomation,
    idCardPhoto: defaultAutomation,
    idCardData: defaultAutomation,
    facephoto: defaultAutomation,
    usSsn: defaultAutomation
  }

  const overrides = _.get('triggersConfig_overrides')(config)

  const requirementsOverrides = _.reduce((acc, override) => {
    return _.assign(acc, { [override.requirement]: override.automation })
  }, {}, overrides)

  return _.assign(requirements, requirementsOverrides)
}

const splitGetFirst = _.compose(_.head, _.split('_'))

const getCryptosFromWalletNamespace = config => {
  return _.uniq(_.map(splitGetFirst, _.keys(fromNamespace('wallets', config))))
}

const getCashInSettings = config => fromNamespace(namespaces.CASH_IN)(config)

module.exports = {
  getWalletSettings,
  getCashInSettings,
  getOperatorInfo,
  getNotifications,
  getGlobalNotifications,
  getLocale,
  getGlobalLocale,
  getCommissions,
  getReceipt,
  getCompliance,
  getCoinAtmRadar,
  getTermsConditions,
  getAllCryptoCurrencies,
  getTriggers,
  getTriggersAutomation,
  getCashOut,
  getCryptosFromWalletNamespace
}
<|endoftext|>


<commit_before>define([
	'goo/entities/Entity',
	'goo/entities/managers/EntityManager',
	'goo/entities/components/TransformComponent'
],
/** @lends */
function (
	Entity,
	EntityManager,
	TransformComponent
) {
	'use strict';

	/**
	 * @class Main handler for an entity world
	 */
	function World (gooRunner) {
		this.gooRunner = gooRunner;
		this._managers = [];
		this._systems = [];

		this._addedEntities = [];
		this._changedEntities = [];
		this._removedEntities = [];

		/** Main keeper of entities
		 * @type {EntityManager}
		 */
		this.entityManager = new EntityManager();
		this.setManager(this.entityManager);

		this.time = 0.0;

		/** Time since last frame in seconds
		 * @type {number}
		 */
		this.tpf = 1.0;

		this._components = [];
	}

	World.time = 0.0;
	World.tpf = 1.0;

	World.prototype.registerComponent = function (componentConstructor) {
		if (this._components.indexOf(componentConstructor) === -1) {
			this._components.push(componentConstructor);
		}
	};

	/**
	 * Adds a Manager to the world
	 *
	 * @param {Manager} manager
	 */
	World.prototype.setManager = function (manager) {
		this._managers.push(manager);
	};

	/**
	 * Retrieve a manager of type 'type'
	 *
	 * @param {String} type Type of manager to retrieve eg. 'EntityManager'
	 * @returns manager
	 */
	World.prototype.getManager = function (type) {
		for (var i = 0; i < this._managers.length; i++) {
			var manager = this._managers[i];
			if (manager.type === type) {
				return manager;
			}
		}
	};

	/**
	 * Adds a {@link System} to the world
	 *
	 * @param {System} system
	 */
	World.prototype.setSystem = function (system) {
		var priority = system.priority;

		for (var i = 0; i < this._systems.length; i++) {
			if (this._systems[i].priority > priority) {
				break;
			}
		}
		this._systems.splice(i, 0, system);
	};

	/**
	 * Retrieve a {@link System} of type 'type'
	 *
	 * @param {String} type Type of system to retrieve
	 * @returns System
	 */
	World.prototype.getSystem = function (type) {
		for (var i = 0; i < this._systems.length; i++) {
			var system = this._systems[i];
			if (system.type === type) {
				return system;
			}
		}
	};

	/**
	 * Creates a new {@link Entity} with an optional MeshData, MeshRenderer, Camera, Script and Light component, placed optionally at a location. Parameters can be given in any order.
	 * @param {MeshData} [meshData]
	 * @param {Material} [material]
	 * @param {String} [name]
	 * @param {Camera} [camera]
	 * @param {Light} [light]
	 * @returns {Entity}
	 */
	World.prototype.createEntity = function () {
		var entity = new Entity(this);
		for (var i = 0; i < arguments.length; i++) {
			if (typeof arguments[i] === 'string') { // does not cover new String()
				entity.name = arguments[i];
			} else {
				entity.set(arguments[i]);
			}
		}

		// separate treatment
		if (!entity.transformComponent) {
			entity.setComponent(new TransformComponent());
		}

		return entity;
	};

	/**
	 * Get all entities in world
	 *
	 * @returns All entities existing in world
	 */
	World.prototype.getEntities = function () {
		return this.entityManager.getEntities();
	};

	/**
	 * Add an entity to the world
	 *
	 * @param {Entity} entity Entity to add
	 * @param {boolean} [recursive=true] If entity hierarchy should be added recursively
	 */
	World.prototype.addEntity = function (entity, recursive) {
		if (this._addedEntities.indexOf(entity) === -1) {
			this._addedEntities.push(entity);
		}

		if (entity.transformComponent && (recursive === undefined || recursive === true)) {
			var children = entity.transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this.addEntity(children[i].entity, recursive);
			}
		}
	};

	/**
	 * Remove an entity from the world
	 *
	 * @param {Entity} entity Entity to remove
	 * @param {boolean} [recursive=true] If entity hierarchy should be removed recursively
	 */
	World.prototype.removeEntity = function (entity, recursive) {
		if (this._removedEntities.indexOf(entity) === -1) {
			this._removedEntities.push(entity);
		}

		var transformComponent = entity.transformComponent;
		if (transformComponent.parent) {
			transformComponent.parent.detachChild(transformComponent);
			transformComponent.parent = null;
		}

		if (recursive === false) {
			var children = transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				children[i].parent = null;
			}

			transformComponent.children = [];
		} else {
			var children = transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this._recursiveRemoval(children[i].entity, recursive);
			}
		}
	};

	World.prototype._recursiveRemoval = function (entity, recursive) {
		if (this._removedEntities.indexOf(entity) === -1) {
			this._removedEntities.push(entity);
		}

		if (entity.transformComponent && (recursive === undefined || recursive === true)) {
			var children = entity.transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this._recursiveRemoval(children[i].entity, recursive);
			}
		}
	};

	/**
	 * Let the system know that an entity has been changed/updated
	 *
	 * @param entity
	 * @param component
	 * @param eventType
	 */
	World.prototype.changedEntity = function (entity, component, eventType) {
		var event = {
			entity: entity
		};
		if (component !== undefined) {
			event.component = component;
		}
		if (eventType !== undefined) {
			event.eventType = eventType;
		}
		this._changedEntities.push(event);
	};

	/**
	 * Process all added/changed/removed entities and callback to active systems and managers. Usually called each frame
	 */
	World.prototype.process = function () {
		this._check(this._addedEntities, function (observer, entity) {
			if (observer.added) {
				observer.added(entity);
			}

			// not in use by any system
			if (observer.addedComponent) {
				for (var i = 0; i < entity._components.length; i++) {
					observer.addedComponent(entity, entity._components[i]);
				}
			}
		});
		this._check(this._changedEntities, function (observer, event) {
			if (observer.changed) {
				observer.changed(event.entity);
			}
			if (event.eventType !== undefined) {
				if (observer[event.eventType]) {
					observer[event.eventType](event.entity, event.component);
				}
			}
		});
		this._check(this._removedEntities, function (observer, entity) {
			if (observer.removed) {
				observer.removed(entity);
			}

			// not in use by any system
			if (observer.removedComponent) {
				for (var i = 0; i < entity._components.length; i++) {
					observer.removedComponent(entity, entity._components[i]);
				}
			}
		});

		for (var i = 0; i < this._systems.length; i++) {
			var system = this._systems[i];
			if (!system.passive) {
				system._process(this.tpf);
			}
		}
	};

	World.prototype._check = function (entities, callback) {
		for (var i = 0; i < entities.length; i++) {
			var entity = entities[i];
			for (var managerIndex = 0; managerIndex < this._managers.length; managerIndex++) {
				var manager = this._managers[managerIndex];
				callback(manager, entity);
			}
			for (var systemIndex = 0; systemIndex < this._systems.length; systemIndex++) {
				var system = this._systems[systemIndex];
				callback(system, entity);
			}
		}
		entities.length = 0;
	};

	return World;
});<commit_msg>#809 World methods allow for chaining; added some missing jsDocs<commit_after>define([
	'goo/entities/Entity',
	'goo/entities/managers/EntityManager',
	'goo/entities/components/TransformComponent'
],
/** @lends */
function (
	Entity,
	EntityManager,
	TransformComponent
) {
	'use strict';

	/**
	 * @class Main handler for an entity world
	 */
	function World (gooRunner) {
		this.gooRunner = gooRunner;
		this._managers = [];
		this._systems = [];

		this._addedEntities = [];
		this._changedEntities = [];
		this._removedEntities = [];

		/** Main keeper of entities
		 * @type {EntityManager}
		 */
		this.entityManager = new EntityManager();
		this.setManager(this.entityManager);

		this.time = 0.0;

		/** Time since last frame in seconds
		 * @type {number}
		 */
		this.tpf = 1.0;

		this._components = [];
	}

	World.time = 0.0;
	World.tpf = 1.0;

	/**
	 * Registers a component type. This is necessary to allow automatic creation of components from 'basic' data types (CameraComponents from Cameras, MeshRendererComponents from materials and so on)
	 *
	 * @param {Component} componentConstructor
	 * @returns {World} Returns self to allow chaining
	 */
	World.prototype.registerComponent = function (componentConstructor) {
		if (this._components.indexOf(componentConstructor) === -1) {
			this._components.push(componentConstructor);
		}
		return this;
	};

	/**
	 * Adds a Manager to the world
	 *
	 * @param {Manager} manager
	 * @returns {World} Returns self to allow chaining
	 */
	World.prototype.setManager = function (manager) {
		this._managers.push(manager);
		return this;
	};

	/**
	 * Retrieve a manager of type 'type'
	 *
	 * @param {String} type Type of manager to retrieve eg. 'EntityManager'
	 * @returns manager
	 */
	World.prototype.getManager = function (type) {
		for (var i = 0; i < this._managers.length; i++) {
			var manager = this._managers[i];
			if (manager.type === type) {
				return manager;
			}
		}
	};

	/**
	 * Adds a {@link System} to the world
	 *
	 * @param {System} system
	 * @returns {World} Returns self to allow chaining
	 */
	World.prototype.setSystem = function (system) {
		var priority = system.priority;

		for (var i = 0; i < this._systems.length; i++) {
			if (this._systems[i].priority > priority) {
				break;
			}
		}
		this._systems.splice(i, 0, system);

		return this;
	};

	/**
	 * Retrieve a {@link System} of type 'type'
	 *
	 * @param {String} type Type of system to retrieve
	 * @returns System
	 */
	World.prototype.getSystem = function (type) {
		for (var i = 0; i < this._systems.length; i++) {
			var system = this._systems[i];
			if (system.type === type) {
				return system;
			}
		}
	};

	/**
	 * Creates a new {@link Entity} with an optional MeshData, MeshRenderer, Camera, Script and Light component, placed optionally at a location. Parameters can be given in any order.
	 * @param {MeshData} [meshData]
	 * @param {Material} [material]
	 * @param {String} [name]
	 * @param {Camera} [camera]
	 * @param {Light} [light]
	 * @returns {Entity}
	 */
	World.prototype.createEntity = function () {
		var entity = new Entity(this);
		for (var i = 0; i < arguments.length; i++) {
			if (typeof arguments[i] === 'string') { // does not cover new String()
				entity.name = arguments[i];
			} else {
				entity.set(arguments[i]);
			}
		}

		// separate treatment
		if (!entity.transformComponent) {
			entity.setComponent(new TransformComponent());
		}

		return entity;
	};

	/**
	 * Get all entities in world
	 *
	 * @returns All entities existing in world
	 */
	World.prototype.getEntities = function () {
		return this.entityManager.getEntities();
	};

	/**
	 * Add an entity to the world
	 *
	 * @param {Entity} entity Entity to add
	 * @param {boolean} [recursive=true] If entity hierarchy should be added recursively
	 * @returns {World} Returns self to allow chaining
	 */
	World.prototype.addEntity = function (entity, recursive) {
		if (this._addedEntities.indexOf(entity) === -1) {
			this._addedEntities.push(entity);
		}

		if (entity.transformComponent && (recursive === undefined || recursive === true)) {
			var children = entity.transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this.addEntity(children[i].entity, recursive);
			}
		}

		return this;
	};

	/**
	 * Remove an entity from the world
	 *
	 * @param {Entity} entity Entity to remove
	 * @param {boolean} [recursive=true] If entity hierarchy should be removed recursively
	 * @returns {World} Returns self to allow chaining
	 */
	World.prototype.removeEntity = function (entity, recursive) {
		if (this._removedEntities.indexOf(entity) === -1) {
			this._removedEntities.push(entity);
		}

		var transformComponent = entity.transformComponent;
		if (transformComponent.parent) {
			transformComponent.parent.detachChild(transformComponent);
			transformComponent.parent = null;
		}

		if (recursive === false) {
			var children = transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				children[i].parent = null;
			}

			transformComponent.children = [];
		} else {
			var children = transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this._recursiveRemoval(children[i].entity, recursive);
			}
		}

		return this;
	};

	World.prototype._recursiveRemoval = function (entity, recursive) {
		if (this._removedEntities.indexOf(entity) === -1) {
			this._removedEntities.push(entity);
		}

		if (entity.transformComponent && (recursive === undefined || recursive === true)) {
			var children = entity.transformComponent.children;
			for (var i = 0; i < children.length; i++) {
				this._recursiveRemoval(children[i].entity, recursive);
			}
		}
	};

	/**
	 * Let the system know that an entity has been changed/updated
	 *
	 * @param entity
	 * @param component
	 * @param eventType
	 */
	World.prototype.changedEntity = function (entity, component, eventType) {
		var event = {
			entity: entity
		};
		if (component !== undefined) {
			event.component = component;
		}
		if (eventType !== undefined) {
			event.eventType = eventType;
		}
		this._changedEntities.push(event);
	};

	/**
	 * Process all added/changed/removed entities and callback to active systems and managers. Usually called each frame
	 */
	World.prototype.process = function () {
		this._check(this._addedEntities, function (observer, entity) {
			if (observer.added) {
				observer.added(entity);
			}

			// not in use by any system
			if (observer.addedComponent) {
				for (var i = 0; i < entity._components.length; i++) {
					observer.addedComponent(entity, entity._components[i]);
				}
			}
		});
		this._check(this._changedEntities, function (observer, event) {
			if (observer.changed) {
				observer.changed(event.entity);
			}
			if (event.eventType !== undefined) {
				if (observer[event.eventType]) {
					observer[event.eventType](event.entity, event.component);
				}
			}
		});
		this._check(this._removedEntities, function (observer, entity) {
			if (observer.removed) {
				observer.removed(entity);
			}

			// not in use by any system
			if (observer.removedComponent) {
				for (var i = 0; i < entity._components.length; i++) {
					observer.removedComponent(entity, entity._components[i]);
				}
			}
		});

		for (var i = 0; i < this._systems.length; i++) {
			var system = this._systems[i];
			if (!system.passive) {
				system._process(this.tpf);
			}
		}
	};

	World.prototype._check = function (entities, callback) {
		for (var i = 0; i < entities.length; i++) {
			var entity = entities[i];
			for (var managerIndex = 0; managerIndex < this._managers.length; managerIndex++) {
				var manager = this._managers[managerIndex];
				callback(manager, entity);
			}
			for (var systemIndex = 0; systemIndex < this._systems.length; systemIndex++) {
				var system = this._systems[systemIndex];
				callback(system, entity);
			}
		}
		entities.length = 0;
	};

	return World;
});<|endoftext|>


<commit_before>define(
/** @lends */
function () {
	'use strict';

	/**
	 * @class Shims for standard gaming features
	 * @description Only used to define the class. Should never be instantiated.
	 */
	function GameUtils () {
	}

	/** Supported features. All true by default.
	 * @type {Object}
	 * @property {boolean} fullscreen
	 * @property {boolean} pointerLock
	 */
	GameUtils.supported = {
		fullscreen: true,
		pointerLock: true
	};

	/**
	 * Attempts to toggle fullscreen.
	 */
	GameUtils.toggleFullScreen = function () {
		if (!document.fullscreenElement) {
			if (document.documentElement.requestFullScreen) {
				document.documentElement.requestFullScreen();
			}
		} else {
			if (document.cancelFullScreen) {
				document.cancelFullScreen();
			}
		}
	};

	/**
	 * Attempts to lock the mouse pointer in the window.
	 */
	GameUtils.requestPointerLock = function () {
		if (document.documentElement.requestPointerLock) {
			document.documentElement.requestPointerLock();
		}
	};

	/**
	 * Attempts to unlock the mouse pointer in the window.
	 */
	GameUtils.exitPointerLock = function () {
		if (document.exitPointerLock) {
			document.exitPointerLock();
		}
	};

	/**
	 * Attempts to toggle the lock on the mouse pointer in the window.
	 */
	GameUtils.togglePointerLock = function () {
		if (!document.pointerLockElement) {
			if (document.documentElement.requestPointerLock) {
				document.documentElement.requestPointerLock();
			}
		} else {
			if (document.exitPointerLock) {
				document.exitPointerLock();
			}
		}
	};

	var visibilityChangeListeners = [];

	/**
	 * Add a visibilitychange listener.
	 * @param {Function} callback function called with a boolean (true=hidden, false=visible)
	 */
	GameUtils.addVisibilityChangeListener = function (callback) {
		if (typeof(callback) !== 'function') {
			return;
		}

		var vendors = ['', 'ms', 'moz', 'webkit'];

		var hidden, visibilityChange;
		for (var x = 0; x < vendors.length; ++x) {
			var hiddenAttribute = vendors[x] + (vendors[x].length === 0 ? 'hidden' : 'Hidden');
			var visibilityAttribute = vendors[x] + 'visibilitychange';

			if (typeof document[hiddenAttribute] !== 'undefined') {
				hidden = hiddenAttribute;
				visibilityChange = visibilityAttribute;
				break;
			}
		}

		if (typeof document.addEventListener !== 'undefined' &&
			typeof hidden !== 'undefined') {
			var eventListener = function () {
				if (document[hidden]) {
					callback(true);
				} else {
					callback(false);
				}
			};
			visibilityChangeListeners.push({
				eventName: visibilityChange,
				eventListener: eventListener
			});
			document.addEventListener(visibilityChange, eventListener);
		}
	};

	GameUtils.clearVisibilityChangeListeners = function () {
		visibilityChangeListeners.forEach(function (listener) {
			document.removeEventListener(listener.eventName, listener.eventListener);
		});
		visibilityChangeListeners = [];
	};

	/**
	 * Attempts to initialize all shims (animation, fullscreen, pointer lock).
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initAllShims = function (global) {
		GameUtils.initWebGLShims();
		GameUtils.initAnimationShims();
		GameUtils.initFullscreenShims(global);
		GameUtils.initPointerLockShims(global);
	};

	/**
	 * Handle missing WebGL features like IE 11 Uint8ClampedArray
	 */
	GameUtils.initWebGLShims = function () {
		window.Uint8ClampedArray = window.Uint8ClampedArray || window.Uint8Array;
	};

	/**
	 * Attempts to initialize the animation shim, ie. defines requestAnimationFrame and cancelAnimationFrame
	 */
	GameUtils.initAnimationShims = function () {
		var lastTime = 0;
		var vendors = ['ms', 'moz', 'webkit', 'o'];

		for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
			window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
			window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
		}

		if (window.requestAnimationFrame === undefined) {
			window.requestAnimationFrame = function (callback) {
				var currTime = Date.now(), timeToCall = Math.max(0, 16 - (currTime - lastTime));
				var id = window.setTimeout(function () {
					callback(currTime + timeToCall);
				}, timeToCall);
				lastTime = currTime + timeToCall;
				return id;
			};
		}

		if (window.cancelAnimationFrame === undefined) {
			window.cancelAnimationFrame = function (id) {
				clearTimeout(id);
			};
		}
	};

	/**
	 * Attempts to initialize the fullscreen shim, ie. defines requestFullscreen and cancelFullscreen
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initFullscreenShims = function (global) {
		global = global || window;
		var elementPrototype = (global.HTMLElement || global.Element).prototype;

		if (!document.hasOwnProperty("fullscreenEnabled")) {
			var getter = (function () {
				if ("webkitIsFullScreen" in document) {
					return function () {
						return document.webkitFullscreenEnabled;
					};
				}
				if ("mozFullScreenEnabled" in document) {
					return function () {
						return document.mozFullScreenEnabled;
					};
				}

				GameUtils.supported.fullscreen = false;

				return function () {
					return false;
				};
			})();

			Object.defineProperty(document, "fullscreenEnabled", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		if (!document.hasOwnProperty("fullscreenElement")) {
			var getter = (function () {
				var name = ["webkitCurrentFullScreenElement", "webkitFullscreenElement", "mozFullScreenElement"];

				var getNameInDocument = function (i) {
					return function() {
						return document[name[i]];
					};
				};

				for (var i = 0; i < name.length; i++) {
					if (name[i] in document) {
						return getNameInDocument(i);
					}
				}
				return function () {
					return null;
				};
			})();

			Object.defineProperty(document, "fullscreenElement", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		function fullscreenchange () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("fullscreenchange", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitfullscreenchange", fullscreenchange, false);
		document.addEventListener("mozfullscreenchange", fullscreenchange, false);

		function fullscreenerror () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("fullscreenerror", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitfullscreenerror", fullscreenerror, false);
		document.addEventListener("mozfullscreenerror", fullscreenerror, false);

		if (!elementPrototype.requestFullScreen) {
			elementPrototype.requestFullScreen = (function () {
				if (elementPrototype.webkitRequestFullScreen) {
					return function () {
						this.webkitRequestFullScreen(global.Element.ALLOW_KEYBOARD_INPUT);
					};
				}

				if (elementPrototype.mozRequestFullScreen) {
					return function () {
						this.mozRequestFullScreen();
					};
				}

				return function () {
				};
			})();
		}

		if (!document.cancelFullScreen) {
			document.cancelFullScreen = (function () {
				return document.webkitCancelFullScreen || document.mozCancelFullScreen || function () {
				};
			})();
		}
	};

	/**
	 * Attempts to initialize the pointer lock shim, ie. define requestPointerLock and exitPointerLock
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initPointerLockShims = function (global) {
		global = global || window;
		var elementPrototype = (global.HTMLElement || global.Element).prototype;

		if (!global.MouseEvent) {
			return;
		}

		var mouseEventPrototype = global.MouseEvent.prototype;

		if (!("movementX" in mouseEventPrototype)) {
			Object.defineProperty(mouseEventPrototype, "movementX", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: function () {
					return this.webkitMovementX || this.mozMovementX || 0;
				}
			});
		}

		if (!("movementY" in mouseEventPrototype)) {
			Object.defineProperty(mouseEventPrototype, "movementY", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: function () {
					return this.webkitMovementY || this.mozMovementY || 0;
				}
			});
		}

		if (!navigator.pointer) {
			navigator.pointer = navigator.webkitPointer || navigator.mozPointer;
		}

		function pointerlockchange () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("pointerlockchange", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitpointerlockchange", pointerlockchange, false);
		document.addEventListener("webkitpointerlocklost", pointerlockchange, false);
		document.addEventListener("mozpointerlockchange", pointerlockchange, false);
		document.addEventListener("mozpointerlocklost", pointerlockchange, false);

		function pointerlockerror () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("pointerlockerror", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitpointerlockerror", pointerlockerror, false);
		document.addEventListener("mozpointerlockerror", pointerlockerror, false);

		if (!document.hasOwnProperty("pointerLockElement")) {
			var getter = (function () {
				if ("webkitPointerLockElement" in document) {
					return function () {
						return document.webkitPointerLockElement;
					};
				}
				if ("mozPointerLockElement" in document) {
					return function () {
						return document.mozPointerLockElement;
					};
				}
				return function () {
					return null;
				};
			})();

			Object.defineProperty(document, "pointerLockElement", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		if (!elementPrototype.requestPointerLock) {
			elementPrototype.requestPointerLock = (function () {
				if (elementPrototype.webkitRequestPointerLock) {
					return function () {
						this.webkitRequestPointerLock();
					};
				}

				if (elementPrototype.mozRequestPointerLock) {
					return function () {
						this.mozRequestPointerLock();
					};
				}

				if (navigator.pointer) {
					return function () {
						var elem = this;
						navigator.pointer.lock(elem, pointerlockchange, pointerlockerror);
					};
				}

				GameUtils.supported.pointerLock = false;

				return function () {
				};
			})();
		}

		if (!document.exitPointerLock) {
			document.exitPointerLock = (function () {
				return document.webkitExitPointerLock || document.mozExitPointerLock || function () {
					if (navigator.pointer) {
						navigator.pointer.unlock();
					}
				};
			})();
		}
	};

	return GameUtils;
});<commit_msg>Removed the requestAnimationFrame shim<commit_after>define(
/** @lends */
function () {
	'use strict';

	/**
	 * @class Shims for standard gaming features
	 * @description Only used to define the class. Should never be instantiated.
	 */
	function GameUtils () {
	}

	/** Supported features. All true by default.
	 * @type {Object}
	 * @property {boolean} fullscreen
	 * @property {boolean} pointerLock
	 */
	GameUtils.supported = {
		fullscreen: true,
		pointerLock: true
	};

	/**
	 * Attempts to toggle fullscreen.
	 */
	GameUtils.toggleFullScreen = function () {
		if (!document.fullscreenElement) {
			if (document.documentElement.requestFullScreen) {
				document.documentElement.requestFullScreen();
			}
		} else {
			if (document.cancelFullScreen) {
				document.cancelFullScreen();
			}
		}
	};

	/**
	 * Attempts to lock the mouse pointer in the window.
	 */
	GameUtils.requestPointerLock = function () {
		if (document.documentElement.requestPointerLock) {
			document.documentElement.requestPointerLock();
		}
	};

	/**
	 * Attempts to unlock the mouse pointer in the window.
	 */
	GameUtils.exitPointerLock = function () {
		if (document.exitPointerLock) {
			document.exitPointerLock();
		}
	};

	/**
	 * Attempts to toggle the lock on the mouse pointer in the window.
	 */
	GameUtils.togglePointerLock = function () {
		if (!document.pointerLockElement) {
			if (document.documentElement.requestPointerLock) {
				document.documentElement.requestPointerLock();
			}
		} else {
			if (document.exitPointerLock) {
				document.exitPointerLock();
			}
		}
	};

	var visibilityChangeListeners = [];

	/**
	 * Add a visibilitychange listener.
	 * @param {Function} callback function called with a boolean (true=hidden, false=visible)
	 */
	GameUtils.addVisibilityChangeListener = function (callback) {
		if (typeof(callback) !== 'function') {
			return;
		}

		var vendors = ['', 'ms', 'moz', 'webkit'];

		var hidden, visibilityChange;
		for (var x = 0; x < vendors.length; ++x) {
			var hiddenAttribute = vendors[x] + (vendors[x].length === 0 ? 'hidden' : 'Hidden');
			var visibilityAttribute = vendors[x] + 'visibilitychange';

			if (typeof document[hiddenAttribute] !== 'undefined') {
				hidden = hiddenAttribute;
				visibilityChange = visibilityAttribute;
				break;
			}
		}

		if (typeof document.addEventListener !== 'undefined' &&
			typeof hidden !== 'undefined') {
			var eventListener = function () {
				if (document[hidden]) {
					callback(true);
				} else {
					callback(false);
				}
			};
			visibilityChangeListeners.push({
				eventName: visibilityChange,
				eventListener: eventListener
			});
			document.addEventListener(visibilityChange, eventListener);
		}
	};

	GameUtils.clearVisibilityChangeListeners = function () {
		visibilityChangeListeners.forEach(function (listener) {
			document.removeEventListener(listener.eventName, listener.eventListener);
		});
		visibilityChangeListeners = [];
	};

	/**
	 * Attempts to initialize all shims (animation, fullscreen, pointer lock).
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initAllShims = function (global) {
		GameUtils.initWebGLShims();
		GameUtils.initFullscreenShims(global);
		GameUtils.initPointerLockShims(global);
	};

	/**
	 * Handle missing WebGL features like IE 11 Uint8ClampedArray
	 */
	GameUtils.initWebGLShims = function () {
		window.Uint8ClampedArray = window.Uint8ClampedArray || window.Uint8Array;
	};

	/**
	 * Attempts to initialize the fullscreen shim, ie. defines requestFullscreen and cancelFullscreen
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initFullscreenShims = function (global) {
		global = global || window;
		var elementPrototype = (global.HTMLElement || global.Element).prototype;

		if (!document.hasOwnProperty("fullscreenEnabled")) {
			var getter = (function () {
				if ("webkitIsFullScreen" in document) {
					return function () {
						return document.webkitFullscreenEnabled;
					};
				}
				if ("mozFullScreenEnabled" in document) {
					return function () {
						return document.mozFullScreenEnabled;
					};
				}

				GameUtils.supported.fullscreen = false;

				return function () {
					return false;
				};
			})();

			Object.defineProperty(document, "fullscreenEnabled", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		if (!document.hasOwnProperty("fullscreenElement")) {
			var getter = (function () {
				var name = ["webkitCurrentFullScreenElement", "webkitFullscreenElement", "mozFullScreenElement"];

				var getNameInDocument = function (i) {
					return function() {
						return document[name[i]];
					};
				};

				for (var i = 0; i < name.length; i++) {
					if (name[i] in document) {
						return getNameInDocument(i);
					}
				}
				return function () {
					return null;
				};
			})();

			Object.defineProperty(document, "fullscreenElement", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		function fullscreenchange () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("fullscreenchange", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitfullscreenchange", fullscreenchange, false);
		document.addEventListener("mozfullscreenchange", fullscreenchange, false);

		function fullscreenerror () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("fullscreenerror", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitfullscreenerror", fullscreenerror, false);
		document.addEventListener("mozfullscreenerror", fullscreenerror, false);

		if (!elementPrototype.requestFullScreen) {
			elementPrototype.requestFullScreen = (function () {
				if (elementPrototype.webkitRequestFullScreen) {
					return function () {
						this.webkitRequestFullScreen(global.Element.ALLOW_KEYBOARD_INPUT);
					};
				}

				if (elementPrototype.mozRequestFullScreen) {
					return function () {
						this.mozRequestFullScreen();
					};
				}

				return function () {
				};
			})();
		}

		if (!document.cancelFullScreen) {
			document.cancelFullScreen = (function () {
				return document.webkitCancelFullScreen || document.mozCancelFullScreen || function () {
				};
			})();
		}
	};

	/**
	 * Attempts to initialize the pointer lock shim, ie. define requestPointerLock and exitPointerLock
	 * @param {Element} [global=window] The global element (for compatibility checks and patching)
	 */
	GameUtils.initPointerLockShims = function (global) {
		global = global || window;
		var elementPrototype = (global.HTMLElement || global.Element).prototype;

		if (!global.MouseEvent) {
			return;
		}

		var mouseEventPrototype = global.MouseEvent.prototype;

		if (!("movementX" in mouseEventPrototype)) {
			Object.defineProperty(mouseEventPrototype, "movementX", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: function () {
					return this.webkitMovementX || this.mozMovementX || 0;
				}
			});
		}

		if (!("movementY" in mouseEventPrototype)) {
			Object.defineProperty(mouseEventPrototype, "movementY", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: function () {
					return this.webkitMovementY || this.mozMovementY || 0;
				}
			});
		}

		if (!navigator.pointer) {
			navigator.pointer = navigator.webkitPointer || navigator.mozPointer;
		}

		function pointerlockchange () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("pointerlockchange", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitpointerlockchange", pointerlockchange, false);
		document.addEventListener("webkitpointerlocklost", pointerlockchange, false);
		document.addEventListener("mozpointerlockchange", pointerlockchange, false);
		document.addEventListener("mozpointerlocklost", pointerlockchange, false);

		function pointerlockerror () {
			var newEvent = document.createEvent("CustomEvent");
			newEvent.initCustomEvent("pointerlockerror", true, false, null);
			document.dispatchEvent(newEvent);
		}
		document.addEventListener("webkitpointerlockerror", pointerlockerror, false);
		document.addEventListener("mozpointerlockerror", pointerlockerror, false);

		if (!document.hasOwnProperty("pointerLockElement")) {
			var getter = (function () {
				if ("webkitPointerLockElement" in document) {
					return function () {
						return document.webkitPointerLockElement;
					};
				}
				if ("mozPointerLockElement" in document) {
					return function () {
						return document.mozPointerLockElement;
					};
				}
				return function () {
					return null;
				};
			})();

			Object.defineProperty(document, "pointerLockElement", {
				enumerable: true,
				configurable: false,
				writeable: false,
				get: getter
			});
		}

		if (!elementPrototype.requestPointerLock) {
			elementPrototype.requestPointerLock = (function () {
				if (elementPrototype.webkitRequestPointerLock) {
					return function () {
						this.webkitRequestPointerLock();
					};
				}

				if (elementPrototype.mozRequestPointerLock) {
					return function () {
						this.mozRequestPointerLock();
					};
				}

				if (navigator.pointer) {
					return function () {
						var elem = this;
						navigator.pointer.lock(elem, pointerlockchange, pointerlockerror);
					};
				}

				GameUtils.supported.pointerLock = false;

				return function () {
				};
			})();
		}

		if (!document.exitPointerLock) {
			document.exitPointerLock = (function () {
				return document.webkitExitPointerLock || document.mozExitPointerLock || function () {
					if (navigator.pointer) {
						navigator.pointer.unlock();
					}
				};
			})();
		}
	};

	return GameUtils;
});<|endoftext|>


<commit_before>'use strict';

var Node = require('../node');

var TYPE = 'gravity';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY), // "populated places"
    target: Node.PARAM.NODE(Node.GEOMETRY.POINT), // "malls"
    weight_column: Node.PARAM.STRING(),
    weight_threshold: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(),-10e307),
    pop_column: Node.PARAM.STRING(),
    max_distance: Node.PARAM.NUMBER(), // meters
    target_id: Node.PARAM.NUMBER() // the "mall" to be studied
};

var Gravity = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Gravity;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

var gravityTemplate = Node.template([
    'WITH ',
    ' raw_s as({{=it.sourceQuery}}),',
    ' raw_t as({{=it.targetQuery}}),',
    ' s as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.p}},0)::numeric) as p',
        ' FROM raw_s',
    '),',
    ' t as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.w}},0)::numeric) as w',
        ' FROM raw_t',
    ')',
    'SELECT ',
    ' g.source_id as cartodb_id,',
    ' g.the_geom,',
    ' ST_transform(g.the_geom, 3857) as the_geom_webmercator,',
    ' g.h as patronage_prob,',
    ' g.hpop patronaging_pop,',
    ' g.dist as dist_to_target ',
    'FROM ',
    ' t,',
    ' s,',
    ' cdb_crankshaft.CDB_Gravity(t.id, t.g, t.w, s.id, s.g, s.p,',
    '  {{=it.targetID}}::bigint, {{=it.r}}::integer, {{=it.wt}}::numeric) g'
].join('\n'));

Gravity.prototype.sql = function(){
    return gravityTemplate({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        targetID: this.target_id,
        w: this.weight_column,
        wt: this.weight_threshold,
        p: this.pop_column,
        r: this.max_distance
    });
};
<commit_msg>add verification of threshold and ANY geometry<commit_after>'use strict';

var Node = require('../node');

var TYPE = 'gravity';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY), // "populated places"
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY), // "malls"
    weight_column: Node.PARAM.STRING(),
    weight_threshold: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(), -10e307),
    pop_column: Node.PARAM.STRING(),
    max_distance: Node.PARAM.NUMBER(), // meters
    target_id: Node.PARAM.NUMBER() // the "mall" to be studied
};

var Gravity = Node.create(TYPE, PARAMS, {
    cache: true,
    version: 1,
    beforeCreate: function (node) {
        if (node.weight_threshold < -10e307) {
            throw new Error('weight_threshold param should be bigger than -10e307');
        }
        if (node.weight_threshold > 10e307) {
            throw new Error('weight_threshold param should be bigger than 10e307');
        }
    }
});

module.exports = Gravity;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

var gravityTemplate = Node.template([
    'WITH ',
    ' raw_s as({{=it.sourceQuery}}),',
    ' raw_t as({{=it.targetQuery}}),',
    ' s as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.p}},0)::numeric) as p',
        ' FROM raw_s',
    '),',
    ' t as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.w}},0)::numeric) as w',
        ' FROM raw_t',
    ')',
    'SELECT ',
    ' g.source_id as cartodb_id,',
    ' g.the_geom,',
    ' ST_transform(g.the_geom, 3857) as the_geom_webmercator,',
    ' g.h as patronage_prob,',
    ' g.hpop patronaging_pop,',
    ' g.dist as dist_to_target ',
    'FROM ',
    ' t,',
    ' s,',
    ' cdb_crankshaft.CDB_Gravity(t.id, t.g, t.w, s.id, s.g, s.p,',
    '  {{=it.targetID}}::bigint, {{=it.r}}::integer, {{=it.wt}}::numeric) g'
].join('\n'));

Gravity.prototype.sql = function () {
    return gravityTemplate({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        targetID: this.target_id,
        w: this.weight_column,
        wt: this.weight_threshold,
        p: this.pop_column,
        r: this.max_distance
    });
};
<|endoftext|>


<commit_before>let async = require("async"),
    debug = require("debug")("nuimojs"),
    EventEmitter = require("events").EventEmitter;

const Swipe = {
    LEFT: 0,
    RIGHT: 1,
    UP: 2,
    DOWN: 3
};

const Fly = {
    LEFT: 0,
    RIGHT: 1
};

const Area = {
    LEFT: 4,
    RIGHT: 5,
    TOP: 6,
    BOTTOM: 7,
    LONGLEFT: 8,
    LONGRIGHT: 9,
    LONGTOP: 10,
    LONGBOTTOM: 11
};

// Direction is now deprecated, use Swipe, Fly, or Area instead
const Direction = Swipe;

// Configuration bits, see https://github.com/nathankunicki/nuimojs/pull/12
const Options = {
    ONION_SKINNING: 16,
    BUILTIN_MATRIX: 32
};

const UUID = {
    Service: {
        BATTERY_STATUS: "180f",
        DEVICE_INFORMATION: "180a",
        LED_MATRIX: "f29b1523cb1940f3be5c7241ecb82fd1",
        USER_INPUT_EVENTS: "f29b1525cb1940f3be5c7241ecb82fd2"
    },
    Characteristic: {
        BATTERY_LEVEL: "2a19",
        DEVICE_INFORMATION: "2a29",
        FLY: "f29b1526cb1940f3be5c7241ecb82fd2",
        SWIPE: "f29b1527cb1940f3be5c7241ecb82fd2",
        ROTATION: "f29b1528cb1940f3be5c7241ecb82fd2",
        BUTTON_CLICK: "f29b1529cb1940f3be5c7241ecb82fd2"
    }
};

class Device extends EventEmitter {

    constructor (peripheral) {
        super();

        this.deviceType = "nuimo";

        this._peripheral = peripheral;
        this._LEDCharacteristic = null;
        this._batteryLevel = 100;
        this._rssi = -100; // Initialize as -100 - no signal
    }

    static get Direction () {
        return Direction;
    }

    static get Swipe () {
        return Swipe;
    }

    static get Fly () {
        return Fly;
    }

    static get Area () {
        return Area;
    }

    static get Options () {
        return Options;
    }

    get uuid () {
        return this._peripheral.uuid;
    }

    get UUID () {
        return this.uuid;
    }

    get batteryLevel () {
        return this._batteryLevel;
    }

    get rssi () {
        return this._rssi;
    }

    get RSSI () {
        return this.rssi;
    }

    connect (callback) {

        let self = this;

        let batteryReady = false;
        let LEDReady = false;
        let userInputs = 0;

        this._peripheral.connect((err) => {

            this._rssi = this._peripheral.rssi;

            let rssiUpdateInterval = setInterval(() => {
                this._peripheral.updateRssi((err, rssi) => {
                    if (!err) {
                        if (this._rssi != rssi) {
                            this._rssi = rssi;
                            self.emit("rssiChange", rssi);
                        }
                    }
                });
            }, 2000);

            self._peripheral.on("disconnect", () => {
               clearInterval(rssiUpdateInterval);
            });

            self._peripheral.discoverServices([], (error, services) => {

                debug("Service discovery started");

                let serviceIndex = 0;

                async.whilst(
                    function () {
                        return (serviceIndex < services.length);
                    },
                    function (callback) {

                        let service = services[serviceIndex];

                        service.discoverCharacteristics([], (error, characteristics) => {

                            let characteristicIndex = 0;

                            async.whilst(
                                function () {
                                    return (characteristicIndex < characteristics.length);
                                },
                                function (callback) {

                                    let characteristic = characteristics[characteristicIndex];

                                    switch (service.uuid) {
                                        case UUID.Service.BATTERY_STATUS:
                                            batteryReady = true;
                                            debug("Found Battery characteristic");
                                            self._subscribeToCharacteristic(characteristic, self._handleBatteryChange.bind(self));
                                            characteristic.read();
                                            break;
                                        case UUID.Service.LED_MATRIX:
                                            self._LEDCharacteristic = characteristic;
                                            LEDReady = true;
                                            debug("Found LED characteristic");
                                            break;
                                        case UUID.Service.USER_INPUT_EVENTS:
                                            switch (characteristic.uuid) {
                                                case UUID.Characteristic.BUTTON_CLICK:
                                                    debug("Found Button Click characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleClick.bind(self));
                                                    break;
                                                case UUID.Characteristic.FLY:
                                                    debug("Found Fly characteristic");
                                                    self._subscribeToCharacteristic((characteristic), self._handleFlying.bind(self));
                                                    break;
                                                case UUID.Characteristic.ROTATION:
                                                    debug("Found Rotation characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleRotation.bind(self));
                                                    break;
                                                case UUID.Characteristic.SWIPE:
                                                    debug("Found Swipe characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleTouchSwipe.bind(self));
                                                    break;
                                            }
                                            userInputs++;
                                            break;
                                    }

                                    characteristicIndex++;
                                    return callback();

                                },
                                function (err) {
                                    serviceIndex++;
                                    return callback();
                                }
                            );
                        });
                    },
                    function (err) {

                        debug("Service discovery finished");

                        if (err !== null || batteryReady === false || LEDReady === false || userInputs < 5) {
                            self._peripheral.disconnect();
                            debug("Force disconnect");
                        } else {
                            debug("Emit connect");
                            self.emit("connect");
                        }

                        if (callback) {
                            return callback();
                        }
                    }
                );
            });
        });
    }

    disconnect () {
        this._peripheral.disconnect();
    }

    setLEDMatrix (matrixData, brightness, timeout, options) {

        if (this._LEDCharacteristic) {
            let buf = Buffer.alloc(13);

            if (matrixData instanceof Buffer) {
                matrixData.copy(buf);
            } else {
                this._LEDArrayToBuffer(matrixData).copy(buf);
            }

            if (typeof options === "number") {
                buf[10] += options;
            } else if (typeof options === "object") {
                if (options.onion_skinning || options.onionSkinning) {
                    buf[10] += Options.ONION_SKINNING;
                }
                if (options.builtin_matrix || options.builtinMatrix){
                    buf[10] += Options.BUILTIN_MATRIX;
                }
            }

            buf[11] = brightness;
            buf[12] = Math.floor(timeout / 100);

            this._LEDCharacteristic.write(buf, true);
        } else {
            this.emit("error", new Error("Not fully connected"));
        }
    }

    _LEDArrayToBuffer (arr) {
        let buf = Buffer.alloc(11);

        for (let i = 0; i < 11; i++) {
            buf[i] = parseInt(arr.slice(i*8, i*8+8).reverse().join(""), 2);
        }

        return buf;
    }

    _subscribeToCharacteristic (characteristic, callback) {
        characteristic.on("read", (data, isNotification) => {
            return callback(data);
        });
        characteristic.subscribe((err) => {
            if (err) {
                this.emit("error", err);
            }
        });
    }

    _handleBatteryChange (data) {
        this._batteryLevel = data[0];
        debug("Battery level %s%", data[0]);
        this.emit("batteryLevelChange", data[0]);
    }

    _handleTouchSwipe (data) {
        let direction = data[0];
        if (direction <= 3) {
            this.emit("swipe", direction);
        } else {
            this.emit("touch", direction);
        }
        switch (direction) {
            case (Swipe.LEFT):
                debug("Swipe left");
                this.emit("swipeLeft");
                break;
            case (Swipe.RIGHT):
                debug("Swipe right");
                this.emit("swipeRight");
                break;
            case (Swipe.UP):
                debug("Swipe up");
                this.emit("swipeUp");
                break;
            case (Swipe.DOWN):
                debug("Swipe down");
                this.emit("swipeDown");
                break;
            case (Area.LEFT):
                debug("Touch left");
                this.emit("touchLeft");
                break;
            case (Area.RIGHT):
                debug("Touch right");
                this.emit("touchRight");
                break;
            case (Area.TOP):
                debug("Touch top");
                this.emit("touchTop");
                break;
            case (Area.BOTTOM):
                debug("Touch bottom");
                this.emit("touchBottom");
                break;
            case (Area.LONGLEFT):
                debug("Long Touch left");
                this.emit("longTouchLeft");
                break;
            case (Area.LONGRIGHT):
                debug("Long Touch right");
                this.emit("longTouchRight");
                break;
            case (Area.LONGTOP):
                debug("Long Touch top");
                this.emit("longTouchTop");
                break;
            case (Area.LONGBOTTOM):
                debug("Long Touch bottom");
                this.emit("longTouchBottom");
                break;
        }
    }

    _handleClick (data) {
        if (data[0] === 0) {
  //          debug("Button released");
  //          this.emit("release");
        } else {
            debug("Button pressed");
            this.emit("press");
        }
    }

    _handleRotation (data) {
        let amount = data.readInt16LE();
        debug("Rotate %s", amount);
        this.emit("rotate", amount);
    }

    _handleFlying (data) {

        let gesture = data[0],
            amount = data[1];

        switch (gesture) {
            case 0:
            case 1:
            case 2:
                let direction = gesture,
                    speed = amount;
                this.emit("fly", direction, speed); break;
                switch (direction) {
                    case (Fly.LEFT):
                        debug("Fly left %s", speed);
                        this.emit("flyLeft", speed);
                        break;
                    case (Fly.RIGHT):
                        debug("Fly right %s", speed);
                        this.emit("flyRight", speed);
                        break;
                }
                break;
            case 4:
                debug("Detect %s", amount);
                this.emit("detect", amount);
                this.emit("distance", amount);
                break;
        }
    }
}

module.exports = Device;
<commit_msg>Fix temp change made to handleClick.<commit_after>let async = require("async"),
    debug = require("debug")("nuimojs"),
    EventEmitter = require("events").EventEmitter;

const Swipe = {
    LEFT: 0,
    RIGHT: 1,
    UP: 2,
    DOWN: 3
};

const Fly = {
    LEFT: 0,
    RIGHT: 1
};

const Area = {
    LEFT: 4,
    RIGHT: 5,
    TOP: 6,
    BOTTOM: 7,
    LONGLEFT: 8,
    LONGRIGHT: 9,
    LONGTOP: 10,
    LONGBOTTOM: 11
};

// Direction is now deprecated, use Swipe, Fly, or Area instead
const Direction = Swipe;

// Configuration bits, see https://github.com/nathankunicki/nuimojs/pull/12
const Options = {
    ONION_SKINNING: 16,
    BUILTIN_MATRIX: 32
};

const UUID = {
    Service: {
        BATTERY_STATUS: "180f",
        DEVICE_INFORMATION: "180a",
        LED_MATRIX: "f29b1523cb1940f3be5c7241ecb82fd1",
        USER_INPUT_EVENTS: "f29b1525cb1940f3be5c7241ecb82fd2"
    },
    Characteristic: {
        BATTERY_LEVEL: "2a19",
        DEVICE_INFORMATION: "2a29",
        FLY: "f29b1526cb1940f3be5c7241ecb82fd2",
        SWIPE: "f29b1527cb1940f3be5c7241ecb82fd2",
        ROTATION: "f29b1528cb1940f3be5c7241ecb82fd2",
        BUTTON_CLICK: "f29b1529cb1940f3be5c7241ecb82fd2"
    }
};

class Device extends EventEmitter {

    constructor (peripheral) {
        super();

        this.deviceType = "nuimo";

        this._peripheral = peripheral;
        this._LEDCharacteristic = null;
        this._batteryLevel = 100;
        this._rssi = -100; // Initialize as -100 - no signal
    }

    static get Direction () {
        return Direction;
    }

    static get Swipe () {
        return Swipe;
    }

    static get Fly () {
        return Fly;
    }

    static get Area () {
        return Area;
    }

    static get Options () {
        return Options;
    }

    get uuid () {
        return this._peripheral.uuid;
    }

    get UUID () {
        return this.uuid;
    }

    get batteryLevel () {
        return this._batteryLevel;
    }

    get rssi () {
        return this._rssi;
    }

    get RSSI () {
        return this.rssi;
    }

    connect (callback) {

        let self = this;

        let batteryReady = false;
        let LEDReady = false;
        let userInputs = 0;

        this._peripheral.connect((err) => {

            this._rssi = this._peripheral.rssi;

            let rssiUpdateInterval = setInterval(() => {
                this._peripheral.updateRssi((err, rssi) => {
                    if (!err) {
                        if (this._rssi != rssi) {
                            this._rssi = rssi;
                            self.emit("rssiChange", rssi);
                        }
                    }
                });
            }, 2000);

            self._peripheral.on("disconnect", () => {
               clearInterval(rssiUpdateInterval);
            });

            self._peripheral.discoverServices([], (error, services) => {

                debug("Service discovery started");

                let serviceIndex = 0;

                async.whilst(
                    function () {
                        return (serviceIndex < services.length);
                    },
                    function (callback) {

                        let service = services[serviceIndex];

                        service.discoverCharacteristics([], (error, characteristics) => {

                            let characteristicIndex = 0;

                            async.whilst(
                                function () {
                                    return (characteristicIndex < characteristics.length);
                                },
                                function (callback) {

                                    let characteristic = characteristics[characteristicIndex];

                                    switch (service.uuid) {
                                        case UUID.Service.BATTERY_STATUS:
                                            batteryReady = true;
                                            debug("Found Battery characteristic");
                                            self._subscribeToCharacteristic(characteristic, self._handleBatteryChange.bind(self));
                                            characteristic.read();
                                            break;
                                        case UUID.Service.LED_MATRIX:
                                            self._LEDCharacteristic = characteristic;
                                            LEDReady = true;
                                            debug("Found LED characteristic");
                                            break;
                                        case UUID.Service.USER_INPUT_EVENTS:
                                            switch (characteristic.uuid) {
                                                case UUID.Characteristic.BUTTON_CLICK:
                                                    debug("Found Button Click characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleClick.bind(self));
                                                    break;
                                                case UUID.Characteristic.FLY:
                                                    debug("Found Fly characteristic");
                                                    self._subscribeToCharacteristic((characteristic), self._handleFlying.bind(self));
                                                    break;
                                                case UUID.Characteristic.ROTATION:
                                                    debug("Found Rotation characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleRotation.bind(self));
                                                    break;
                                                case UUID.Characteristic.SWIPE:
                                                    debug("Found Swipe characteristic");
                                                    self._subscribeToCharacteristic(characteristic, self._handleTouchSwipe.bind(self));
                                                    break;
                                            }
                                            userInputs++;
                                            break;
                                    }

                                    characteristicIndex++;
                                    return callback();

                                },
                                function (err) {
                                    serviceIndex++;
                                    return callback();
                                }
                            );
                        });
                    },
                    function (err) {

                        debug("Service discovery finished");

                        if (err !== null || batteryReady === false || LEDReady === false || userInputs < 5) {
                            self._peripheral.disconnect();
                            debug("Force disconnect");
                        } else {
                            debug("Emit connect");
                            self.emit("connect");
                        }

                        if (callback) {
                            return callback();
                        }
                    }
                );
            });
        });
    }

    disconnect () {
        this._peripheral.disconnect();
    }

    setLEDMatrix (matrixData, brightness, timeout, options) {

        if (this._LEDCharacteristic) {
            let buf = Buffer.alloc(13);

            if (matrixData instanceof Buffer) {
                matrixData.copy(buf);
            } else {
                this._LEDArrayToBuffer(matrixData).copy(buf);
            }

            if (typeof options === "number") {
                buf[10] += options;
            } else if (typeof options === "object") {
                if (options.onion_skinning || options.onionSkinning) {
                    buf[10] += Options.ONION_SKINNING;
                }
                if (options.builtin_matrix || options.builtinMatrix){
                    buf[10] += Options.BUILTIN_MATRIX;
                }
            }

            buf[11] = brightness;
            buf[12] = Math.floor(timeout / 100);

            this._LEDCharacteristic.write(buf, true);
        } else {
            this.emit("error", new Error("Not fully connected"));
        }
    }

    _LEDArrayToBuffer (arr) {
        let buf = Buffer.alloc(11);

        for (let i = 0; i < 11; i++) {
            buf[i] = parseInt(arr.slice(i*8, i*8+8).reverse().join(""), 2);
        }

        return buf;
    }

    _subscribeToCharacteristic (characteristic, callback) {
        characteristic.on("read", (data, isNotification) => {
            return callback(data);
        });
        characteristic.subscribe((err) => {
            if (err) {
                this.emit("error", err);
            }
        });
    }

    _handleBatteryChange (data) {
        this._batteryLevel = data[0];
        debug("Battery level %s%", data[0]);
        this.emit("batteryLevelChange", data[0]);
    }

    _handleTouchSwipe (data) {
        let direction = data[0];
        if (direction <= 3) {
            this.emit("swipe", direction);
        } else {
            this.emit("touch", direction);
        }
        switch (direction) {
            case (Swipe.LEFT):
                debug("Swipe left");
                this.emit("swipeLeft");
                break;
            case (Swipe.RIGHT):
                debug("Swipe right");
                this.emit("swipeRight");
                break;
            case (Swipe.UP):
                debug("Swipe up");
                this.emit("swipeUp");
                break;
            case (Swipe.DOWN):
                debug("Swipe down");
                this.emit("swipeDown");
                break;
            case (Area.LEFT):
                debug("Touch left");
                this.emit("touchLeft");
                break;
            case (Area.RIGHT):
                debug("Touch right");
                this.emit("touchRight");
                break;
            case (Area.TOP):
                debug("Touch top");
                this.emit("touchTop");
                break;
            case (Area.BOTTOM):
                debug("Touch bottom");
                this.emit("touchBottom");
                break;
            case (Area.LONGLEFT):
                debug("Long Touch left");
                this.emit("longTouchLeft");
                break;
            case (Area.LONGRIGHT):
                debug("Long Touch right");
                this.emit("longTouchRight");
                break;
            case (Area.LONGTOP):
                debug("Long Touch top");
                this.emit("longTouchTop");
                break;
            case (Area.LONGBOTTOM):
                debug("Long Touch bottom");
                this.emit("longTouchBottom");
                break;
        }
    }

    _handleClick (data) {
        if (data[0] === 0) {
            debug("Button released");
            this.emit("release");
        } else {
            debug("Button pressed");
            this.emit("press");
        }
    }

    _handleRotation (data) {
        let amount = data.readInt16LE();
        debug("Rotate %s", amount);
        this.emit("rotate", amount);
    }

    _handleFlying (data) {

        let gesture = data[0],
            amount = data[1];

        switch (gesture) {
            case 0:
            case 1:
            case 2:
                let direction = gesture,
                    speed = amount;
                this.emit("fly", direction, speed); break;
                switch (direction) {
                    case (Fly.LEFT):
                        debug("Fly left %s", speed);
                        this.emit("flyLeft", speed);
                        break;
                    case (Fly.RIGHT):
                        debug("Fly right %s", speed);
                        this.emit("flyRight", speed);
                        break;
                }
                break;
            case 4:
                debug("Detect %s", amount);
                this.emit("detect", amount);
                this.emit("distance", amount);
                break;
        }
    }
}

module.exports = Device;
<|endoftext|>


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

module.exports = (url) => {
  if (!/^(http[s]?:\/\/)(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/i.test(url)) return;

  return new Promise((resolve, reject) => {
    request( { method: 'HEAD', url: url, followAllRedirects: true },
      function (error, response) {
        if (error) {
          reject(error);
        }
        else {
          resolve(response.request.href);
        }
      });
  });
};
<commit_msg>Improved followURL function<commit_after>const request = require('request');

module.exports = (url) => {
  return new Promise((resolve, reject) => {
    if (!/^(http[s]?:\/\/)(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/i.test(url)) {
      resolve('Invalid URI');
    }

    request( { method: 'HEAD', url: url, followAllRedirects: true },
      function (error, response) {
        if (error) {
          reject(error);
        }
        else {
          resolve(response.request.href);
        }
      });
  });
};
<|endoftext|>


<commit_before>Ext.define('nineam-localization-plugin-ext.controls.LocalesComboBox', {
    extend: 'Ext.form.field.ComboBox',
    alias: 'widget.localesCombobox',

    /**
     * Custom refresh method to update locales ComboBox with localized labels
     * when user changes selected locale.
     */
    refresh: function(labels) {
        //get the index of the currently selected model
        var selectionIndex = this.store.find('label', this.getRawValue());

        //copy model objects from the stores mixedCollection into an array to be used when creating a new store
        var data = [];
        var storeLen = this.store.getCount();
        for(var i=0; i<storeLen; i++) {
            data.push(this.store.getAt(i));
        }

        //create new store from old store's data
        var store = Ext.create('nineam.localization.store.LocalesStore', {
            data: data
        })

        //update new store with new label values
        var labelsLen = labels.length;
        for(var i=0; i<labelsLen; i++) {
            var label = labels[i];
            var itemIndex = store.find('id', label.id);
            store.getAt(itemIndex).set('label', label.label);
        }

        //bind ComboBox to new store
        this.bindStore(store);

        //reset selection
        this.setValue(this.store.getAt(selectionIndex));
    }
})<commit_msg>fixed typo in file name<commit_after>Ext.define('nineam-localization-plugin-ext.controls.LocalesComboBox', {
    extend: 'Ext.form.field.ComboBox',
    alias: 'widget.localesCombobox',

    /**
     * Custom refresh method to update locales ComboBox with localized labels
     * when user changes selected locale.
     */
    refresh: function(labels) {
        //get the index of the currently selected model
        var selectionIndex = this.store.find('label', this.getRawValue());

        //copy model objects from the stores mixedCollection into an array to be used when creating a new store
        var data = [];
        var storeLen = this.store.getCount();
        for(var i=0; i<storeLen; i++) {
            data.push(this.store.getAt(i));
        }

        //create new store from old store's data
        var store = Ext.create('nineam.localization.store.LocalesStore', {
            data: data
        });

        //update new store with new label values
        var labelsLen = labels.length;
        for(var j=0; j<labelsLen; j++) {
            var label = labels[j];
            var itemIndex = store.find('id', label.id);
            store.getAt(itemIndex).set('label', label.label);
        }

        //bind ComboBox to new store
        this.bindStore(store);

        //reset selection
        this.setValue(this.store.getAt(selectionIndex));
    }
});<|endoftext|>