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

'use strict'

const Commands = require('./commands')
const Job = require('./job')
const RecordStream = require('./record_stream')

/**
 * @class Scan
 * @classdesc The scan object created by calling {@link Client#scan} is used
 * for executing record scans on the specified namespace and set (optional).
 * Scans can return a set of records as a {@link RecordStream} or apply an
 * Aerospike UDF (user-defined function) on each of the records on the server.
 *
 * For more information, please refer to the section on
 * ⇑Scans
 * in the Aerospike technical documentation.
 *
 * #### Selecting Bins
 *
 * Using {@link Scan#select} it is possible to select a subset of bins which
 * should be returned by the query. If no bins are selected, then the whole
 * record will be returned. If the {@link Scan#nobins} property is set to
 * true the only the record meta data (ttl, generation, etc.) will
 * be returned.
 *
 * #### Executing a Scan
 *
 * A scan is executed using {@link Scan#foreach}. The method returns a {@link
 * RecordStream} which emits a data event for each record returned
 * by the scan. The scan can be aborted at any time by calling
 * {@link RecordStream#abort}.
 *
 * #### Executing Record UDFs using Background Scans
 *
 * Record UDFs perform operations on a single record such as updating records
 * based on a set of parameters. Using {@link Scan#background} you can run a
 * Record UDF on the result set of a scan. Scans using Records UDFs are run
 * in the background on the server and do not return the records to the client.
 *
 * For additional information please refer to the section on
 * ⇑Record UDFs
 * in the Aerospike technical documentation.
 *
 * @param {Client} client - A client instance.
 * @param {string} ns - The namescape.
 * @param {string} set - The name of a set.
 * @param {object} [options] - Scan parameters.
 * @param {Array<string>} [options.select] - List of bin names to select. See
 * {@link Scan#select}.
 * @param {number} [options.priority] - Priority level at which the scan will
 * be executed. See {@link Scan#priority}.
 * @param {number} [options.percent=100] - Percentage of records to scan. See
 * {@link Scan#percent}.
 * @param {boolean} [options.nobins=false] - Whether only meta data should be
 * returned. See {@link Scan#nobins}.
 * @param {boolean} [options.concurrent=false] - Whether all cluster nodes
 * should be scanned concurrently. See {@link Scan#concurrent}.
 *
 * @see {@link Client#scan} to create new instances of this class.
 *
 * @since v2.0
 *
 * @example
 *
 * const Aerospike = require('aerospike')
 *
 * Aerospike.connect((error, client) => {
 *   if (error) throw error
 *
 *   var scan = client.scan('test', 'demo')
 *   scan.priority = Aerospike.scanPriority.LOW
 *   scan.percent = 50 // scan only 50% of all records in the set
 *
 *   var recordsSeen = 0
 *   var stream = scan.foreach()
 *   stream.on('error', (error) => { throw error })
 *   stream.on('end', () => client.close())
 *   stream.on('data', (record) => {
 *     console.log(record)
 *     recordsSeen++
 *     if (recordsSeen > 100) stream.abort() // We've seen enough!
 *   })
 * })
 */
function Scan (client, ns, set, options) {
  if (typeof set === 'object') {
    options = set
    set = null
  }

  this.client = client

  /**
   * Namespace to scan.
   * @member {string} Scan#ns
   */
  this.ns = ns

  /**
   * Name of the set to scan.
   * @member {string} Scan#set
   */
  this.set = set

  /**
   * List of bin names to be selected by the scan. If a scan specifies bins to
   * be selected, then only those bins will be returned. If no bins are
   * selected, then all bins will be returned (unless {@link Scan#nobins} is
   * set to true).
   *
   * @member {string[]} Scan#selected
   *
   * @see Use {@link Scan#select} to specify the bins to select.
   */
  this.selected = options.select

  /**
   * Priority level at which the scan will be executed.
   *
   * @member {number} Scan#priority
   *
   * @see {@link module:aerospike.scanPriority} for enumeration of allowed values.
   */
  this.priority = options.priority

  /**
   * Percentage of records in the cluster to scan.
   *
   * @member {number} Scan#percent
   */
  this.percent = options.percent

  /**
   * If set to true, the scan will return only meta data, and exclude bins.
   *
   * @member {boolean} Scan#nobins
   */
  this.nobins = options.nobins

  /**
   * If set to true, all cluster nodes will be scanned in parallel.
   *
   * @member {boolean} Scan#concurrent.
   */
  this.concurrent = options.concurrent
}

/**
 * @function Scan#select
 *
 * @summary Specify the names of bins to be selected by the scan.
 *
 * @description If a scan specifies bins to be selected, then only those bins
 * will be returned. If no bins are selected, then all bins will be returned.
 * (Unless {@link Scan#nobins} is set to true.)
 *
 * @param {...string} bins - List of bin names to return.
 */
Scan.prototype.select = function (bins) {
  if (Array.isArray(bins)) {
    this.selected = bins
  } else {
    this.selected = Array.prototype.slice.call(arguments)
  }
}

/**
 * @function Scan#background
 *
 * @summary Perform a read-write background scan and apply a Lua user-defined
 * function (UDF) to each record.
 *
 * @description When a background scan is initiated, the client will not wait
 * for results from the database. Instead a {@link Job} instance will be
 * returned, which can be used to query the scan status on the database.
 *
 * @param {string} udfModule - UDF module name.
 * @param {string} udfFunction - UDF function name.
 * @param {Array<*>} [udfArgs] - Arguments for the function.
 * @param {ScanPolicy} [policy] - The Scan Policy to use for this operation.
 * @param {number} [scanID] - Job ID to use for the scan; will be assigned
 * randomly if zero or undefined.
 * @param {Client~jobCallback} [callback] - The function to call when the operation completes.
 *
 * @returns {?Promise} If no callback function is passed, the function returns
 * a Promise that resolves to a Job instance.
 */
Scan.prototype.background = function (udfModule, udfFunction, udfArgs, policy, scanID, callback) {
  if (typeof udfArgs === 'function') {
    callback = udfArgs
    udfArgs = null
  } else if (typeof policy === 'function') {
    callback = policy
    policy = null
  } else if (typeof scanID === 'function') {
    callback = scanID
    scanID = null
  }

  this.udf = {
    module: udfModule,
    funcname: udfFunction,
    args: udfArgs
  }
  scanID = scanID || Job.safeRandomJobID()

  let cmd = new Commands.ScanBackground(this.client, [this.ns, this.set, this, policy, scanID], callback)
  cmd.convertResult = () => new Job(this.client, scanID, 'scan')
  return cmd.execute()
}

/**
 * @function Scan#foreach
 *
 * @summary Performs a read-only scan on each node in the cluster. As the scan
 * iterates through each partition, it returns the current version of each
 * record to the client.
 *
 * @param {ScanPolicy} [policy] - The Scan Policy to use for this operation.
 *
 * @returns {RecordStream}
 */
Scan.prototype.foreach = function (policy, dataCb, errorCb, endCb) {
  if (this.udf) throw new Error('Record UDF can only be applied using background scan.')
  var stream = new RecordStream(this.client)
  if (dataCb) stream.on('data', dataCb)
  if (errorCb) stream.on('error', errorCb)
  if (endCb) stream.on('end', endCb)

  var scanID = Job.safeRandomJobID()
  let args = [this.ns, this.set, this, policy, scanID]
  let cmd = new Commands.Scan(stream, args)
  cmd.execute()

  stream.job = new Job(this.client, scanID, 'scan')
  return stream
}

module.exports = Scan
<commit_msg>Remove trailing dot from member name<commit_after>// *****************************************************************************
// Copyright 2013-2018 Aerospike, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// *****************************************************************************

'use strict'

const Commands = require('./commands')
const Job = require('./job')
const RecordStream = require('./record_stream')

/**
 * @class Scan
 * @classdesc The scan object created by calling {@link Client#scan} is used
 * for executing record scans on the specified namespace and set (optional).
 * Scans can return a set of records as a {@link RecordStream} or apply an
 * Aerospike UDF (user-defined function) on each of the records on the server.
 *
 * For more information, please refer to the section on
 * ⇑Scans
 * in the Aerospike technical documentation.
 *
 * #### Selecting Bins
 *
 * Using {@link Scan#select} it is possible to select a subset of bins which
 * should be returned by the query. If no bins are selected, then the whole
 * record will be returned. If the {@link Scan#nobins} property is set to
 * true the only the record meta data (ttl, generation, etc.) will
 * be returned.
 *
 * #### Executing a Scan
 *
 * A scan is executed using {@link Scan#foreach}. The method returns a {@link
 * RecordStream} which emits a data event for each record returned
 * by the scan. The scan can be aborted at any time by calling
 * {@link RecordStream#abort}.
 *
 * #### Executing Record UDFs using Background Scans
 *
 * Record UDFs perform operations on a single record such as updating records
 * based on a set of parameters. Using {@link Scan#background} you can run a
 * Record UDF on the result set of a scan. Scans using Records UDFs are run
 * in the background on the server and do not return the records to the client.
 *
 * For additional information please refer to the section on
 * ⇑Record UDFs
 * in the Aerospike technical documentation.
 *
 * @param {Client} client - A client instance.
 * @param {string} ns - The namescape.
 * @param {string} set - The name of a set.
 * @param {object} [options] - Scan parameters.
 * @param {Array<string>} [options.select] - List of bin names to select. See
 * {@link Scan#select}.
 * @param {number} [options.priority] - Priority level at which the scan will
 * be executed. See {@link Scan#priority}.
 * @param {number} [options.percent=100] - Percentage of records to scan. See
 * {@link Scan#percent}.
 * @param {boolean} [options.nobins=false] - Whether only meta data should be
 * returned. See {@link Scan#nobins}.
 * @param {boolean} [options.concurrent=false] - Whether all cluster nodes
 * should be scanned concurrently. See {@link Scan#concurrent}.
 *
 * @see {@link Client#scan} to create new instances of this class.
 *
 * @since v2.0
 *
 * @example
 *
 * const Aerospike = require('aerospike')
 *
 * Aerospike.connect((error, client) => {
 *   if (error) throw error
 *
 *   var scan = client.scan('test', 'demo')
 *   scan.priority = Aerospike.scanPriority.LOW
 *   scan.percent = 50 // scan only 50% of all records in the set
 *
 *   var recordsSeen = 0
 *   var stream = scan.foreach()
 *   stream.on('error', (error) => { throw error })
 *   stream.on('end', () => client.close())
 *   stream.on('data', (record) => {
 *     console.log(record)
 *     recordsSeen++
 *     if (recordsSeen > 100) stream.abort() // We've seen enough!
 *   })
 * })
 */
function Scan (client, ns, set, options) {
  if (typeof set === 'object') {
    options = set
    set = null
  }

  this.client = client

  /**
   * Namespace to scan.
   * @member {string} Scan#ns
   */
  this.ns = ns

  /**
   * Name of the set to scan.
   * @member {string} Scan#set
   */
  this.set = set

  /**
   * List of bin names to be selected by the scan. If a scan specifies bins to
   * be selected, then only those bins will be returned. If no bins are
   * selected, then all bins will be returned (unless {@link Scan#nobins} is
   * set to true).
   *
   * @member {string[]} Scan#selected
   *
   * @see Use {@link Scan#select} to specify the bins to select.
   */
  this.selected = options.select

  /**
   * Priority level at which the scan will be executed.
   *
   * @member {number} Scan#priority
   *
   * @see {@link module:aerospike.scanPriority} for enumeration of allowed values.
   */
  this.priority = options.priority

  /**
   * Percentage of records in the cluster to scan.
   *
   * @member {number} Scan#percent
   */
  this.percent = options.percent

  /**
   * If set to true, the scan will return only meta data, and exclude bins.
   *
   * @member {boolean} Scan#nobins
   */
  this.nobins = options.nobins

  /**
   * If set to true, all cluster nodes will be scanned in parallel.
   *
   * @member {boolean} Scan#concurrent
   */
  this.concurrent = options.concurrent
}

/**
 * @function Scan#select
 *
 * @summary Specify the names of bins to be selected by the scan.
 *
 * @description If a scan specifies bins to be selected, then only those bins
 * will be returned. If no bins are selected, then all bins will be returned.
 * (Unless {@link Scan#nobins} is set to true.)
 *
 * @param {...string} bins - List of bin names to return.
 */
Scan.prototype.select = function (bins) {
  if (Array.isArray(bins)) {
    this.selected = bins
  } else {
    this.selected = Array.prototype.slice.call(arguments)
  }
}

/**
 * @function Scan#background
 *
 * @summary Perform a read-write background scan and apply a Lua user-defined
 * function (UDF) to each record.
 *
 * @description When a background scan is initiated, the client will not wait
 * for results from the database. Instead a {@link Job} instance will be
 * returned, which can be used to query the scan status on the database.
 *
 * @param {string} udfModule - UDF module name.
 * @param {string} udfFunction - UDF function name.
 * @param {Array<*>} [udfArgs] - Arguments for the function.
 * @param {ScanPolicy} [policy] - The Scan Policy to use for this operation.
 * @param {number} [scanID] - Job ID to use for the scan; will be assigned
 * randomly if zero or undefined.
 * @param {Client~jobCallback} [callback] - The function to call when the operation completes.
 *
 * @returns {?Promise} If no callback function is passed, the function returns
 * a Promise that resolves to a Job instance.
 */
Scan.prototype.background = function (udfModule, udfFunction, udfArgs, policy, scanID, callback) {
  if (typeof udfArgs === 'function') {
    callback = udfArgs
    udfArgs = null
  } else if (typeof policy === 'function') {
    callback = policy
    policy = null
  } else if (typeof scanID === 'function') {
    callback = scanID
    scanID = null
  }

  this.udf = {
    module: udfModule,
    funcname: udfFunction,
    args: udfArgs
  }
  scanID = scanID || Job.safeRandomJobID()

  let cmd = new Commands.ScanBackground(this.client, [this.ns, this.set, this, policy, scanID], callback)
  cmd.convertResult = () => new Job(this.client, scanID, 'scan')
  return cmd.execute()
}

/**
 * @function Scan#foreach
 *
 * @summary Performs a read-only scan on each node in the cluster. As the scan
 * iterates through each partition, it returns the current version of each
 * record to the client.
 *
 * @param {ScanPolicy} [policy] - The Scan Policy to use for this operation.
 *
 * @returns {RecordStream}
 */
Scan.prototype.foreach = function (policy, dataCb, errorCb, endCb) {
  if (this.udf) throw new Error('Record UDF can only be applied using background scan.')
  var stream = new RecordStream(this.client)
  if (dataCb) stream.on('data', dataCb)
  if (errorCb) stream.on('error', errorCb)
  if (endCb) stream.on('end', endCb)

  var scanID = Job.safeRandomJobID()
  let args = [this.ns, this.set, this, policy, scanID]
  let cmd = new Commands.Scan(stream, args)
  cmd.execute()

  stream.job = new Job(this.client, scanID, 'scan')
  return stream
}

module.exports = Scan
<|endoftext|>


<commit_before>/* ============================================================================

 >4SESz.,     _,     ,gSEE2zx.,_        .azx                    ,w.
@Sh. "QEE3.  JEE3.  &ss  `*4EEEEE2x.,_  "EEV  ,aS5^;dEEEE2x.,   VEEF  _
\E2`_,gF4EEEx.?jF   EE5L       `*4EEEEE2zpn..ZEEF ;sz.  `*EEESzw.w* '|EE.
  ,dEEF   `"?j]  _,_   ,_  _,     _,.     L.EEEF  !EEF  _,,  `"``    EE7   ,,_
 :EEE7 ,ws,`|EEL`JEEL`JEE)`JEEL zE5` E3. / [EE3  ,w.  zE2` Ek .zE5^JZE3.,6EF [3
 {EEE. VEE7.EE2  AE3. EEV  ZEEL{EEL ws. ;  [EE1  EEEt{E3. JEELEE3. JE5LJEEF ,w,
  \EEk,,>^ JEEL,@EEF ZE5L,ZE5^ "Q3. V2`.    \EEk,,J' "Q[ yE2^ VE[_zEE[,"QEL V5F
		  ,ss  :EE7 ;EEF               L,szzw..            ,.,            ``
		  \E5.,E5F  EE1.              /; ``*4EEEZhw._      EEEL
			````     ``              JEEE.     `"45EEEhw.,,,]

From 2010 till ∞
typecode-js v 0.1
*/

define(['jquery'], function($) {

	var window = this,
	NI = {},
	fakeConsole,
	_id = 0;

	NI.ex = {

		checkStr: function(s) {
			var t = typeof s;
			if (t === 'string') { return true; }
			console.error('Expected string, but found "'+ String(t) +'" instead');
		},

		checkFn: function(fn) {
			if ($.isFunction(fn)) { return true; }
			console.error('Expected function, but found "'+ typeof fn +'" instead');
		},

		checkJQ: function(o) {
			if (o instanceof $) { return true; }
			console.error('Expected jQuery object, but found "'+ typeof o +'" instead');
		},

		checkJQNode: function($e, type) {
			NI.ex.checkJQ($e);
			type = type.toLowerCase();
			if ($e.length === 1) {
				if ($e[0].nodeName.toLowerCase() === type) {
					return true;
				}
			}
			throw new TypeError('Expected jQuery object holding single '+ type +' element');
		},

		typeOf: function(v) {
			var s = typeof v;
			if (s === 'object') {
				if (v) {
					if (typeof v.length === 'number' &&
						!(v.propertyIsEnumerable('length')) &&
						typeof v.splice === 'function') {
						s = 'array';
					}
				} else {
					s = 'null';
				}
			}
			return s;
		},

		isEmpty: function(v) {
			NI.ex.checkStr(v);
			return $.trim(v) ?
				false : true;
		},

		isHeadless: function($e) {
			var node = $e[0];
			if (!node.parentNode) {
				return true;
			}
			if (node.parentNode === NI.co.node_types.DOCUMENT_NODE) {
				return true;
			}
			return false;
		}
	};

	NI.fn = {

		get_console: function(debug) {
			if (debug && typeof window.console !== 'undefined') {
				return window.console;
			}
			if (!fakeConsole) {
				fakeConsole = {};
				$.each(('assert,count,debug,dir,dirxml,error,exception,\
				group,groupCollapsed,groupEnd,info,log,markTimeline,\
				profile,profileEnd,time,timeEnd,trace,warn').split(','), function() {
					fakeConsole[this] = $.noop;
				});
			}
			return fakeConsole;
		},

		// via http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/
		load_script: function(url, callback) {
			var script = window.document.createElement('script');
			script.type = 'text/javascript';
			if (script.readyState) {
				script.onreadystatechange = function() {
					if (script.readyState == 'loaded' || script.readyState == 'complete') {
						script.onreadystatechange = null;
						if ($.isFunction(callback)) {
							callback();
						}
					}
				};
			} else {
				script.onload = function() {
					if ($.isFunction(callback)) {
						callback();
					}
				};
			}
			script.src = url;
			window.document.getElementsByTagName('head')[0].appendChild(script);
		},

		guid: function(prefix) {
			var id = _id++;
			return (prefix || 'obj_')+ id;
		},

		random_element: function(array) {
			if (NI.ex.typeOf(array) === 'array' && array.length > 0) {
				return array[window.Math.floor(NI.math.random(array.length))];
			}
		},

		// debounce implementation from Underscore.js
		// http://documentcloud.github.com/underscore/
		debounce: function(fn, delay) {
			var timer;
			return function() {
				var self = this, args = arguments,
				execute = function() {
					timer = null;
					fn.apply(self, args);
				};
				window.clearTimeout(timer);
				timer = window.setTimeout(execute, delay);
			};
		},

		// String interpolation
		// var s = interpolate('Hello %', ['world'])
		interpolate: function(str, args) {
			var i;
			if (args) {
				for (i = 0; i < args.length; i += 1) {
					str = str.replace('%', args[i]);
				}
			}
			return str;
		}
	};

	NI.co = {

		keyboard: {

			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38
		},

		node_types: {

			ELEMENT_NODE: 1,
			ATTRIBUTE_NODE: 2,
			TEXT_NODE: 3,
			CDATA_SECTION_NODE: 4,
			ENTITY_REFERENCE_NODE: 5,
			ENTITY_NODE: 6,
			PROCESSING_INSTRUCTION_NODE: 7,
			COMMENT_NODE: 8,
			DOCUMENT_NODE: 9,
			DOCUMENT_TYPE_NODE: 10,
			DOCUMENT_FRAGMENT_NODE: 11,
			NOTATION_NODE: 12
		},

		directions: {

			UP: 0,
			RIGHT: 1,
			DOWN: 2,
			LEFT: 3
		}
	};

	NI.math = {

		random: function() {
			if (arguments.length === 0) {
				return window.Math.random();
			} else if (arguments.length === 1) {
				return window.Math.random()*arguments[0];
			}
			return window.Math.random()*(arguments[1] - arguments[0]) + arguments[0];
		},

		round: function(n, places) {
			var p = window.Math.pow(10, places);
			return window.Math.round(n*p)/p;
		}
	};

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

	window.NI = NI;

});<commit_msg>added NI.fn.once_visible<commit_after>/* ============================================================================

 >4SESz.,     _,     ,gSEE2zx.,_        .azx                    ,w.
@Sh. "QEE3.  JEE3.  &ss  `*4EEEEE2x.,_  "EEV  ,aS5^;dEEEE2x.,   VEEF  _
\E2`_,gF4EEEx.?jF   EE5L       `*4EEEEE2zpn..ZEEF ;sz.  `*EEESzw.w* '|EE.
  ,dEEF   `"?j]  _,_   ,_  _,     _,.     L.EEEF  !EEF  _,,  `"``    EE7   ,,_
 :EEE7 ,ws,`|EEL`JEEL`JEE)`JEEL zE5` E3. / [EE3  ,w.  zE2` Ek .zE5^JZE3.,6EF [3
 {EEE. VEE7.EE2  AE3. EEV  ZEEL{EEL ws. ;  [EE1  EEEt{E3. JEELEE3. JE5LJEEF ,w,
  \EEk,,>^ JEEL,@EEF ZE5L,ZE5^ "Q3. V2`.    \EEk,,J' "Q[ yE2^ VE[_zEE[,"QEL V5F
		  ,ss  :EE7 ;EEF               L,szzw..            ,.,            ``
		  \E5.,E5F  EE1.              /; ``*4EEEZhw._      EEEL
			````     ``              JEEE.     `"45EEEhw.,,,]

From 2010 till ∞
typecode-js v 0.1
*/

define(['jquery'], function($) {

	var window = this,
	NI = {},
	fakeConsole,
	_id = 0;

	NI.ex = {

		checkStr: function(s) {
			var t = typeof s;
			if (t === 'string') { return true; }
			console.error('Expected string, but found "'+ String(t) +'" instead');
		},

		checkFn: function(fn) {
			if ($.isFunction(fn)) { return true; }
			console.error('Expected function, but found "'+ typeof fn +'" instead');
		},

		checkJQ: function(o) {
			if (o instanceof $) { return true; }
			console.error('Expected jQuery object, but found "'+ typeof o +'" instead');
		},

		checkJQNode: function($e, type) {
			NI.ex.checkJQ($e);
			type = type.toLowerCase();
			if ($e.length === 1) {
				if ($e[0].nodeName.toLowerCase() === type) {
					return true;
				}
			}
			throw new TypeError('Expected jQuery object holding single '+ type +' element');
		},

		typeOf: function(v) {
			var s = typeof v;
			if (s === 'object') {
				if (v) {
					if (typeof v.length === 'number' &&
						!(v.propertyIsEnumerable('length')) &&
						typeof v.splice === 'function') {
						s = 'array';
					}
				} else {
					s = 'null';
				}
			}
			return s;
		},

		isEmpty: function(v) {
			NI.ex.checkStr(v);
			return $.trim(v) ?
				false : true;
		},

		isHeadless: function($e) {
			var node = $e[0];
			if (!node.parentNode) {
				return true;
			}
			if (node.parentNode === NI.co.node_types.DOCUMENT_NODE) {
				return true;
			}
			return false;
		}
	};

	NI.fn = {

		get_console: function(debug) {
			if (debug && typeof window.console !== 'undefined') {
				return window.console;
			}
			if (!fakeConsole) {
				fakeConsole = {};
				$.each(('assert,count,debug,dir,dirxml,error,exception,\
				group,groupCollapsed,groupEnd,info,log,markTimeline,\
				profile,profileEnd,time,timeEnd,trace,warn').split(','), function() {
					fakeConsole[this] = $.noop;
				});
			}
			return fakeConsole;
		},

		// via http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/
		load_script: function(url, callback) {
			var script = window.document.createElement('script');
			script.type = 'text/javascript';
			if (script.readyState) {
				script.onreadystatechange = function() {
					if (script.readyState == 'loaded' || script.readyState == 'complete') {
						script.onreadystatechange = null;
						if ($.isFunction(callback)) {
							callback();
						}
					}
				};
			} else {
				script.onload = function() {
					if ($.isFunction(callback)) {
						callback();
					}
				};
			}
			script.src = url;
			window.document.getElementsByTagName('head')[0].appendChild(script);
		},

		guid: function(prefix) {
			var id = _id++;
			return (prefix || 'obj_')+ id;
		},

		random_element: function(array) {
			if (NI.ex.typeOf(array) === 'array' && array.length > 0) {
				return array[window.Math.floor(NI.math.random(array.length))];
			}
		},

		// debounce implementation from Underscore.js
		// http://documentcloud.github.com/underscore/
		debounce: function(fn, delay) {
			var timer;
			return function() {
				var self = this, args = arguments,
				execute = function() {
					timer = null;
					fn.apply(self, args);
				};
				window.clearTimeout(timer);
				timer = window.setTimeout(execute, delay);
			};
		},

		once_visible: function($e, fn) {
			if ($e.is(':visible')) {
				fn();
			} else {
				setTimeout(function() {
						NI.fn.once_visible($e, fn);
				}, 10);
			}
		},

		// String interpolation
		// var s = interpolate('Hello %', ['world'])
		interpolate: function(str, args) {
			var i;
			if (args) {
				for (i = 0; i < args.length; i += 1) {
					str = str.replace('%', args[i]);
				}
			}
			return str;
		}
	};

	NI.co = {

		keyboard: {

			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38
		},

		node_types: {

			ELEMENT_NODE: 1,
			ATTRIBUTE_NODE: 2,
			TEXT_NODE: 3,
			CDATA_SECTION_NODE: 4,
			ENTITY_REFERENCE_NODE: 5,
			ENTITY_NODE: 6,
			PROCESSING_INSTRUCTION_NODE: 7,
			COMMENT_NODE: 8,
			DOCUMENT_NODE: 9,
			DOCUMENT_TYPE_NODE: 10,
			DOCUMENT_FRAGMENT_NODE: 11,
			NOTATION_NODE: 12
		},

		directions: {

			UP: 0,
			RIGHT: 1,
			DOWN: 2,
			LEFT: 3
		}
	};

	NI.math = {

		random: function() {
			if (arguments.length === 0) {
				return window.Math.random();
			} else if (arguments.length === 1) {
				return window.Math.random()*arguments[0];
			}
			return window.Math.random()*(arguments[1] - arguments[0]) + arguments[0];
		},

		round: function(n, places) {
			var p = window.Math.pow(10, places);
			return window.Math.round(n*p)/p;
		}
	};

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

	window.NI = NI;

});<|endoftext|>


<commit_before>(function() {
  var save = function() {
    return true;
  };

  var goback = function() {
    var gui = require('nw.gui');
    var win = gui.Window.get().window;
    win.location = 'index.html';
  };

  $('#save').click(function() {
    if (!save()) return;
    goback();
  });

  $('#cancel').click(goback);
})();

<commit_msg>Edit screen implementation<commit_after>(function() {
  /*
   * Loads current settings
   */
  var load = function() {
    $('#workmin').val( localStorage.workTimeMin || 0 );
    $('#worksec').val( localStorage.workTimeSec || 0 );
    $('#restmin').val( localStorage.restTimeMin || 0 );
    $('#restsec').val( localStorage.restTimeSec || 0 );
    var tasks = localStorage.tasks || '[]';
    tasks = JSON.parse(tasks);
    var inputs = $('.add-tasks-section input');
    tasks.forEach(function(task, i) {
      $(inputs[i]).val(task);
    });
  };

  /*
   * Saves settings in local storage
   */
  var save = function() {
    localStorage.workTimeMin = $('#workmin').val();
    localStorage.workTimeSec = $('#worksec').val();
    localStorage.restTimeMin = $('#restmin').val();
    localStorage.restTimeSec = $('#restsec').val();
    var tasks = [];
    $('.add-tasks-section input').each(function(i, el) {
      tasks.push( $(el).val().trim() );
    });
    tasks = _.compact(tasks);
    localStorage.tasks = JSON.stringify(tasks);
    return true;
  };

  /*
   * Return to main screen
   */
  var goback = function() {
    var gui = require('nw.gui');
    var win = gui.Window.get().window;
    win.location = 'index.html';
  };

  /*** Event listeners ***/
  $('#save').click(function() {
    if (!save()) return;
    goback();
  });

  $('#cancel').click(goback);

  /*** Start here ***/
  load();
})();

<|endoftext|>


<commit_before>const hash = require('crypto').createHash('sha1')

module.exports = str => hash.update(str).digest('hex')
<commit_msg>fixed sha1 bug<commit_after>const crypto = require('crypto')

module.exports = str => crypto.createHash('sha1').update(str).digest('hex')
<|endoftext|>


<commit_before>/*!
 * Методы live библиотеки Snakeskin
 */

if (/\[native code]/.test(Object.keys && Object.keys.toString())) {
	var keys = Object.keys;
}

/**
 * Конструктор объекта StringBuffer
 *
 * @expose
 * @constructor
 * @return {!Array}
 */
Snakeskin.StringBuffer = function () {
	return [];
};

/**
 * Итератор массива или объекта (с проверкой hasOwnProperty)
 *
 * @expose
 * @param {(Array|Object)} obj - исходный объект
 * @param {(function(?, number, !Array, boolean, boolean, number)|function(?, string, !Object, number, boolean, boolean, number))} callback - функция обратного вызова
 */
Snakeskin.forEach = function (obj, callback) {
	if (!obj) {
		return;
	}

	var length = 0;

	if (Array.isArray(obj)) {
		length = obj.length;
		for (let i = -1; ++i < length;) {
			if (callback(obj[i], i, obj, i === 0, i === length - 1, length) === false) {
				break;
			}
		}

	} else if (keys) {
		let arr = keys(obj);
		length = arr.length;

		for (let i = -1; ++i < length;) {
			if (callback(obj[arr[i]], arr[i], obj, i, i === 0, i === length - 1, length) === false) {
				break;
			}
		}

	} else {
		let i = 0;

		if (callback.length >= 6) {
			for (let key in obj) {
				/* istanbul ignore if */
				if (!obj.hasOwnProperty(key)) {
					continue;
				}

				length++;
			}
		}

		for (let key in obj) {
			/* istanbul ignore if */
			if (!obj.hasOwnProperty(key)) {
				continue;
			}

			if (callback(obj[key], key, obj, i, i === 0, i === length - 1, length) === false) {
				break;
			}

			i++;
		}
	}
};

/**
 * Итератор объекта без проверки hasOwnProperty
 *
 * @expose
 * @param {Object} obj - исходный объект
 * @param {function(?, string, !Object, number, boolean, boolean, number)} callback - функция обратного вызова
 */
Snakeskin.forIn = function (obj, callback) {
	if (!obj) {
		return;
	}

	var length = 0,
		i = 0;

	if (callback.length >= 6) {
		for (let key in obj) {
			length++;
		}
	}

	for (let key in obj) {
		if (callback(obj[key], key, obj, i, i === 0, i === length - 1, length) === false) {
			break;
		}

		i++;
	}
};

var inlineTagMap = {
	'img': true,
	'link': true,
	'embed': true,
	'br': true,
	'hr': true,
	'wbr': true,
	'meta': true,
	'input': true,
	'source': true,
	'track': true,
	'base': true,
	'area': true,
	'col': true,
	'param': true
};

/**
 * Вставить заданный узел или текст в исходный
 *
 * @expose
 * @param {!Node} node - исходный элемент
 * @param {(!Node|string)} obj - элемент для вставки или текст
 * @return {(!Node|string)}
 */
Snakeskin.appendChild = function (node, obj) {
	if (node['tagName'] && inlineTagMap[node['tagName'].toLowerCase()]) {
		return String(obj).trim();
	}

	if (typeof obj === 'string') {
		obj = document.createTextNode(obj);
	}

	node.appendChild(obj);
	return obj;
};
<commit_msg>Исправление ошибки в jsDoc<commit_after>/*!
 * Методы live библиотеки Snakeskin
 */

if (/\[native code]/.test(Object.keys && Object.keys.toString())) {
	var keys = Object.keys;
}

/**
 * Конструктор объекта StringBuffer
 *
 * @expose
 * @constructor
 * @return {!Array}
 */
Snakeskin.StringBuffer = function () {
	return [];
};

/**
 * Итератор массива или объекта (с проверкой hasOwnProperty)
 *
 * @expose
 * @param {(Array|Object|undefined)} obj - исходный объект
 * @param {(function(?, number, !Array, boolean, boolean, number)|function(?, string, !Object, number, boolean, boolean, number))} callback - функция обратного вызова
 */
Snakeskin.forEach = function (obj, callback) {
	if (!obj) {
		return;
	}

	var length = 0;

	if (Array.isArray(obj)) {
		length = obj.length;
		for (let i = -1; ++i < length;) {
			if (callback(obj[i], i, obj, i === 0, i === length - 1, length) === false) {
				break;
			}
		}

	} else if (keys) {
		let arr = keys(obj);
		length = arr.length;

		for (let i = -1; ++i < length;) {
			if (callback(obj[arr[i]], arr[i], obj, i, i === 0, i === length - 1, length) === false) {
				break;
			}
		}

	} else {
		let i = 0;

		if (callback.length >= 6) {
			for (let key in obj) {
				/* istanbul ignore if */
				if (!obj.hasOwnProperty(key)) {
					continue;
				}

				length++;
			}
		}

		for (let key in obj) {
			/* istanbul ignore if */
			if (!obj.hasOwnProperty(key)) {
				continue;
			}

			if (callback(obj[key], key, obj, i, i === 0, i === length - 1, length) === false) {
				break;
			}

			i++;
		}
	}
};

/**
 * Итератор объекта без проверки hasOwnProperty
 *
 * @expose
 * @param {Object} obj - исходный объект
 * @param {function(?, string, !Object, number, boolean, boolean, number)} callback - функция обратного вызова
 */
Snakeskin.forIn = function (obj, callback) {
	if (!obj) {
		return;
	}

	var length = 0,
		i = 0;

	if (callback.length >= 6) {
		for (let key in obj) {
			length++;
		}
	}

	for (let key in obj) {
		if (callback(obj[key], key, obj, i, i === 0, i === length - 1, length) === false) {
			break;
		}

		i++;
	}
};

var inlineTagMap = {
	'img': true,
	'link': true,
	'embed': true,
	'br': true,
	'hr': true,
	'wbr': true,
	'meta': true,
	'input': true,
	'source': true,
	'track': true,
	'base': true,
	'area': true,
	'col': true,
	'param': true
};

/**
 * Вставить заданный узел или текст в исходный
 *
 * @expose
 * @param {!Node} node - исходный элемент
 * @param {(!Node|string)} obj - элемент для вставки или текст
 * @return {(!Node|string)}
 */
Snakeskin.appendChild = function (node, obj) {
	if (node['tagName'] && inlineTagMap[node['tagName'].toLowerCase()]) {
		return String(obj).trim();
	}

	if (typeof obj === 'string') {
		obj = document.createTextNode(obj);
	}

	node.appendChild(obj);
	return obj;
};
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;

function Lock(){
	this.initialize.apply(this,arguments);
}

Lock.prototype = {
    initialize:function(gpio){
        this.gpio = gpio;
        this.state = "initialize";
	}
    ,attach:function(config){
        this.emitter = new EventEmitter();
        this.config = config;

        this.readPort(config.inA,'inA',this.emitter);
        this.readPort(config.inB,'inB',this.emitter);
        this.readPort(config.outA,'outA',this.emitter);
        this.readPort(config.outB,'outB',this.emitter);

        this.gpio.open(config.motor1,"output");
        this.gpio.open(config.motor2,"output");
        this.beginWatcher(this.emitter);
	}
    ,lock:function(){
        this.state = "toLock";
        if(this.isLocked()){
            return;
        }
        this.toLock();
    }
    ,open:function(){
        this.state = "toOpen";
        if(this.isOpen()){
            return;
        }
        this.toOpen();
    }
    ,neutral:function(){
        this.state = "toNeutral";
        if(this.isNeutral()){
            return;
        }
        if(this.isOpened()){
            this.openedToNeutral();
        }else{
            this.lockedToNeutral();
        }
    }
    ,toLock:function(){
        this.turnRight();
    }
    ,toOpen:function(){
        this.turnLeft();
    }
    ,openedToNeutral:function(){
        this.turnRight();
    }
    ,lockedToNeutral():function(){
        this.turnLeft();
    }
    ,isOpened:function(){
        return this.inA;
    }
    ,isLocked:function(){
        return this.inB;
    }
    ,isNeutral:function(){
        return this.outA && this.outB;
    }
    ,turnRight:function(){
        this.gpio.write(this.config.motor1,1);
        this.gpio.write(this.config.motor2,0);
    }
    ,turnLeft:function(){
        this.gpio.write(this.config.motor1,0);
        this.gpio.write(this.config.motor2,1);
    }
    ,stopMotor:function(){
        this.gpio.write(this.config.motor1,0);
        this.gpio.write(this.config.motor2,0);
    }
    ,beginWatcher:function(emitter){
        var self = this;
        emitter.on("onRead",function(){
           if(self.state == "toLock" && self.isLocked()){
               self.neutral();
           }else if(self.state == "toOpen" && self.isOpened()){
               self.neutral();
           }else if(self.state == "toNeutral" && self.isNeutral()){
               self.state == "neutral";
           }
        });
    }
    ,readPort:function(pin,prop,emitter){
        var self = this;
        this.gpio.open(pin,"input pullup",function(){
            setInterval(function(){
                self.gpio.read(pin,function(e,v){
                    self[pin] = v ? false : true;
                    emitter.emit('onRead');
                });
            },100);
        });
    }
}

module.exports = Lock;
<commit_msg>fixed indent<commit_after>var EventEmitter = require('events').EventEmitter;

function Lock(){
	this.initialize.apply(this,arguments);
}

Lock.prototype = {
    initialize:function(gpio){
        this.gpio = gpio;
        this.state = "initialize";
    }
    ,attach:function(config){
        this.emitter = new EventEmitter();
        this.config = config;

        this.readPort(config.inA,'inA',this.emitter);
        this.readPort(config.inB,'inB',this.emitter);
        this.readPort(config.outA,'outA',this.emitter);
        this.readPort(config.outB,'outB',this.emitter);

        this.gpio.open(config.motor1,"output");
        this.gpio.open(config.motor2,"output");
        this.beginWatcher(this.emitter);
    }
    ,lock:function(){
        this.state = "toLock";
        if(this.isLocked()){
            return;
        }
        this.toLock();
    }
    ,open:function(){
        this.state = "toOpen";
        if(this.isOpen()){
            return;
        }
        this.toOpen();
    }
    ,neutral:function(){
        this.state = "toNeutral";
        if(this.isNeutral()){
            return;
        }
        if(this.isOpened()){
            this.openedToNeutral();
        }else{
            this.lockedToNeutral();
        }
    }
    ,toLock:function(){
        this.turnRight();
    }
    ,toOpen:function(){
        this.turnLeft();
    }
    ,openedToNeutral:function(){
        this.turnRight();
    }
    ,lockedToNeutral():function(){
        this.turnLeft();
    }
    ,isOpened:function(){
        return this.inA;
    }
    ,isLocked:function(){
        return this.inB;
    }
    ,isNeutral:function(){
        return this.outA && this.outB;
    }
    ,turnRight:function(){
        this.gpio.write(this.config.motor1,1);
        this.gpio.write(this.config.motor2,0);
    }
    ,turnLeft:function(){
        this.gpio.write(this.config.motor1,0);
        this.gpio.write(this.config.motor2,1);
    }
    ,stopMotor:function(){
        this.gpio.write(this.config.motor1,0);
        this.gpio.write(this.config.motor2,0);
    }
    ,beginWatcher:function(emitter){
        var self = this;
        emitter.on("onRead",function(){
           if(self.state == "toLock" && self.isLocked()){
               self.neutral();
           }else if(self.state == "toOpen" && self.isOpened()){
               self.neutral();
           }else if(self.state == "toNeutral" && self.isNeutral()){
               self.state == "neutral";
           }
        });
    }
    ,readPort:function(pin,prop,emitter){
        var self = this;
        this.gpio.open(pin,"input pullup",function(){
            setInterval(function(){
                self.gpio.read(pin,function(e,v){
                    self[pin] = v ? false : true;
                    emitter.emit('onRead');
                });
            },100);
        });
    }
}

module.exports = Lock;
<|endoftext|>


<commit_before>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0
const FIRST = 1
const FULL = 2
const LAST = 3

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Moon's angular size at distance a from Earth
const MOON_ANGULAR_SIZE = 0.5181

// Semi-mojor axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // Mean anomaly of the Sun
  // Convert from perigee coordinates to epoch 1980
  const sun_mean_anomaly = fixangle((360 / 365.2422) * day + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)

  // Solve Kepler's equation
  // True anomaly
  const sun_true_anomaly = 2 * todeg(Math.atan(Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(0.5 * kepler(sun_mean_anomaly, ECCENTRICITY))))

  // Suns's geometric ecliptic longuitude
  const sun_ecliptic_longitude = fixangle(sun_true_anomaly + ECLIPTIC_LONGITUDE_PERIGEE)

  // Orbital distance factor
  // XXX: capital vars should only be used for local constants
  const sun_orbital_distance_factor = ((1 + ECCENTRICITY * dcos(sun_true_anomaly)) / (1 - ECCENTRICITY * ECCENTRICITY))

  // Calculation of the Moon's position

  // Moon's mean longitude
  const moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH)

  // Moon's mean anomaly
  // XXX: capital vars should only be used for local constants
  const MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH)

  const evection = 1.2739 * dsin(2 * (moon_longitude - sun_ecliptic_longitude) - MM)

  // Annual equation
  const annual_eq = 0.1858 * dsin(sun_mean_anomaly)

  // Correction term
  // XXX: capital vars should only be used for local constants
  const A3 = 0.37 * dsin(sun_mean_anomaly)

  // XXX: capital vars should only be used for local constants
  const MmP = MM + evection - annual_eq - A3

  // Correction for the equation of the centre
  const mEc = 6.2886 * dsin(MmP)

  // Another correction term
  // XXX: capital vars should only be used for local constants
  const A4 = 0.214 * dsin(2 * MmP)

  // Corrected longitude
  const lP = moon_longitude + evection + mEc - annual_eq + A4

  // Variation
  const variation = 0.6583 * dsin(2 * (lP - sun_ecliptic_longitude))

  // True longitude
  const lPP = lP + variation

  // Calculation of the phase of the Moon

  // Age of the Moon, in degrees
  const moon_age = fixangle(lPP - sun_ecliptic_longitude)

  // Calculate distance of Moon from the centre of the Earth
  const moon_distance = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * dcos(MmP + mEc))

  return {
    phase: (1.0 / 360.0) * moon_age,
    illuminated: 0.5 * (1.0 - dcos(moon_age)),
    age: (SYNODIC_MONTH / 360.0) * moon_age,
    distance: moon_distance,
    angular_diameter: MOON_ANGULAR_SIZE * MOON_SMAXIS / moon_distance,
    sun_distance: SUN_SMAXIS / sun_orbital_distance_factor,
    sun_angular_diameter: SUN_ANGULAR_SIZE_SMAXIS * sun_orbital_distance_factor
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new
 * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the
 * true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + 0.25 * tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = k / 1236.85

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  switch (tphase & 3) {
    case NEW:
    case FULL:
      pt += (0.1734 - 0.000393 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.4068 * dsin(mprime) +
        0.0161 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0104 * dsin(2 * f) -
        0.0051 * dsin(m + mprime) -
        0.0074 * dsin(m - mprime) +
        0.0004 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0010 * dsin(2 * f - mprime) +
        0.0005 * dsin(m + 2 * mprime)
      break

    case FIRST:
    case LAST:
      pt += (0.1721 - 0.0004 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.6280 * dsin(mprime) +
        0.0089 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0079 * dsin(2 * f) -
        0.0119 * dsin(m + mprime) -
        0.0047 * dsin(m - mprime) +
        0.0003 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0021 * dsin(2 * f - mprime) +
        0.0003 * dsin(m + 2 * mprime) +
        0.0004 * dsin(m - 2 * mprime) -
        0.0003 * dsin(2 * m + mprime)

      switch (tphase & 1) {
        case (FIRST & 1):
          pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
          break

        case (LAST & 1):
          pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
          break
      }
      break
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1

  let k2
  let nt2
  while (1) {
    adate = adate + SYNODIC_MONTH
    k2 = k1 + 1
    nt2 = meanphase(adate, k2)
    if (nt1 <= sdate && sdate < nt2) {
      break
    }
    nt1 = nt2
    k1 = k2
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<commit_msg>Replaced the rest of the crazy variable names with saner ones.<commit_after>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0
const FIRST = 1
const FULL = 2
const LAST = 3

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Semi-major axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// MOON_SMAXIS premultiplied by the angular size of the Moon from the Earth
const MOON_ANGULAR_SIZE_SMAXIS = MOON_SMAXIS * 0.5181

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // calculate sun position
  const sun_mean_anomaly =
    (360.0 / 365.2422) * day +
    (ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)
  const sun_true_anomaly =
    2 * todeg(Math.atan(
      Math.sqrt((1.0 + ECCENTRICITY) / (1.0 - ECCENTRICITY)) *
      Math.tan(0.5 * kepler(sun_mean_anomaly, ECCENTRICITY))
    ))
  const sun_ecliptic_longitude =
    ECLIPTIC_LONGITUDE_PERIGEE + sun_true_anomaly
  const sun_orbital_distance_factor =
    (1 + ECCENTRICITY * dcos(sun_true_anomaly)) /
    (1 - ECCENTRICITY * ECCENTRICITY)

  // calculate moon position
  const moon_mean_longitude =
    MOON_MEAN_LONGITUDE_EPOCH + 13.1763966 * day
  const moon_mean_anomaly =
    moon_mean_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH
  const moon_evection =
    1.2739 * dsin(
      2 * (moon_mean_longitude - sun_ecliptic_longitude) - moon_mean_anomaly
    )
  const moon_annual_equation =
    0.1858 * dsin(sun_mean_anomaly)
  // XXX: what is the proper name for this value?
  const moon_mp =
    moon_mean_anomaly +
    moon_evection -
    moon_annual_equation -
    0.37 * dsin(sun_mean_anomaly)
  const moon_equation_center_correction =
    6.2886 * dsin(moon_mp)
  const moon_corrected_longitude =
    moon_mean_longitude +
    moon_evection +
    moon_equation_center_correction -
    moon_annual_equation +
    0.214 * dsin(2.0 * moon_mp)
  const moon_age =
    fixangle(
      moon_corrected_longitude -
      sun_ecliptic_longitude +
      0.6583 * dsin(
        2 * (moon_corrected_longitude - sun_ecliptic_longitude)
      )
    )
  const moon_distance =
    (MOON_SMAXIS * (1.0 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) /
    (1.0 + MOON_ECCENTRICITY * dcos(moon_mp + moon_equation_center_correction))

  return {
    phase: (1.0 / 360.0) * moon_age,
    illuminated: 0.5 * (1.0 - dcos(moon_age)),
    age: (SYNODIC_MONTH / 360.0) * moon_age,
    distance: moon_distance,
    angular_diameter: MOON_ANGULAR_SIZE_SMAXIS / moon_distance,
    sun_distance: SUN_SMAXIS / sun_orbital_distance_factor,
    sun_angular_diameter: SUN_ANGULAR_SIZE_SMAXIS * sun_orbital_distance_factor
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new moon, and a
 * phase selector (0, 1, 2, 3), obtain the true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + 0.25 * tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = (1.0 / 1236.85) * k

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  switch (tphase & 3) {
    case NEW:
    case FULL:
      pt += (0.1734 - 0.000393 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.4068 * dsin(mprime) +
        0.0161 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0104 * dsin(2 * f) -
        0.0051 * dsin(m + mprime) -
        0.0074 * dsin(m - mprime) +
        0.0004 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0010 * dsin(2 * f - mprime) +
        0.0005 * dsin(m + 2 * mprime)
      break

    case FIRST:
    case LAST:
      pt += (0.1721 - 0.0004 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.6280 * dsin(mprime) +
        0.0089 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0079 * dsin(2 * f) -
        0.0119 * dsin(m + mprime) -
        0.0047 * dsin(m - mprime) +
        0.0003 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0021 * dsin(2 * f - mprime) +
        0.0003 * dsin(m + 2 * mprime) +
        0.0004 * dsin(m - 2 * mprime) -
        0.0003 * dsin(2 * m + mprime)

      switch (tphase & 1) {
        case (FIRST & 1):
          pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
          break

        case (LAST & 1):
          pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
          break
      }
      break
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1 + SYNODIC_MONTH
  let k2 = k1 + 1
  let nt2 = meanphase(adate, k2)
  while (nt1 > sdate || sdate >= nt2) {
    adate += SYNODIC_MONTH
    k1++
    k2++
    nt1 = nt2
    nt2 = meanphase(adate, k2)
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

"use strict";

const states = require('./states');
const endpoint = require('./endpoint');
const loggingSupport = require('./loggingSupport');
const myScopeReporter = require('scope-reporter');
const scopeDefinitions = require('../lib/scopeDefinitions');

// Steps plain attributes without special handling
// may be extended by some properties like writable,...
const ATTRIBUTES = ['description'];

const logEndpoint = endpoint.createEndpoint("log", {
	"description": "logging endpoint. All logging goes through this endpoint",
	"out": true,
	"active": true,
	"default": true
});

const baseStep = {
	"name": "kronos-step",
	"description": "This step is the base class for step implementations",

	/**
	 * Creates the properties for a given object
	 * @param {Object} manager The kronos service manager
	 * @param {String} (mandatory) name The Name of the step
	 * @param {Object} (mandatory) endpoints the pre-populated endpoints
	 * @param {Object} (optional) stepDefinition The step definition
	 *
	 */
	_prepareProperties(manager, scopeReporter, name, stepConfiguration, endpoints) {
		let state = "stopped";

		if (!endpoints) {
			endpoints = {};
		}

		// TODO ther is no better way ?
		const type = stepConfiguration.type ? stepConfiguration.type : this.name;

		const props = {
			name: {
				value: name
			},
			type: {
				value: type
			},
			endpoints: {
				value: endpoints
			},
			manager: {
				value: manager
			},
			state: {
				get: function () {
					return state;
				},
				set: function (newState) {
					if (state != newState) {
						const oldState = state;
						state = newState;
						this._stateChanged(oldState, newState);
					}
				}
			},
			/**
			 * @return {Boolean} if step is in a running state
			 */
			isRunning: {
				get: function () {
					return state === 'running' || state === 'starting';
				}
			}
		};

		ATTRIBUTES.forEach(a => {
			//console.log(`${a}: ${stepConfiguration[a]} : ${this[a]}`);
			if (stepConfiguration[a] !== undefined /*&& stepConfiguration[a] !== this[a]*/ ) {
				props[a] = {
					value: stepConfiguration[a]
				};
			}
		});

		return props;
	},

	initialize(manager, scopeReporter, name, stepConfiguration, endpoints, props) {},

	finalize(manager, scopeReporter, stepConfiguration) {},

	/**
	 * This method could be overwritten by a derived object to setup default endpoints.
	 * This method may be overwritten by derived classes.
	 * This will be called by the initialize method
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} stepConfiguration The default step configuration
	 * @api protected
	 */
	_createPredefinedEndpoints(scopeReporter, stepConfiguration) {

		// log endpoint already present
		if (this.endpoints && this.endpoints.log) return;

		const newLogEndpoint = endpoint.createEndpoint("log", {}, logEndpoint);
		this.endpoints.log = newLogEndpoint;

		//console.log(`DEFAULT ${this.endpoints.log.default}`);
		loggingSupport.assignLoggerFunctions(this, function (args) {
			if (newLogEndpoint.isConnected()) {
				newLogEndpoint.send(args);
			} else {
				console.log(args);
			}
		});
	},

	/**
	 * Creates the endpoint objects defined as a combination from
	 * implementation and definition
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} def The step configuration
	 * @param {Object} impl The json step implementations definition
	 * @return {Object} endpoints A hash containing the endpoints stored by its name
	 * @api protected
	 */
	_createEndpoints(scopeReporter, impl, def) {
		const endpoints = {};

		// LINK: This does not work. After the change like you could see in the next lines it works.
		// const allEndpointNames = new Set(impl.endpoints ? Object.keys(impl.endpoints) :
		// 	undefined);
		const allEndpointNames = new Set();

		// Add the endpoint of the step implementation.
		if (impl.endpoints) {
			for (const endpointName in impl.endpoints) {
				allEndpointNames.add(endpointName);
			}
		}

		// Add the endpoints of the step definition
		if (def.endpoints) {
			for (const en in def.endpoints) {
				allEndpointNames.add(en);
			}
		}

		for (const en of allEndpointNames) {
			const de = def.endpoints && def.endpoints[en] ?
				def.endpoints[en] : undefined;
			const ie = impl.endpoints && impl.endpoints[en] ? impl.endpoints[
				en] : undefined;

			if (de) {
				endpoints[en] = endpoint.createEndpoint(en, de, ie);
			} else if (ie) {
				endpoints[en] = endpoint.createEndpoint(en, ie);

				if (endpoints[en].mandatory) {
					scopeReporter.error('Mandatory endpoint not defined', 'endpoint', en);
				}
			}
		}
		return endpoints;
	},

	/**
	 * Sends a 'stepStateChanged' event to the manager.
	 * arguments are:
	 *  step,oldState,newState
	 * @param {String} oldState
	 * @param {String} newState
	 */
	_stateChanged(oldState, newState) {
		this.manager.emit('stepStateChanged', this, oldState, newState);
	},

	/**
	 * Called when state transition is not allowed
	 * @param {String} action
	 * @return {Promise} rejecting with an Error
	 */
	_rejectWrongState(action) {
		return Promise.reject(new Error(`Can't ${action} ${this.name} in ${this.state} state`));
	},

	/**
	 * To be overwritten
	 * Overwrite to implement the functionality to bring the step into the running state.
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_start() {
		return Promise.resolve(this);
	},

	/**
	 * To be overwritten
	 * Overwrite to implement the functionality to bring the step into the stopped state.
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_stop() {
		return Promise.resolve(this);
	},

	/**
	 * To be overwritten.
	 * Tear down every resource as a final step if the the step removal
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_remove() {
		return Promise.resolve(this);
	},

	/**
	 * Stores the given endpoint under its name. If there was an exsting endpoint before
	 * with the same name it will be overwritten.
	 * @param endpoint The endpoint to set
	 */
	putEndpoint(endpoint) {
		this.endpoints[endpoint.name] = endpoint;
		endpoint.step = this;
	},

	/**
	 * Returns the string representation of this step
	 */
	toString() {
		return this.name;
	},

	/**
	 * Deliver json representation
	 * @param {Objects} options
	 *  with the following flags:
	 *    includeRuntimeInfo - include runtime informtion like state
	 *    includeName - name of the step
	 *    includeDefaults - include all properties also the inherited and not overwittern ones
	 * @return json representation
	 */
	toJSONWithOptions(options) {
		const json = {
			type: this.type,
			endpoints: {}
		};

		if (options.includeName) {
			json.name = this.name;
		}

		if (options.includeRuntimeInfo) {
			json.state = this.state;
		}

		for (const endpointName in this.endpoints) {
			if (!this.endpoints[endpointName].default || options.includeDefaults) {
				json.endpoints[endpointName] = this.endpoints[endpointName].toJSON();
			}
		}

		if (options.includeDefaults) {
			ATTRIBUTES.forEach(a => {
				json[a] = this[a];
			});
		} else {
			const prototype = Object.getPrototypeOf(this);

			ATTRIBUTES.forEach(a => {
				if (this[a] !== prototype[a]) {
					json[a] = this[a];
				}
			});
		}

		return json;
	},

	toJSON() {
		return this.toJSONWithOptions({
			includeRuntimeInfo: false,
			includeDefaults: false,
			includeName: false
		});
	},

	/**
	 * Could be overwritten by a derived object. This method is the first method called from
	 * the initialize function.
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} stepConfiguration The default step configuration
	 * @param {Object} stepDefinition The json step definition
	 * @api protected
	 */
	_beforeInitialize(scopeReporter, stepConfiguration) {},

	/**
	 * Could be overwritten by a derived object. This method is the last method called from
	 * the initialize function.
	 * Called when the generated step object has alredy consumed all information
	 * from the configuration.
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @api protected
	 */
	_afterInitialize(scopeReporter) {},

	/**
	 * Derived objects should implement this method to setup the endpoints
	 * This will be called by the initialize method
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} stepConfiguration The default step configuration
	 * @return {Object} endpoints A hash containing the endpoints stored by its name
	 * @api protected
	 */
	_setupEndpoints(scopeReporter, stepConfiguration, endpoints) {},
};

/**
 * Adding a start function
 * Brings a step into the running state.
 * @return {Promise} that fullfills with the step in the running state
 */
baseStep.start = states.transitionFunction(states.transitions.start);

/**
 * Adding a stop function
 * Brings the step into the stopped state
 * @return {Promise} that fullfills with the step in the stopped state
 */
baseStep.stop = states.transitionFunction(states.transitions.stop);

/**
 * Adding a remove function
 * Brings the step into the removed state
 * @return {Promise} that fullfills with the step in the removed state
 */
baseStep.remove = states.transitionFunction(states.transitions.remove);

module.exports = baseStep;
<commit_msg>refactor(Step): removed unused initialization methods<commit_after>/* jslint node: true, esnext: true */

"use strict";

const states = require('./states');
const endpoint = require('./endpoint');
const loggingSupport = require('./loggingSupport');
const myScopeReporter = require('scope-reporter');
const scopeDefinitions = require('../lib/scopeDefinitions');

// Steps plain attributes without special handling
// may be extended by some properties like writable,...
const ATTRIBUTES = ['description'];

const logEndpoint = endpoint.createEndpoint("log", {
	"description": "logging endpoint. All logging goes through this endpoint",
	"out": true,
	"active": true,
	"default": true
});

const baseStep = {
	"name": "kronos-step",
	"description": "This step is the base class for step implementations",

	/**
	 * Creates the properties for a given object
	 * @param {Object} manager The kronos service manager
	 * @param {String} (mandatory) name The Name of the step
	 * @param {Object} (mandatory) endpoints the pre-populated endpoints
	 * @param {Object} (optional) stepDefinition The step definition
	 *
	 */
	_prepareProperties(manager, scopeReporter, name, stepConfiguration, endpoints) {
		let state = "stopped";

		if (!endpoints) {
			endpoints = {};
		}

		// TODO ther is no better way ?
		const type = stepConfiguration.type ? stepConfiguration.type : this.name;

		const props = {
			name: {
				value: name
			},
			type: {
				value: type
			},
			endpoints: {
				value: endpoints
			},
			manager: {
				value: manager
			},
			state: {
				get: function () {
					return state;
				},
				set: function (newState) {
					if (state != newState) {
						const oldState = state;
						state = newState;
						this._stateChanged(oldState, newState);
					}
				}
			},
			/**
			 * @return {Boolean} if step is in a running state
			 */
			isRunning: {
				get: function () {
					return state === 'running' || state === 'starting';
				}
			}
		};

		ATTRIBUTES.forEach(a => {
			//console.log(`${a}: ${stepConfiguration[a]} : ${this[a]}`);
			if (stepConfiguration[a] !== undefined /*&& stepConfiguration[a] !== this[a]*/ ) {
				props[a] = {
					value: stepConfiguration[a]
				};
			}
		});

		return props;
	},

	/**
	 * Called to initialize step
	 * Please note 'this' is not jet present
	 */
	initialize(manager, scopeReporter, name, stepConfiguration, endpoints, props) {},

	/**
	 * Called when step instance properties are present.
	 *
	 */
	finalize(manager, scopeReporter, stepConfiguration) {},

	/**
	 * This method could be overwritten by a derived object to setup default endpoints.
	 * This method may be overwritten by derived classes.
	 * This will be called by the initialize method
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} stepConfiguration The default step configuration
	 * @api protected
	 */
	_createPredefinedEndpoints(scopeReporter, stepConfiguration) {

		// log endpoint already present
		if (this.endpoints && this.endpoints.log) return;

		const newLogEndpoint = endpoint.createEndpoint("log", {}, logEndpoint);
		this.endpoints.log = newLogEndpoint;

		//console.log(`DEFAULT ${this.endpoints.log.default}`);
		loggingSupport.assignLoggerFunctions(this, function (args) {
			if (newLogEndpoint.isConnected()) {
				newLogEndpoint.send(args);
			} else {
				console.log(args);
			}
		});
	},

	/**
	 * Creates the endpoint objects defined as a combination from
	 * implementation and definition
	 * @param {Object} scopeReporter This reporter is used to report parsing errors
	 * @param {Object} def The step configuration
	 * @param {Object} impl The json step implementations definition
	 * @return {Object} endpoints A hash containing the endpoints stored by its name
	 * @api protected
	 */
	_createEndpoints(scopeReporter, impl, def) {
		const endpoints = {};

		// LINK: This does not work. After the change like you could see in the next lines it works.
		// const allEndpointNames = new Set(impl.endpoints ? Object.keys(impl.endpoints) :
		// 	undefined);
		const allEndpointNames = new Set();

		// Add the endpoint of the step implementation.
		if (impl.endpoints) {
			for (const endpointName in impl.endpoints) {
				allEndpointNames.add(endpointName);
			}
		}

		// Add the endpoints of the step definition
		if (def.endpoints) {
			for (const en in def.endpoints) {
				allEndpointNames.add(en);
			}
		}

		for (const en of allEndpointNames) {
			const de = def.endpoints && def.endpoints[en] ?
				def.endpoints[en] : undefined;
			const ie = impl.endpoints && impl.endpoints[en] ? impl.endpoints[
				en] : undefined;

			if (de) {
				endpoints[en] = endpoint.createEndpoint(en, de, ie);
			} else if (ie) {
				endpoints[en] = endpoint.createEndpoint(en, ie);

				if (endpoints[en].mandatory) {
					scopeReporter.error('Mandatory endpoint not defined', 'endpoint', en);
				}
			}
		}
		return endpoints;
	},

	/**
	 * Sends a 'stepStateChanged' event to the manager.
	 * arguments are:
	 *  step,oldState,newState
	 * @param {String} oldState
	 * @param {String} newState
	 */
	_stateChanged(oldState, newState) {
		this.manager.emit('stepStateChanged', this, oldState, newState);
	},

	/**
	 * Called when state transition is not allowed
	 * @param {String} action
	 * @return {Promise} rejecting with an Error
	 */
	_rejectWrongState(action) {
		return Promise.reject(new Error(`Can't ${action} ${this.name} in ${this.state} state`));
	},

	/**
	 * To be overwritten
	 * Overwrite to implement the functionality to bring the step into the running state.
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_start() {
		return Promise.resolve(this);
	},

	/**
	 * To be overwritten
	 * Overwrite to implement the functionality to bring the step into the stopped state.
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_stop() {
		return Promise.resolve(this);
	},

	/**
	 * To be overwritten.
	 * Tear down every resource as a final step if the the step removal
	 * @return {Promise} default implementation always fullfills with the receiving step
	 */
	_remove() {
		return Promise.resolve(this);
	},

	/**
	 * Stores the given endpoint under its name. If there was an exsting endpoint before
	 * with the same name it will be overwritten.
	 * @param endpoint The endpoint to set
	 */
	putEndpoint(endpoint) {
		this.endpoints[endpoint.name] = endpoint;
		endpoint.step = this;
	},

	/**
	 * Returns the string representation of this step
	 * @return {String} human readable name
	 */
	toString() {
		return this.name;
	},

	/**
	 * Deliver json representation
	 * @param {Objects} options
	 *  with the following flags:
	 *    includeRuntimeInfo - include runtime informtion like state
	 *    includeName - name of the step
	 *    includeDefaults - include all properties also the inherited and not overwittern ones
	 * @return json representation
	 */
	toJSONWithOptions(options) {
		const json = {
			type: this.type,
			endpoints: {}
		};

		if (options.includeName) {
			json.name = this.name;
		}

		if (options.includeRuntimeInfo) {
			json.state = this.state;
		}

		for (const endpointName in this.endpoints) {
			if (!this.endpoints[endpointName].default || options.includeDefaults) {
				json.endpoints[endpointName] = this.endpoints[endpointName].toJSON();
			}
		}

		if (options.includeDefaults) {
			ATTRIBUTES.forEach(a => {
				json[a] = this[a];
			});
		} else {
			const prototype = Object.getPrototypeOf(this);

			ATTRIBUTES.forEach(a => {
				if (this[a] !== prototype[a]) {
					json[a] = this[a];
				}
			});
		}

		return json;
	},

	toJSON() {
		return this.toJSONWithOptions({
			includeRuntimeInfo: false,
			includeDefaults: false,
			includeName: false
		});
	}
};

/**
 * Adding a start function
 * Brings a step into the running state.
 * @return {Promise} that fullfills with the step in the running state
 */
baseStep.start = states.transitionFunction(states.transitions.start);

/**
 * Adding a stop function
 * Brings the step into the stopped state
 * @return {Promise} that fullfills with the step in the stopped state
 */
baseStep.stop = states.transitionFunction(states.transitions.stop);

/**
 * Adding a remove function
 * Brings the step into the removed state
 * @return {Promise} that fullfills with the step in the removed state
 */
baseStep.remove = states.transitionFunction(states.transitions.remove);

module.exports = baseStep;
<|endoftext|>


<commit_before>import React from 'react';
import {Component, PropTypes} from '../imports';
import {Tile} from './tile';

/**
 * This class describes a Preact/React component which renders a tiles chart
 * @class WSTilesChart
 * @property {Object} props React properties object
 * @property {Object} props.data Defines the Groups of tiles that should be shown in the chart
 * @property {Object} props.config Defines the color of each group of tiles
 * @property {string} props.title Title of the chart
 * @property {number} props.maxTileSize Defines the maximum size that the tile can be
 * @property {number} props.minTileSize Defines the minimum size that the tile can be
 * @property {number} props.width Defines width of the chart
 * @property {number} props.height Defines height of the chart
 * @property {func} props.onMouseEnter Defines function that is called for onMouseEnter event
 * @property {func} props.onMouseLeave Defines function that is called for onMouseLeave event
 * @property {func} props.onClick Defines function that is called for onCLick event
 */
export class WSTilesChart extends Component {

  /**
   * @type {Object}
   */
  static defaultProps = {
    data: {},
    config: {},
    title: '',
    maxTileSize: 25,
    minTileSize: 8,
    width: 80,
    height: 80,
    onMouseEnter: () => {},
    onMouseLeave: () => {},
    onClick: () => {}
  };

  /**
   * @type {Object}
   */
  static propTypes = {
    data: PropTypes.object,
    config: PropTypes.object,
    title: PropTypes.string,
    maxTileSize: PropTypes.number,
    width: PropTypes.number,
    height: PropTypes.number,
    onMouseEnter: PropTypes.func,
    onMouseLeave: PropTypes.func,
    onClick: PropTypes.func
  };

  /**
   * @param {Object} props React properties
   * @constructor
   */
  constructor(props) {
    super(props);
    this.state = {tileSize: 0};
    this.titleDivSize = 30;

    this.getTileSize = this.getTileSize.bind(this);
  }

  /**
   * Calculate the tiles size
   * @returns {void}
   */
  componentWillMount() {
    this.setState({tileSize: this.getTileSize()});
  }

  /**
   * Returns the size to be used for the tile
   * @returns {number}
   */
  getTileSize() {
    const groups = this.props.data.groups || {};
    const tilesAmount = Object.keys(groups).map(groupName => groups[groupName].length).reduce((a, b) => a + b);

    const tileSize = this.calculateMaximumPossibleTileSize(
      this.props.width, this.props.height - this.titleDivSize, tilesAmount
    );

    if (tileSize <= this.props.maxTileSize && tileSize >= this.props.minTileSize) {
      return tileSize;
    } else if (tileSize > this.props.maxTileSize) {
      return this.props.maxTileSize;
    }

    return this.props.minTileSize;
  }

  /**
   * Calculates the maximum tile size based on total width, height and amount of tiles
   * @param {number} width of the container
   * @param {number} height of the container
   * @param {number} tilesAmount total number of tiles in the chart
   * @returns {number}
   */
  calculateMaximumPossibleTileSize(width, height, tilesAmount) {
    const chartArea = (width < height) ? width * width : height * height;
    return Math.sqrt(chartArea / tilesAmount);
  }

  /**
   * Renders the chart
   * @returns {Object}
   */
  render() {
    const {data, config, title, width, height} = this.props;
    const groups = data.groups || {};
    return (
      <div className="ws-tiles-chart" style={{width: `${width}px`, height: `${height}px`}}>

{title}

        <div
          className="tiles-chart-container"
          style={{maxHeight: `${height - this.titleDivSize}px`}}
          onMouseEnter={this.props.onMouseEnter}
          onMouseLeave={this.props.onMouseLeave}
        >
          {Object.keys(groups).map(groupName => groups[groupName].map(tile =>
            <Tile
              identifier={tile}
              groupName={groupName}
              config={config[groupName]}
              size={this.state.tileSize}
              onClick={this.props.onClick}
            />
          ))}

    );
  }
}
<commit_msg>fix(ws-tile-chart): Fix to not break when there aren't any groups to show<commit_after>import React from 'react';
import {Component, PropTypes} from '../imports';
import {Tile} from './tile';

/**
 * This class describes a Preact/React component which renders a tiles chart
 * @class WSTilesChart
 * @property {Object} props React properties object
 * @property {Object} props.data Defines the Groups of tiles that should be shown in the chart
 * @property {Object} props.config Defines the color of each group of tiles
 * @property {string} props.title Title of the chart
 * @property {number} props.maxTileSize Defines the maximum size that the tile can be
 * @property {number} props.minTileSize Defines the minimum size that the tile can be
 * @property {number} props.width Defines width of the chart
 * @property {number} props.height Defines height of the chart
 * @property {func} props.onMouseEnter Defines function that is called for onMouseEnter event
 * @property {func} props.onMouseLeave Defines function that is called for onMouseLeave event
 * @property {func} props.onClick Defines function that is called for onCLick event
 */
export class WSTilesChart extends Component {

  /**
   * @type {Object}
   */
  static defaultProps = {
    data: {},
    config: {},
    title: '',
    maxTileSize: 25,
    minTileSize: 8,
    width: 80,
    height: 80,
    onMouseEnter: () => {},
    onMouseLeave: () => {},
    onClick: () => {}
  };

  /**
   * @type {Object}
   */
  static propTypes = {
    data: PropTypes.object,
    config: PropTypes.object,
    title: PropTypes.string,
    maxTileSize: PropTypes.number,
    width: PropTypes.number,
    height: PropTypes.number,
    onMouseEnter: PropTypes.func,
    onMouseLeave: PropTypes.func,
    onClick: PropTypes.func
  };

  /**
   * @param {Object} props React properties
   * @constructor
   */
  constructor(props) {
    super(props);
    this.state = {tileSize: 0};
    this.titleDivSize = 30;

    this.getTileSize = this.getTileSize.bind(this);
  }

  /**
   * Calculate the tiles size
   * @returns {void}
   */
  componentWillMount() {
    this.setState({tileSize: this.getTileSize()});
  }

  /**
   * Returns the size to be used for the tile
   * @returns {number}
   */
  getTileSize() {
    const {height, width, maxTileSize, minTileSize, data} = this.props;
    const groups = data.groups || {};

    if (maxTileSize === minTileSize || Object.keys(groups).length === 0) {
      return minTileSize;
    }

    const tilesAmount = Object.keys(groups).map(groupName => groups[groupName].length).reduce((a, b) => a + b);

    const tileSize = this.calculateMaximumPossibleTileSize(
      width, height - this.titleDivSize, tilesAmount
    );

    if (tileSize <= maxTileSize && tileSize >= minTileSize) {
      return tileSize;
    } else if (tileSize > maxTileSize) {
      return maxTileSize;
    }

    return minTileSize;
  }

  /**
   * Calculates the maximum tile size based on total width, height and amount of tiles
   * @param {number} width of the container
   * @param {number} height of the container
   * @param {number} tilesAmount total number of tiles in the chart
   * @returns {number}
   */
  calculateMaximumPossibleTileSize(width, height, tilesAmount) {
    const chartArea = (width < height) ? width * width : height * height;
    return Math.sqrt(chartArea / tilesAmount);
  }

  /**
   * Renders the chart
   * @returns {Object}
   */
  render() {
    const {data, config, title, width, height} = this.props;
    const groups = data.groups || {};
    return (
      <div className="ws-tiles-chart" style={{width: `${width}px`, height: `${height}px`}}>

{title}

        <div
          className="tiles-chart-container"
          style={{maxHeight: `${height - this.titleDivSize}px`}}
          onMouseEnter={this.props.onMouseEnter}
          onMouseLeave={this.props.onMouseLeave}
        >
          {Object.keys(groups).map(groupName => groups[groupName].map(tile =>
            <Tile
              identifier={tile}
              groupName={groupName}
              config={config[groupName]}
              size={this.state.tileSize}
              onClick={this.props.onClick}
            />
          ))}

    );
  }
}
<|endoftext|>


<commit_before>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

let InspectorObserver =
{
  init: function()
  {
    Services.obs.addObserver(this, "inspector-opened", true);
    onShutdown.add((function() Services.obs.removeObserver(this, "inspector-opened")).bind(this));
  },

  get inspectorButton()
  {
    // Randomize URI to work around bug 719376
    let stringBundle = Services.strings.createBundle("chrome://removetemporarily/locale/global.properties?" + Math.random());
    let result = [stringBundle.GetStringFromName("inspector.button.label"), stringBundle.GetStringFromName("inspector.button.accesskey"), stringBundle.GetStringFromName("inspector.button.tooltiptext")];

    delete this.inspectorButton;
    this.__defineGetter__("inspectorButton", function() result);
    return this.inspectorButton;
  },

  observe: function(subject, topic, data)
  {
    if (topic != "inspector-opened")
      return;

    let InspectorUI = subject.wrappedJSObject;

    let [label, accesskey, tooltiptext] = this.inspectorButton;
    let tool = {
      id: "remove-temporarily",
      label: label,
      accesskey: accesskey,
      tooltiptext: tooltiptext,
      get isOpen() false,
      show: function(selection)
      {
        if (selection && selection.parentNode && selection.parentNode.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
        {
          let parent = selection.parentNode;
          InspectorUI.highlighter.highlight(parent);
          parent.removeChild(selection);
        }
        InspectorUI.toolHide(tool);
      },
      hide: function() {}
    };
    InspectorUI.registerTool(tool);
  },

  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
};

InspectorObserver.init();
<commit_msg>InspectorUI.registerTool API disappeared in Firefox 14 (bug 707809), add inspector button manually<commit_after>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

let InspectorObserver =
{
  init: function()
  {
    Services.obs.addObserver(this, "inspector-opened", true);
    onShutdown.add(function()
    {
      Services.obs.removeObserver(this, "inspector-opened")

      let e = Services.ww.getWindowEnumerator();
      while (e.hasMoreElements())
      {
        let window = e.getNext().QueryInterface(Ci.nsIDOMWindow);
        let button = window.document.getElementById("inspector-remove-temporarily-toolbutton");
        if (button)
          button.parentNode.removeChild(button);
      }
    }.bind(this));
  },

  get inspectorButton()
  {
    // Randomize URI to work around bug 719376
    let stringBundle = Services.strings.createBundle("chrome://removetemporarily/locale/global.properties?" + Math.random());
    let result = [stringBundle.GetStringFromName("inspector.button.label"), stringBundle.GetStringFromName("inspector.button.accesskey"), stringBundle.GetStringFromName("inspector.button.tooltiptext")];

    delete this.inspectorButton;
    this.__defineGetter__("inspectorButton", function() result);
    return this.inspectorButton;
  },

  observe: function(subject, topic, data)
  {
    if (topic != "inspector-opened")
      return;

    let InspectorUI = subject.wrappedJSObject;
    let window = InspectorUI.chromeWin;
    let button = window.document.getElementById("inspector-remove-temporarily-toolbutton");
    if (button)
      button.parentNode.removeChild(button);

    let parent = window.document.getElementById("inspector-tools");
    if (!parent)
      return;

    let [label, accesskey, tooltiptext] = this.inspectorButton;
    button = window.document.createElement("toolbarbutton");
    button.setAttribute("id", "inspector-remove-temporarily-toolbutton");
    button.setAttribute("label", label);
    button.setAttribute("class", "devtools-toolbarbutton");
    button.setAttribute("accesskey", accesskey);
    button.setAttribute("tooltiptext", tooltiptext);
    button.setAttribute("tabindex", "0");
    button.addEventListener("command", function()
    {
      let selection = InspectorUI.selection;
      if (selection && selection.parentNode && selection.parentNode.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
      {
        let parent = selection.parentNode;
        InspectorUI.highlighter.highlight(parent);
        parent.removeChild(selection);
      }
    }, false);
    parent.appendChild(button);
  },

  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
};

InspectorObserver.init();
<|endoftext|>