<commit_before>module.exports = Client

var debug = require('debug')('bittorrent-tracker')
var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')
var once = require('once')
var url = require('url')

var common = require('./lib/common')
var HTTPTracker = require('./lib/http-tracker') // empty object in browser
var UDPTracker = require('./lib/udp-tracker') // empty object in browser
var WebSocketTracker = require('./lib/websocket-tracker')

inherits(Client, EventEmitter)

/**
 * BitTorrent tracker client.
 *
 * Find torrent peers, to help a torrent client participate in a torrent swarm.
 *
 * @param {string} peerId          peer id
 * @param {Number} port            torrent client listening port
 * @param {Object} torrent         parsed torrent
 * @param {Object} opts            options object
 * @param {Number} opts.numWant    number of peers to request
 * @param {Number} opts.interval   announce interval (in ms)
 * @param {Number} opts.rtcConfig  RTCPeerConnection configuration object
 */
function Client (peerId, port, torrent, opts) {
  var self = this
  if (!(self instanceof Client)) return new Client(peerId, port, torrent, opts)
  EventEmitter.call(self)
  if (!opts) opts = {}

  // required
  self._peerId = Buffer.isBuffer(peerId)
    ? peerId
    : new Buffer(peerId, 'hex')
  self._port = port
  self._infoHash = Buffer.isBuffer(torrent.infoHash)
    ? torrent.infoHash
    : new Buffer(torrent.infoHash, 'hex')
  self.torrentLength = torrent.length

  // optional
  self._numWant = opts.numWant || common.DEFAULT_ANNOUNCE_PEERS
  self._intervalMs = opts.interval || common.DEFAULT_ANNOUNCE_INTERVAL

  debug('new client %s', self._infoHash.toString('hex'))

  if (typeof torrent.announce === 'string') torrent.announce = [ torrent.announce ]
  if (torrent.announce == null) torrent.announce = []

  self._trackers = torrent.announce
    .map(function (announceUrl) {
      var trackerOpts = { interval: self._intervalMs }
      var protocol = url.parse(announceUrl).protocol

      if ((protocol === 'http:' || protocol === 'https:') &&
          typeof HTTPTracker === 'function') {
        return new HTTPTracker(self, announceUrl, trackerOpts)
      } else if (protocol === 'udp:' && typeof UDPTracker === 'function') {
        return new UDPTracker(self, announceUrl, trackerOpts)
      } else if ((protocol === 'ws:' || protocol === 'wss:') &&
          WebSocketTracker.supported) {
        return new WebSocketTracker(self, announceUrl, trackerOpts)
      }
      return null
    })
    .filter(Boolean)
}

/**
 * Simple convenience function to scrape a tracker for an info hash without needing to
 * create a Client, pass it a parsed torrent, etc. Support scraping a tracker for multiple
 * torrents at the same time.
 * @param  {string} announceUrl
 * @param  {string|Array.<string>} infoHash
 * @param  {function} cb
 */
Client.scrape = function (announceUrl, infoHash, cb) {
  cb = once(cb)

  var peerId = new Buffer('01234567890123456789') // dummy value
  var port = 6881 // dummy value
  var torrent = {
    infoHash: Array.isArray(infoHash) ? infoHash[0] : infoHash,
    announce: [ announceUrl ]
  }
  var client = new Client(peerId, port, torrent)
  client.once('error', cb)

  var len = Array.isArray(infoHash) ? infoHash.length : 1
  var results = {}
  client.on('scrape', function (data) {
    len -= 1
    results[data.infoHash] = data
    if (len === 0) {
      client.destroy()
      var keys = Object.keys(results)
      if (keys.length === 1) {
        cb(null, results[keys[0]])
      } else {
        cb(null, results)
      }
    }
  })

  infoHash = Array.isArray(infoHash)
    ? infoHash.map(function (infoHash) { return new Buffer(infoHash, 'hex') })
    : new Buffer(infoHash, 'hex')
  client.scrape({ infoHash: infoHash })

}

/**
 * Send a `start` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.start = function (opts) {
  var self = this
  debug('send `start`')
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'started'
  self._announce(opts)

  // start announcing on intervals
  self._trackers.forEach(function (tracker) {
    tracker.setInterval(self._intervalMs)
  })
}

/**
 * Send a `stop` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.stop = function (opts) {
  var self = this
  debug('send `stop`')
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'stopped'
  self._announce(opts)

  self.destroy()
}

/**
 * Send a `complete` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.complete = function (opts) {
  var self = this
  debug('send `complete`')
  if (!opts) opts = {}
  if (opts.downloaded == null && self.torrentLength != null) {
    opts.downloaded = self.torrentLength
  }
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'completed'
  self._announce(opts)
}

/**
 * Send a `update` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.update = function (opts) {
  var self = this
  debug('send `update`')
  opts = self._defaultAnnounceOpts(opts)
  if (opts.event) delete opts.event
  self._announce(opts)
}

Client.prototype._announce = function (opts) {
  var self = this
  self._trackers.forEach(function (tracker) {
    tracker.announce(opts)
  })
}

/**
 * Send a scrape request to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.scrape = function (opts) {
  var self = this
  debug('send `scrape`')
  if (!opts) opts = {}
  self._trackers.forEach(function (tracker) {
    tracker.scrape(opts)
  })
}

Client.prototype.setInterval = function (intervalMs) {
  var self = this
  debug('setInterval')
  self._intervalMs = intervalMs

  self._trackers.forEach(function (tracker) {
    tracker.setInterval(intervalMs)
  })
}

Client.prototype.destroy = function () {
  var self = this
  debug('destroy')

  self._trackers.forEach(function (tracker) {
    if (tracker.destroy) tracker.destroy()
    tracker.setInterval(0) // stop announcing on intervals
  })
}

Client.prototype._defaultAnnounceOpts = function (opts) {
  var self = this
  if (!opts) opts = {}

  if (opts.numWant == null) opts.numWant = self._numWant

  if (opts.uploaded == null) opts.uploaded = 0
  if (opts.downloaded == null) opts.downloaded = 0

  if (opts.left == null && self.torrentLength != null) {
    opts.left = self.torrentLength - opts.downloaded
  }
  return opts
}
<commit_msg>standard<commit_after>module.exports = Client

var debug = require('debug')('bittorrent-tracker')
var EventEmitter = require('events').EventEmitter
var inherits = require('inherits')
var once = require('once')
var url = require('url')

var common = require('./lib/common')
var HTTPTracker = require('./lib/http-tracker') // empty object in browser
var UDPTracker = require('./lib/udp-tracker') // empty object in browser
var WebSocketTracker = require('./lib/websocket-tracker')

inherits(Client, EventEmitter)

/**
 * BitTorrent tracker client.
 *
 * Find torrent peers, to help a torrent client participate in a torrent swarm.
 *
 * @param {string} peerId          peer id
 * @param {Number} port            torrent client listening port
 * @param {Object} torrent         parsed torrent
 * @param {Object} opts            options object
 * @param {Number} opts.numWant    number of peers to request
 * @param {Number} opts.interval   announce interval (in ms)
 * @param {Number} opts.rtcConfig  RTCPeerConnection configuration object
 */
function Client (peerId, port, torrent, opts) {
  var self = this
  if (!(self instanceof Client)) return new Client(peerId, port, torrent, opts)
  EventEmitter.call(self)
  if (!opts) opts = {}

  // required
  self._peerId = Buffer.isBuffer(peerId)
    ? peerId
    : new Buffer(peerId, 'hex')
  self._port = port
  self._infoHash = Buffer.isBuffer(torrent.infoHash)
    ? torrent.infoHash
    : new Buffer(torrent.infoHash, 'hex')
  self.torrentLength = torrent.length

  // optional
  self._numWant = opts.numWant || common.DEFAULT_ANNOUNCE_PEERS
  self._intervalMs = opts.interval || common.DEFAULT_ANNOUNCE_INTERVAL

  debug('new client %s', self._infoHash.toString('hex'))

  if (typeof torrent.announce === 'string') torrent.announce = [ torrent.announce ]
  if (torrent.announce == null) torrent.announce = []

  self._trackers = torrent.announce
    .map(function (announceUrl) {
      var trackerOpts = { interval: self._intervalMs }
      var protocol = url.parse(announceUrl).protocol

      if ((protocol === 'http:' || protocol === 'https:') &&
          typeof HTTPTracker === 'function') {
        return new HTTPTracker(self, announceUrl, trackerOpts)
      } else if (protocol === 'udp:' && typeof UDPTracker === 'function') {
        return new UDPTracker(self, announceUrl, trackerOpts)
      } else if ((protocol === 'ws:' || protocol === 'wss:') &&
          WebSocketTracker.supported) {
        return new WebSocketTracker(self, announceUrl, trackerOpts)
      }
      return null
    })
    .filter(Boolean)
}

/**
 * Simple convenience function to scrape a tracker for an info hash without needing to
 * create a Client, pass it a parsed torrent, etc. Support scraping a tracker for multiple
 * torrents at the same time.
 * @param  {string} announceUrl
 * @param  {string|Array.<string>} infoHash
 * @param  {function} cb
 */
Client.scrape = function (announceUrl, infoHash, cb) {
  cb = once(cb)

  var peerId = new Buffer('01234567890123456789') // dummy value
  var port = 6881 // dummy value
  var torrent = {
    infoHash: Array.isArray(infoHash) ? infoHash[0] : infoHash,
    announce: [ announceUrl ]
  }
  var client = new Client(peerId, port, torrent)
  client.once('error', cb)

  var len = Array.isArray(infoHash) ? infoHash.length : 1
  var results = {}
  client.on('scrape', function (data) {
    len -= 1
    results[data.infoHash] = data
    if (len === 0) {
      client.destroy()
      var keys = Object.keys(results)
      if (keys.length === 1) {
        cb(null, results[keys[0]])
      } else {
        cb(null, results)
      }
    }
  })

  infoHash = Array.isArray(infoHash)
    ? infoHash.map(function (infoHash) { return new Buffer(infoHash, 'hex') })
    : new Buffer(infoHash, 'hex')
  client.scrape({ infoHash: infoHash })
}

/**
 * Send a `start` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.start = function (opts) {
  var self = this
  debug('send `start`')
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'started'
  self._announce(opts)

  // start announcing on intervals
  self._trackers.forEach(function (tracker) {
    tracker.setInterval(self._intervalMs)
  })
}

/**
 * Send a `stop` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.stop = function (opts) {
  var self = this
  debug('send `stop`')
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'stopped'
  self._announce(opts)

  self.destroy()
}

/**
 * Send a `complete` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.complete = function (opts) {
  var self = this
  debug('send `complete`')
  if (!opts) opts = {}
  if (opts.downloaded == null && self.torrentLength != null) {
    opts.downloaded = self.torrentLength
  }
  opts = self._defaultAnnounceOpts(opts)
  opts.event = 'completed'
  self._announce(opts)
}

/**
 * Send a `update` announce to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.update = function (opts) {
  var self = this
  debug('send `update`')
  opts = self._defaultAnnounceOpts(opts)
  if (opts.event) delete opts.event
  self._announce(opts)
}

Client.prototype._announce = function (opts) {
  var self = this
  self._trackers.forEach(function (tracker) {
    tracker.announce(opts)
  })
}

/**
 * Send a scrape request to the trackers.
 * @param {Object} opts
 * @param {number=} opts.uploaded
 * @param {number=} opts.downloaded
 * @param {number=} opts.left (if not set, calculated automatically)
 */
Client.prototype.scrape = function (opts) {
  var self = this
  debug('send `scrape`')
  if (!opts) opts = {}
  self._trackers.forEach(function (tracker) {
    tracker.scrape(opts)
  })
}

Client.prototype.setInterval = function (intervalMs) {
  var self = this
  debug('setInterval')
  self._intervalMs = intervalMs

  self._trackers.forEach(function (tracker) {
    tracker.setInterval(intervalMs)
  })
}

Client.prototype.destroy = function () {
  var self = this
  debug('destroy')

  self._trackers.forEach(function (tracker) {
    if (tracker.destroy) tracker.destroy()
    tracker.setInterval(0) // stop announcing on intervals
  })
}

Client.prototype._defaultAnnounceOpts = function (opts) {
  var self = this
  if (!opts) opts = {}

  if (opts.numWant == null) opts.numWant = self._numWant

  if (opts.uploaded == null) opts.uploaded = 0
  if (opts.downloaded == null) opts.downloaded = 0

  if (opts.left == null && self.torrentLength != null) {
    opts.left = self.torrentLength - opts.downloaded
  }
  return opts
}
<|endoftext|>


<commit_before>importScripts('task-vars.js');

self.postMessage('starting.');

while(end) {
  end -= 1;
  tmp += end;
  if (end === halfway) {
    self.postMessage('halfway there, `tmp` is now ' + tmp + '.');
  }
}

self.postMessage('add done.');

// called implicitly
// self.terminate();
<commit_msg>Fix typo<commit_after>importScripts('task-vars.js');

self.postMessage('starting.');

while(end) {
  end -= 1;
  tmp += end;
  if (end === halfway) {
    self.postMessage('halfway there, `tmp` is now ' + tmp + '.');
  }
}

self.postMessage('all done.');

// called implicitly
// self.terminate();
<|endoftext|>


<commit_before>// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
//
// MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// new re-factored Listing object
// uses FieldGroup for rendering filters
// removed rarely used functionality
//
// opts:
//   parent
//   method (method to call on server)
//   args (additional args to method)
//   query or get_query (will be deprecated)
//   query_max
//   no_result_message ("No result")
//   page_length (20)
//   filters ([{docfield}, ..])
//   hide_refresh (False)
//   new_doctype
//   [function] render_row(parent, data)
//   [function] onrun
//   no_loading (no ajax indicator)

wn.widgets.Listing = function(opts) {
	this.opts = opts;
	this.page_length = 20;
	this.btns = {};
	this.start = 0;
	var me = this;

	// create place holders for all the elements
	this.make = function(opts) {
		if(this.opts.parent.jquery)
			this.opts.parent = this.opts.parent.get(0);
		this.wrapper = $a(this.opts.parent, 'div');
		this.filters_area = $a(this.wrapper, 'div', 'listing-filters');
		this.toolbar_area = $a(this.wrapper, 'div', 'listing-toolbar');
		this.results_area = $a(this.wrapper, 'div', 'listing-results');

		this.more_button_area = $a(this.wrapper, 'div', 'listing-more');

		this.no_results_area = $a(this.wrapper, 'div', 'help_box', {display: 'none'},
			(this.opts.no_result_message ? this.opts.no_result_message : 'No results'));

		if(opts) this.opts = opts;
		this.page_length = this.opts.page_length ? this.opts.page_length : this.page_length;

		this.make_toolbar();
		this.make_filters();
		this.make_more_button();
	}

	// make filters using FieldGroup
	this.make_filters = function() {
		if(this.opts.filters) {
			$ds(this.filters_area);

			// expand / collapse filters

			this.filters = new wn.widgets.FieldGroup(this.filters_area, this.opts.fields);
		}
	}

	// make the toolbar
	this.make_toolbar = function() {
		if(!(this.opts.hide_refresh || this.opts.no_refresh)) {
			if(this.opts.title) {
				$a(this.toolbar_area, 'h3', '',
					{display:'inline-block',marginRight:'15px'},
					this.opts.title);
			}
			this.ref_img = $a(this.toolbar_area, 'span', 'link_type',
				{color:'#888'}, '[refresh]');
			this.ref_img.onclick = function() { me.run(); }

			this.loading_img = $a(this.toolbar_area, 'img', 'lib/images/ui/button-load.gif', {display:'none', marginLeft:'3px', marginBottom:'-2px'});
		}

		if(this.opts.new_doctype) {
			this.new_btn = $btn(this.toolbar_area,
				'New ' + get_doctype_label(this.opts.new_doctype),
				function() {
					newdoc(me.opts.new_doctype, me.opts.new_doc_onload, me.opts.new_doc_indialog, me.opts.new_doc_onsave);
				},
				{marginLeft:'7px'});
		}
	}

	// make more button
	// that shows more results when they are displayed
	this.make_more_button = function() {
		this.more_btn = $btn(this.more_button_area, 'More...',
			function() {
				me.more_btn.set_working();
				me.run(function() {
					me.more_btn.done_working();
				}, 1);
			}, '', 0, 1
		);

		$y(this.more_btn.loading_img, {marginBottom:'0px'});
	}

	// clear the results and re-run the query
	this.clear = function() {
		this.results_area.innerHTML = '';
		this.table = null;
		$ds(this.results_area);
		$dh(this.no_results_area);
	}

	// callback on the query
	// build the table
	// returns r.values as a table of results
	this.make_results = function(r, rt) {
		if(this.start==0) this.clear();

		$dh(this.more_button_area);
		if(this.loading_img) $dh(this.loading_img)
		if(r.message) r.values = r.message;

		if(r.values && r.values.length) {
			this.values = r.values;
			var m = Math.min(r.values.length, this.page_length);
			// render the rows
			for(var i=0; i < m; i++) {
				var row = this.add_row();

				// call the show_cell with row, ri, ci, d
				this.opts.render_row(row, r.values[i], this, i);
			}
			// extend start
			this.start += m;

			// refreh more button
			if(r.values.length >= this.page_length) $ds(this.more_button_area);

		} else {
			if(this.start==0) {
				$dh(this.results_area);
				$ds(this.no_results_area);
			}
		}

		// callbacks
		if(this.onrun) this.onrun();
		if(this.opts.onrun) this.opts.onrun();
	}

	// add a results row
	this.add_row = function() {
		return $a(this.results_area, 'div', '',
			(opts.cell_style ? opts.cell_style : {padding: '3px 0px'}));
	}

	// run the query, get the query from
	// the get_query method of opts
	this.run = function(callback, append) {
		if(callback)
			this.onrun = callback;

		if(!append)
			this.start = 0;

		// load query
		if(!this.opts.method) {
			this.query = this.opts.get_query ? this.opts.get_query() : this.opts.query;
			this.add_limits();
			var args={
				query_max: this.query_max || this.opts.query_max || '',
				as_dict: 1
			}
			args.simple_query = this.query;
		} else {
			var args = {
				limit_start: this.start,
				limit_page_length: this.page_length
			}
		}

		if(this.opts.args)
			$.extend(args, this.opts.args)

		// show loading
		if(this.loading_img) $di(this.loading_img);
		wn.call({
			method: this.opts.method || 'webnotes.widgets.query_builder.runquery',
			args: args,
			callback: function(r, rt) { me.make_results(r, rt) },
			no_spinner: this.opts.no_loading,
			btn: this.opts.run_btn
		});
	}

	this.refresh = this.run;

	this.add_limits = function() {
		this.query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
	}

	if(opts) this.make();
}<commit_msg>module page link fix<commit_after>// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
//
// MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// new re-factored Listing object
// uses FieldGroup for rendering filters
// removed rarely used functionality
//
// opts:
//   parent
//   method (method to call on server)
//   args (additional args to method)
//   query or get_query (will be deprecated)
//   query_max
//   no_result_message ("No result")
//   page_length (20)
//   filters ([{docfield}, ..])
//   hide_refresh (False)
//   new_doctype
//   [function] render_row(parent, data)
//   [function] onrun
//   no_loading (no ajax indicator)

wn.widgets.Listing = function(opts) {
	this.opts = opts;
	this.page_length = 20;
	this.btns = {};
	this.start = 0;
	var me = this;

	// create place holders for all the elements
	this.make = function(opts) {
		if(this.opts.parent.jquery)
			this.opts.parent = this.opts.parent.get(0);
		this.wrapper = $a(this.opts.parent, 'div');
		this.filters_area = $a(this.wrapper, 'div', 'listing-filters');
		this.toolbar_area = $a(this.wrapper, 'div', 'listing-toolbar');
		this.results_area = $a(this.wrapper, 'div', 'listing-results');

		this.more_button_area = $a(this.wrapper, 'div', 'listing-more');

		this.no_results_area = $a(this.wrapper, 'div', 'help_box', {display: 'none'},
			(this.opts.no_result_message ? this.opts.no_result_message : 'No results'));

		if(opts) this.opts = opts;
		this.page_length = this.opts.page_length ? this.opts.page_length : this.page_length;

		this.make_toolbar();
		this.make_filters();
		this.make_more_button();
	}

	// make filters using FieldGroup
	this.make_filters = function() {
		if(this.opts.filters) {
			$ds(this.filters_area);

			// expand / collapse filters

			this.filters = new wn.widgets.FieldGroup(this.filters_area, this.opts.fields);
		}
	}

	// make the toolbar
	this.make_toolbar = function() {
		if(!(this.opts.hide_refresh || this.opts.no_refresh)) {
			if(this.opts.title) {
				$a(this.toolbar_area, 'h3', '',
					{display:'inline-block',marginRight:'15px'},
					this.opts.title);
			}
			this.ref_img = $a(this.toolbar_area, 'span', 'link_type',
				{color:'#888'}, '[refresh]');
			this.ref_img.onclick = function() { me.run(); }

			this.loading_img = $a(this.toolbar_area, 'img', 'lib/images/ui/button-load.gif', {display:'none', marginLeft:'3px', marginBottom:'-2px'});
		}

		if(this.opts.new_doctype) {
			this.new_btn = $btn(this.toolbar_area,
				'New ' + get_doctype_label(this.opts.new_doctype),
				function() {
					newdoc(me.opts.new_doctype, me.opts.new_doc_onload, me.opts.new_doc_indialog, me.opts.new_doc_onsave);
				},
				{marginLeft:'7px'});
		}
	}

	// make more button
	// that shows more results when they are displayed
	this.make_more_button = function() {
		this.more_btn = $btn(this.more_button_area, 'More...',
			function() {
				me.more_btn.set_working();
				me.run(function() {
					me.more_btn.done_working();
				}, 1);
			}, '', 0, 1
		);

		$y(this.more_btn.loading_img, {marginBottom:'0px'});
	}

	// clear the results and re-run the query
	this.clear = function() {
		this.results_area.innerHTML = '';
		this.table = null;
		$ds(this.results_area);
		$dh(this.no_results_area);
	}

	// callback on the query
	// build the table
	// returns r.values as a table of results
	this.make_results = function(r, rt) {
		if(this.start==0) this.clear();

		$dh(this.more_button_area);
		if(this.loading_img) $dh(this.loading_img)
		if(r.message) r.values = r.message;

		if(r.values && r.values.length) {
			this.values = r.values;
			var m = Math.min(r.values.length, this.page_length);
			// render the rows
			for(var i=0; i < m; i++) {
				var row = this.add_row();

				// call the show_cell with row, ri, ci, d
				this.opts.render_row(row, r.values[i], this, i);
			}
			// extend start
			this.start += m;

			// refreh more button
			if(r.values.length >= this.page_length) $ds(this.more_button_area);

		} else {
			if(this.start==0) {
				$dh(this.results_area);
				$ds(this.no_results_area);
			}
		}

		// callbacks
		if(this.onrun) this.onrun();
		if(this.opts.onrun) this.opts.onrun();
		if(this.opts.callback) this.opts.callback(r);
	}

	// add a results row
	this.add_row = function() {
		return $a(this.results_area, 'div', '',
			(opts.cell_style ? opts.cell_style : {padding: '3px 0px'}));
	}

	// run the query, get the query from
	// the get_query method of opts
	this.run = function(callback, append) {
		if(callback)
			this.onrun = callback;

		if(!append)
			this.start = 0;

		// load query
		if(!this.opts.method) {
			this.query = this.opts.get_query ? this.opts.get_query() : this.opts.query;
			this.add_limits();
			var args={
				query_max: this.query_max || this.opts.query_max || '',
				as_dict: 1
			}
			args.simple_query = this.query;
		} else {
			var args = {
				limit_start: this.start,
				limit_page_length: this.page_length
			}
		}

		if(this.opts.args)
			$.extend(args, this.opts.args)

		// show loading
		if(this.loading_img) $di(this.loading_img);
		wn.call({
			method: this.opts.method || 'webnotes.widgets.query_builder.runquery',
			args: args,
			callback: function(r, rt) { me.make_results(r, rt) },
			no_spinner: this.opts.no_loading,
			btn: this.opts.run_btn
		});
	}

	this.refresh = this.run;

	this.add_limits = function() {
		this.query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
	}

	if(opts) this.make();
}<|endoftext|>


<commit_before>var sendFormRequestManager = {
	init: function(formInstance, treatAllErrorAsGeneral) {

		var that = this;
		// load empty event initially in case there are not set
		that.subscribe('success', function(){});
		that.subscribe('error', function(){});
		that.subscribe('before', function(){ return true });

		if (typeof treatAllErrorAsGeneral == "undefined") {
			var treatAllErrorAsGeneral = true;
		}

		var errorBox     = formInstance.find('.form-error-box').first();
		var submitButton = formInstance.find('input[type="submit"]').first();

		formInstance.submit(function(e) {

			e.preventDefault();

			var sentData = {};
			formInstance.serializeArray().map(function(item){
				sentData[item.name] = item.value;
			});

			// if ok, return true, if not return the error
			executeBefore = that.trigger('before', {sentData: sentData});

			if (executeBefore !== true) {
				errorBox.removeClass('hidden').html(executeBefore);
				return false;
			}

			submitButton.prop("disabled", true);
			errorBox.addClass('hidden');

			$.post(formInstance.attr('_action'), sentData)
			.done(function(response) {
				submitButton.prop("disabled", false);

				if (response['status'] == true) {
					that.trigger('success', response['data']);
				} else {
					alert("Upss. somthing went wrong");
				}
			})
			.error(function(data) {
				var responseData = JSON.parse(data.responseText);

				if (typeof responseData["general"] != "undefined") {
					errorBox.removeClass('hidden').html(responseData["general"]);
				}

				if (treatAllErrorAsGeneral) {
					var getFirstErrorField = function(errors)
					{
						for (var index in errors) {
							var firstErorrField = errors[index];

							for (var index2 in firstErorrField) {
								return firstErorrField[index2];
							}
						}
					};

					errorBox.removeClass('hidden').html(getFirstErrorField(responseData));
				}

				submitButton.prop("disabled", false);
				that.trigger('error', responseData);
			});
		});

	},
	subscribeList: {},
	trigger: function(eventName, data) {
		return this.subscribeList[eventName](data);
	},
	subscribe: function(eventName, callbackFunction){
		return this.subscribeList[eventName] = callbackFunction;
	},
};

<commit_msg>refactor sendFormRequestManager<commit_after>var sendFormRequestManager =
{
    formInstance: null,
    treatAllErrorAsGeneral: true,
    apiClient: null,
    requestInProgress: false,
    submitUrl: null,

    onErrorCallback: function() {},
    onGeneralErrorCallback: function() {},
    onSuccessCallback: function() {},
    beforeSubmitCallback: function() {},

    init: function(newFormInstance, config)
    {
        this.formInstance = $(newFormInstance);

        if (typeof config == "undefined") {
            config = {};
        }

        if (typeof config.treatAllErrorAsGeneral != "undefined") {
            this.treatAllErrorAsGeneral = config.treatAllErrorAsGeneral;
        }

        if (typeof config.apiClient != "undefined") {
            this.apiClient = config.apiClient;
        }

        if (typeof config.submitUrl != "undefined") {
            this.submitUrl = config.submitUrl;
        }

        var that = this;

        this.formInstance.on('submit', function(event) {
            event.preventDefault();

            if (that.requestInProgress == true) {
                return ;
            }
            that.requestInProgress = true;

            var sentData = {};
            that.formInstance.serializeArray().map(function(item){
                sentData[item.name] = item.value;
            });

            // that should be post not get request.
            that.apiClient.get(submitUrl, {
                success: function(response) {
                    that.requestInProgress = false;
                    // call propar erro based on status code
                    that.onSuccessCallback(response);
                },
                error: function(status, response) {
                    that.requestInProgress = false;

                    if (status == 422) {
                        if (that.treatAllErrorAsGeneral) {
                            that.onGeneralErrorCallback(that.getFirstErrorField(response));
                        } else {
                            that.onErrorCallback(response);
                        }
                    } else if (status == 400) {
                        that.onGeneralError(response);
                    } else {
                        console.log("NO idea about this error");
                    }
                },
            });
        });
    },
    getFirstErrorField: function(errors)
    {
        for (var index in errors) {
            var firstErorrField = errors[index];

            for (var index2 in firstErorrField) {
                return firstErorrField[index2];
            }
        }
    },
    onError: function(newOnError)
    {
        this.onErrorCallback = newOnError;
    },
    onGeneralError: function(newOnGeneralError)
    {
        this.onGeneralErrorCallback = newOnGeneralError;
    },
    onSuccess: function(newOnSuccess)
    {
        this.onSuccessCallback = newOnSuccess;
    },
    beforeSubmit: function(newBeforeSummit)
    {
        this.beforeSubmitCallback = newBeforeSummit;
    }
};<|endoftext|>


<commit_before>"use strict";
var router_1 = require('@angular/router');
var template_driven_component_1 = require('./template-driven.component');
var form_builder_component_1 = require('./form-builder.component');
var appRoutes = [
    { path: 'template-driven', component: template_driven_component_1.TemplateDrivenComponent },
    { path: 'form-builder', component: form_builder_component_1.FormBuilderComponent }
];
exports.appRoutingProviders = [];
exports.routing = router_1.RouterModule.forRoot(appRoutes);
//# sourceMappingURL=app.routing.js.map<commit_msg>Remove: js from ts compilation<commit_after><|endoftext|>


<commit_before>describe("About Arrays", function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); // A mistake?-- http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function() { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function() {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, FILL_ME_IN]);

    array.push(3);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should understand array length", function() {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(FILL_ME_IN);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(FILL_ME_IN);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(FILL_ME_IN);
  });

  it("should slice arrays", function() {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
    expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
    expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
    expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
    expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
  });

  it("should know array references", function() {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe(FILL_ME_IN);

    var assignedArray = array;
    assignedArray[5] = "changed in assignedArray";
    expect(array[5]).toBe(FILL_ME_IN);

    var copyOfArray = array.slice();
    copyOfArray[3] = "changed in copyOfArray";
    expect(array[3]).toBe(FILL_ME_IN);
  });

  it("should push and pop", function() {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual(FILL_ME_IN);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });

  it("should know about shifting arrays", function() {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual(FILL_ME_IN);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(FILL_ME_IN);
    expect(array).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Passes remaining "Thinking About Arrays" tests.<commit_after>describe("About Arrays", function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it("should create arrays", function() {
    var emptyArray = [];
    expect(typeof(emptyArray)).toBe("object"); // A mistake?-- http:javascript.crockford.com/remedial.html
    expect(emptyArray.length).toBe(0);

    var multiTypeArray = [0, 1, "two", function() { return 3; }, {value1: 4, value2: 5}, [6, 7]];
    expect(multiTypeArray[0]).toBe(0);
    expect(multiTypeArray[2]).toBe("two");
    expect(multiTypeArray[3]()).toBe(3);
    expect(multiTypeArray[4].value1).toBe(4);
    expect(multiTypeArray[4]["value2"]).toBe(5);
    expect(multiTypeArray[5][0]).toBe(6);
  });

  it("should understand array literals", function() {
    var array = [];
    expect(array).toEqual([]);

    array[0] = 1;
    expect(array).toEqual([1]);

    array[1] = 2;
    expect(array).toEqual([1, 2]);

    array.push(3);
    expect(array).toEqual([1,2,3]);
  });

  it("should understand array length", function() {
    var fourNumberArray = [1, 2, 3, 4];

    expect(fourNumberArray.length).toBe(4);
    fourNumberArray.push(5, 6);
    expect(fourNumberArray.length).toBe(6);

    var tenEmptyElementArray = new Array(10);
    expect(tenEmptyElementArray.length).toBe(10);

    tenEmptyElementArray.length = 5;
    expect(tenEmptyElementArray.length).toBe(5);
  });

  it("should slice arrays", function() {
    var array = ["peanut", "butter", "and", "jelly"];

    expect(array.slice(0, 1)).toEqual(["peanut"]);
    expect(array.slice(0, 2)).toEqual(["peanut", "butter"]);
    expect(array.slice(2, 2)).toEqual([]);
    expect(array.slice(2, 20)).toEqual(["and", "jelly"]);
    expect(array.slice(3, 0)).toEqual([]);
    expect(array.slice(3, 100)).toEqual(["jelly"]);
    expect(array.slice(5, 1)).toEqual([]);
  });

  it("should know array references", function() {
    var array = [ "zero", "one", "two", "three", "four", "five" ];

    function passedByReference(refArray) {
      refArray[1] = "changed in function";
    }
    passedByReference(array);
    expect(array[1]).toBe("changed in function");

    var assignedArray = array;
    assignedArray[5] = "five";
    expect(array[5]).toBe("five");

    var copyOfArray = array.slice();
    copyOfArray[3] = "three";
    expect(array[3]).toBe("three");
  });

  it("should push and pop", function() {
    var array = [1, 2];
    array.push(3);

    expect(array).toEqual([1,2,3]);

    var poppedValue = array.pop();
    expect(poppedValue).toBe(3);
    expect(array).toEqual([1,2]);
  });

  it("should know about shifting arrays", function() {
    var array = [1, 2];

    array.unshift(3);
    expect(array).toEqual([3,1,2]);

    var shiftedValue = array.shift();
    expect(shiftedValue).toEqual(3);
    expect(array).toEqual([1,2]);
  });
});
<|endoftext|>


<commit_before>import { addTemplate } from "./templates";
import { saveGameInfo, creatingGame, clearCreatingGame } from "./game-page";

console.log("stuff: ", document.location);

const ipAddress = document.location.origin.split("/")[2].split(":")[0];

export function getTemplates() {
  return dispatch => {
    fetch(`http://${ipAddress}:8080/api/templates`, {
      method: "GET",
      headers: { "Content-Type": "application/json" },
      mode: "cors"
    })
      .then(res => res.json())
      .then(data => {
        data.map(template => {
          console.log("adding template", template);
          dispatch(addTemplate(template));
        });
      })
      .catch(error => {
        console.log(error);
      });
  };
}

export function postNewGame(templateID) {
  return dispatch => {
    dispatch(creatingGame());
    fetch(`http://${ipAddress}:8080/api/games/new`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      mode: "cors",
      body: JSON.stringify({ templateID: templateID })
    })
      .then(res => {
        return res.json();
      })
      .then(data => {
        console.log(data);
        dispatch(saveGameInfo(data));
        return Promise.resolve();
      })
      .then(() => {
        dispatch(clearCreatingGame());
      })
      .catch(error => {
        console.log(error);
      });
  };
}

export function postNewTemplate(newTemplate) {
  return dispatch => {
    fetch('http://localhost:8080/api/templates/new', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      mode: 'cors',
      body: JSON.stringify({
        templateRules: newTemplate.templateRules,
        templateColumns: newTemplate.templateColumns,
        templateNote: newTemplate.templateNote,
        templateName: newTemplate.templateName
      })
    });
  };
}
<commit_msg>added getGame action to GET games/id<commit_after>import { addTemplate } from './templates';
import {
  saveGameInfo,
  creatingGame,
  clearCreatingGame,
  renderFields
} from './game-page';

console.log('stuff: ', document.location);

const ipAddress = document.location.origin.split('/')[2].split(':')[0];

export function getTemplates() {
  return dispatch => {
    fetch(`http://${ipAddress}:8080/api/templates`, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
      mode: 'cors'
    })
      .then(res => res.json())
      .then(data => {
        data.map(template => {
          console.log('adding template', template);
          dispatch(addTemplate(template));
        });
      })
      .catch(error => {
        console.log(error);
      });
  };
}

export function postNewGame(templateID) {
  return dispatch => {
    dispatch(creatingGame());
    fetch(`http://${ipAddress}:8080/api/games/new`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      mode: 'cors',
      body: JSON.stringify({ templateID: templateID })
    })
      .then(res => {
        return res.json();
      })
      .then(data => {
        console.log(data);
        dispatch(saveGameInfo(data));
        return Promise.resolve();
      })
      .then(() => {
        dispatch(clearCreatingGame());
      })
      .catch(error => {
        console.log(error);
      });
  };
}

export function getGame(gameID) {
  return dispatch => {
    fetch(`http://${ipAddress}:8080/api/games/${gameID}`, {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
      mode: 'cors'
    })
      .then(res => {
        return res.json();
      })
      .then(data => {
        console.log(data.fields);
        dispatch(renderFields(data.fields));
      });
  };
}

export function postNewTemplate(newTemplate) {
  return dispatch => {
    fetch('http://localhost:8080/api/templates/new', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      mode: 'cors',
      body: JSON.stringify({
        templateRules: newTemplate.templateRules,
        templateColumns: newTemplate.templateColumns,
        templateNote: newTemplate.templateNote,
        templateName: newTemplate.templateName
      })
    });
  };
}
<|endoftext|>


<commit_before>import _simpleAt from "./internal/helpers/_simpleAt";
import _simpleSet from "./internal/helpers/_simpleSet";

/**
 * Groups the contents of an array by one or more iteratees.
 * Unlike Lodash [`groupBy()`](https://lodash.com/docs/4.17.4#groupBy),
 * this function can create nested groups, but cannot receive
 * strings for iteratees.
 *
 * @category Collection
 *
 * @param  {Array.<Object>} collection The original array.
 * @param  {...Function} [...iteratees] The functions used to group the array of objects by their results.
 * @return {Object} The resulting object.
 *
 * @example
 *
 * const getLength = str => str.length;
 * const getFirstLetter = str => str.slice(0, 1);
 *
 * deepGroupBy(["one", "two", "three"], getLength, getFirstLetter);
 * // => {
 * // => 	"3": {"o": ["one"], "t": ["two"]},
 * // => 	"5": {"t": ["three"]}
 * // => }
 *
 * @example
 *
 * const getLength = str => str.length;
 * const getFirstLetter = str => str.slice(0, 1);
 *
 * deepGroupBy(["one", "two", "three"], getFirstLetter, getLength);
 * // => {
 * // => 	"o": {"3": ["one"]},
 * // => 	"t": {"3": ["two"], "5": ["three"]}
 * // => }
 *
 * @example
 *
 * const stores = [{
 * 	"name": "Iguatemi",
 * 	"city": "Campinas",
 * 	"state": "SP"
 * }, {
 * 	"name": "Jardins",
 * 	"city": "São Paulo",
 * 	"state": "SP"
 * }, {
 * 	"name": "Iguatemi",
 * 	"city": "São Paulo",
 * 	"state": "SP"
 * }, {
 * 	"name": "Pedras",
 * 	"city": "Búzios",
 * 	"state": "RJ"
 * }, {
 * 	"name": "Ipanema",
 * 	"city": "Rio de Janeiro",
 * 	"state": "RJ"
 * }, {
 * 	"name": "Leblon",
 * 	"city": "Rio de Janeiro",
 * 	"state": "RJ"
 * }, {
 * 	"name": "ParkShopping",
 * 	"city": "Brasília",
 * 	"state": "DF"
 * }];
 *
 * const getStateName = item => item.state;
 * const getCityName = item => item.city;
 *
 * deepGroupBy(stores, getStateName, getCityName);
 * // => {
 * // => 	"SP": { "Campinas": [...], "São Paulo": [...] },
 * // => 	"RJ": { "Búzios": [...], "Rio de Janeiro": [...] },
 * // => 	"DF": { "Brasília": [...] }
 * // => }
 */
const deepGroupBy = (collection, ...iteratees) => {
	let paths = collection.map(value => iteratees.map(iteratee => iteratee(value))),
		result = {};

	paths.forEach((path, index) => {
		let currentValue = _simpleAt(result, path);
		let newValue = (typeof currentValue === "undefined") ? [collection[index]] : currentValue.concat([collection[index]]);
		_simpleSet(result, path, newValue);
	});

	return result;
};

export default deepGroupBy;
<commit_msg>corrected collection type<commit_after>import _simpleAt from "./internal/helpers/_simpleAt";
import _simpleSet from "./internal/helpers/_simpleSet";

/**
 * Groups the contents of an array by one or more iteratees.
 * Unlike Lodash [`groupBy()`](https://lodash.com/docs/4.17.4#groupBy),
 * this function can create nested groups, but cannot receive
 * strings for iteratees.
 *
 * @category Collection
 *
 * @param  {Array} collection The original array.
 * @param  {...Function} [...iteratees] The functions used to group the array of objects by their results.
 * @return {Object} The resulting object.
 *
 * @example
 *
 * const getLength = str => str.length;
 * const getFirstLetter = str => str.slice(0, 1);
 *
 * deepGroupBy(["one", "two", "three"], getLength, getFirstLetter);
 * // => {
 * // => 	"3": {"o": ["one"], "t": ["two"]},
 * // => 	"5": {"t": ["three"]}
 * // => }
 *
 * @example
 *
 * const getLength = str => str.length;
 * const getFirstLetter = str => str.slice(0, 1);
 *
 * deepGroupBy(["one", "two", "three"], getFirstLetter, getLength);
 * // => {
 * // => 	"o": {"3": ["one"]},
 * // => 	"t": {"3": ["two"], "5": ["three"]}
 * // => }
 *
 * @example
 *
 * const stores = [{
 * 	"name": "Iguatemi",
 * 	"city": "Campinas",
 * 	"state": "SP"
 * }, {
 * 	"name": "Jardins",
 * 	"city": "São Paulo",
 * 	"state": "SP"
 * }, {
 * 	"name": "Iguatemi",
 * 	"city": "São Paulo",
 * 	"state": "SP"
 * }, {
 * 	"name": "Pedras",
 * 	"city": "Búzios",
 * 	"state": "RJ"
 * }, {
 * 	"name": "Ipanema",
 * 	"city": "Rio de Janeiro",
 * 	"state": "RJ"
 * }, {
 * 	"name": "Leblon",
 * 	"city": "Rio de Janeiro",
 * 	"state": "RJ"
 * }, {
 * 	"name": "ParkShopping",
 * 	"city": "Brasília",
 * 	"state": "DF"
 * }];
 *
 * const getStateName = item => item.state;
 * const getCityName = item => item.city;
 *
 * deepGroupBy(stores, getStateName, getCityName);
 * // => {
 * // => 	"SP": { "Campinas": [...], "São Paulo": [...] },
 * // => 	"RJ": { "Búzios": [...], "Rio de Janeiro": [...] },
 * // => 	"DF": { "Brasília": [...] }
 * // => }
 */
const deepGroupBy = (collection, ...iteratees) => {
	let paths = collection.map(value => iteratees.map(iteratee => iteratee(value))),
		result = {};

	paths.forEach((path, index) => {
		let currentValue = _simpleAt(result, path);
		let newValue = (typeof currentValue === "undefined") ? [collection[index]] : currentValue.concat([collection[index]]);
		_simpleSet(result, path, newValue);
	});

	return result;
};

export default deepGroupBy;
<|endoftext|>


<commit_before>"use strict";

var db = {

    changelogFile : "changelog.json",
    changelog: [],

    accountsFile : "accounts.json",
    accounts: { sequence: 0, data : {} }, //data[account] = {row}

    foldersFile : "folders.json",
    folders: {}, //assoziative array of assoziative array : folders[<int>accountID][<string>folderID] = {row}

    accountsTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
    foldersTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
    changelogTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),

    writeDelay : 6000,

    saveAccounts: function () {
        db.accountsTimer.cancel();
        db.accountsTimer.init(db.writeJSON, db.writeDelay + 1, 0);
    },

    saveFolders: function () {
        db.foldersTimer.cancel();
        db.foldersTimer.init(db.writeJSON, db.writeDelay + 2, 0);
    },

    saveChangelog: function () {
        db.changelogTimer.cancel();
        db.changelogTimer.init(db.writeJSON, db.writeDelay + 3, 0);
    },

    writeJSON : {
      observe: function(subject, topic, data) {
        switch (subject.delay) { //use delay setting to find out, which file is to be saved
            case (db.writeDelay + 1): tbSync.writeAsyncJSON(db.accounts, db.accountsFile); break;
            case (db.writeDelay + 2): tbSync.writeAsyncJSON(db.folders, db.foldersFile); break;
            case (db.writeDelay + 3): tbSync.writeAsyncJSON(db.changelog, db.changelogFile); break;
        }
      }
    },

    // CHANGELOG FUNCTIONS

    getItemStatusFromChangeLog: function (parentId, itemId) {
        for (let i=0; i<this.changelog.length; i++) {
            if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i].status;
        }
        return null;
    },

    addItemToChangeLog: function (parentId, itemId, status) {
        this.removeItemFromChangeLog(parentId, itemId);

        let row = {
            "parentId" : parentId,
            "itemId" : itemId,
            "status" : status};

        this.changelog.push(row);
        this.saveChangelog();
    },

    removeItemFromChangeLog: function (parentId, itemId, moveToEnd = false) {
        for (let i=this.changelog.length-1; i>-1; i-- ) {
            if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) {
                let row = this.changelog.splice(i,1);
                if (moveToEnd) this.changelog.push(row[0]);
                this.saveChangelog();
                return;
            }
        }
    },

    // Remove all cards of a parentId from ChangeLog
    clearChangeLog: function (parentId) {
        for (let i=this.changelog.length-1; i>-1; i-- ) {
            if (this.changelog[i].parentId == parentId) this.changelog.splice(i,1);
        }
        this.saveChangelog();
    },

    getItemsFromChangeLog: function (parentId, maxnumbertosend, status = null) {
        //maxnumbertosend = 0 will return all results
        let log = [];
        let counts = 0;
        for (let i=0; i<this.changelog.length && (log.length < maxnumbertosend || maxnumbertosend == 0); i++) {
            if (this.changelog[i].parentId == parentId && (status === null || this.changelog[i].status.indexOf(status) != -1)) log.push({ "id":this.changelog[i].itemId, "status":this.changelog[i].status, "type":this.changelog[i].type });
        }
        return log;
    },

    // ACCOUNT FUNCTIONS

    isValidAccountSetting: function (settings, name) {
        //the only hardcoded account option is "provider", all others are taken from tbSync[provider].getNewAccountEntry())
        return ((name == "provider" || tbSync[settings.provider].getNewAccountEntry().hasOwnProperty(name)));
    },

    getDefaultAccountSetting: function (settings, name) {
        //THIS FUNCTION ASSUMES, THAT THE GIVEN FIELD IS VALID
        return tbSync[settings.provider].getNewAccountEntry()[name];
    },

    addAccount: function (newAccountEntry) {
        this.accounts.sequence++;
        let id = this.accounts.sequence;
        newAccountEntry.account = id.toString(),

        this.accounts.data[id]=newAccountEntry;
        this.saveAccounts();
        return id;
    },

    removeAccount: function (account) {
        //check if account is known
        if (this.accounts.data.hasOwnProperty(account) == false ) {
            throw "Unknown account!" + "\nThrown by db.removeAccount("+account+ ")";
        } else {
            delete(this.accounts.data[account]);
            this.saveAccounts();
        }
    },

    setAccountSetting: function (account , name, value) {
        // if the requested account does not exist, getAccount() will fail
        let settings = this.getAccount(account);

        //check if field is allowed, and set given value
        if (this.isValidAccountSetting(settings, name)) {
            this.accounts.data[account][name] = value.toString();
        } else {
            throw "Unknown account setting!" + "\nThrown by db.setAccountSetting("+account+", " + name + ", " + value + ")";
        }
        this.saveAccounts();
    },

    getAccounts: function () {
        let accounts = {};
        accounts.IDs = Object.keys(this.accounts.data).sort((a, b) => a - b);
        accounts.data = this.accounts.data;
        return accounts;
    },

    getAccount: function (account) {
        //check if account is known
        if (this.accounts.data.hasOwnProperty(account) == false ) {
            throw "Unknown account!" + "\nThrown by db.getAccount("+account+ ")";
        } else {
            return this.accounts.data[account];
        }
    },

    getAccountSetting: function (account, name) {
        let data = this.getAccount(account);

        //check if field is allowed and get value or default value if setting is not set
        if (this.isValidAccountSetting(data, name)) {
            if (data.hasOwnProperty(name)) return data[name];
            else return this.getDefaultAccountSetting(data, name);
        }
        else throw "Unknown account setting!" + "\nThrown by db.getAccountSetting("+account+", " + name + ")";
    },

    // FOLDER FUNCTIONS

    isValidFolderSetting: function (account, field) {
        let provider = this.getAccountSetting(account, "provider");
        return tbSync[provider].getNewFolderEntry().hasOwnProperty(field);
    },

    getDefaultFolderSetting: function (account, field) {
        //THIS FUNCTION ASSUMES, THAT THE GIVEN FIELD IS VALID
        let provider = this.getAccountSetting(account, "provider");
        return tbSync[provider].getNewFolderEntry()[name];
    },

    addFolder: function(data) {
        let account = parseInt(data.account);
        if (!this.folders.hasOwnProperty(account)) this.folders[account] = {};

        this.folders[account][data.folderID] = data;
        this.saveFolders();
    },

    deleteFolder: function(account, folderID) {
        delete (this.folders[account][folderID]);
        //if there are no more folders, delete entire account entry
        if (Object.keys(this.folders[account]).length === 0) delete (this.folders[account]);
        this.saveFolders();
    },

    //get all folders of a given account.
    getFolders: function (account) {
        if (!this.folders.hasOwnProperty(account)) this.folders[account] = {};
        return this.folders[account];
    },

    //get a specific folder
    getFolder: function(account, folderID) {
        let folders = this.getFolders(account);
        //does the folder exist?
        if (folders.hasOwnProperty(folderID)) return folders[folderID];
        else return null;
    },

    getFolderSetting: function(account, folderID, field) {
        let folder = this.getFolder(account, folderID);
        //does the field exist?
        if (folder === null || !this.isValidFolderSetting(account, field)) throw "Unknown folder field!" + "\nThrown by db.getFolderSetting("+account+", " + folderID + ", " + field + ")";
        else {
            if (folder.hasOwnProperty(field)) return folder[field];
            else return this.getDefaultFolderSetting(account, field); //TODO: Actually set the default setting, so that the folder OBJ has the value as well?
        }
    },

    findFoldersWithSetting: function (_folderFields, _folderValues, _accountFields = [], _accountValues = []) {
        //Find values based on one (string) or more (array) field conditions in folder and account data.
        //folderValues element may contain "," to seperate multiple field values for matching (OR)
        let data = [];
        let folderFields = [];
        let folderValues = [];
        let accountFields = [];
        let accountValues = [];

        //turn string parameters into arrays
        if (Array.isArray(_folderFields)) folderFields = _folderFields; else folderFields.push(_folderFields);
        if (Array.isArray(_folderValues)) folderValues = _folderValues; else folderValues.push(_folderValues);
        if (Array.isArray(_accountFields)) accountFields = _accountFields; else accountFields.push(_accountFields);
        if (Array.isArray(_accountValues)) accountValues = _accountValues; else accountValues.push(_accountValues);

        //fallback to old interface (name, value, account = "")
        if (accountFields.length == 1 && accountValues.length == 0) {
            accountValues.push(accountFields[0]);
            accountFields[0] = "account";
        }

        for (let aID in this.folders) {
            //is this a leftover folder list of an account, which no longer there?
            if (!this.accounts.data.hasOwnProperty(aID)) {
              delete (this.folders[aID]);
              this.saveFolders();
              continue;
            }

            //does this account match account search options?
            let accountmatch = true;
            for (let a = 0; a < accountFields.length && accountmatch; a++) {
                accountmatch = (this.getAccountSetting(aID, accountFields[a]) == accountValues[a]);
            }

            if (accountmatch) {
                for (let fID in this.folders[aID]) {
                    //does this folder match folder search options?
                    let foldermatch = true;
                    for (let f = 0; f < folderFields.length && foldermatch; f++) {
                        foldermatch = folderValues[f].split(",").includes(this.getFolderSetting(aID, fID, folderFields[f]));
                    }
                    if (foldermatch) data.push(this.folders[aID][fID]);
                }
            }
        }

        //still a reference to the original data
        return data;
    },

    setFolderSetting: function(account, folderID, field, value) {
        //this function can update ALL folders for a given account (if folderID == "") or just a specific folder
        //folders will contain all folders, which need to be updated;
        if (this.isValidFolderSetting(account, field)) {
            let folders = this.getFolders(account);

            if (folderID == "") {
                for (let fID in folders) {
                    folders[fID][field] = value.toString();
                }
            } else {
                folders[folderID][field] = value.toString();
            }

            this.saveFolders();
        } else {
            throw "Unknown folder field!" + "\nThrown by db.setFolderSetting("+account+", " + folderID + ", " + field + ", " + value + ")";
        }
    },

    init: Task.async (function* ()  {

        tbSync.dump("INIT","DB");

        //DB Concept:
        //-- on application start, data is read async from json file into object
        //-- AddOn only works on object
        //-- each time data is changed, an async write job is initiated 2s in the future and is resceduled, if another request arrives within that time

        //load changelog from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.changelogFile));
            db.changelog = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

        //load accounts from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.accountsFile));
            db.accounts = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

        //load folders from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.foldersFile));
            db.folders = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

    }),

};
<commit_msg>fix db using wrong var<commit_after>"use strict";

var db = {

    changelogFile : "changelog.json",
    changelog: [],

    accountsFile : "accounts.json",
    accounts: { sequence: 0, data : {} }, //data[account] = {row}

    foldersFile : "folders.json",
    folders: {}, //assoziative array of assoziative array : folders[<int>accountID][<string>folderID] = {row}

    accountsTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
    foldersTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
    changelogTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),

    writeDelay : 6000,

    saveAccounts: function () {
        db.accountsTimer.cancel();
        db.accountsTimer.init(db.writeJSON, db.writeDelay + 1, 0);
    },

    saveFolders: function () {
        db.foldersTimer.cancel();
        db.foldersTimer.init(db.writeJSON, db.writeDelay + 2, 0);
    },

    saveChangelog: function () {
        db.changelogTimer.cancel();
        db.changelogTimer.init(db.writeJSON, db.writeDelay + 3, 0);
    },

    writeJSON : {
      observe: function(subject, topic, data) {
        switch (subject.delay) { //use delay setting to find out, which file is to be saved
            case (db.writeDelay + 1): tbSync.writeAsyncJSON(db.accounts, db.accountsFile); break;
            case (db.writeDelay + 2): tbSync.writeAsyncJSON(db.folders, db.foldersFile); break;
            case (db.writeDelay + 3): tbSync.writeAsyncJSON(db.changelog, db.changelogFile); break;
        }
      }
    },

    // CHANGELOG FUNCTIONS

    getItemStatusFromChangeLog: function (parentId, itemId) {
        for (let i=0; i<this.changelog.length; i++) {
            if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) return this.changelog[i].status;
        }
        return null;
    },

    addItemToChangeLog: function (parentId, itemId, status) {
        this.removeItemFromChangeLog(parentId, itemId);

        let row = {
            "parentId" : parentId,
            "itemId" : itemId,
            "status" : status};

        this.changelog.push(row);
        this.saveChangelog();
    },

    removeItemFromChangeLog: function (parentId, itemId, moveToEnd = false) {
        for (let i=this.changelog.length-1; i>-1; i-- ) {
            if (this.changelog[i].parentId == parentId && this.changelog[i].itemId == itemId) {
                let row = this.changelog.splice(i,1);
                if (moveToEnd) this.changelog.push(row[0]);
                this.saveChangelog();
                return;
            }
        }
    },

    // Remove all cards of a parentId from ChangeLog
    clearChangeLog: function (parentId) {
        for (let i=this.changelog.length-1; i>-1; i-- ) {
            if (this.changelog[i].parentId == parentId) this.changelog.splice(i,1);
        }
        this.saveChangelog();
    },

    getItemsFromChangeLog: function (parentId, maxnumbertosend, status = null) {
        //maxnumbertosend = 0 will return all results
        let log = [];
        let counts = 0;
        for (let i=0; i<this.changelog.length && (log.length < maxnumbertosend || maxnumbertosend == 0); i++) {
            if (this.changelog[i].parentId == parentId && (status === null || this.changelog[i].status.indexOf(status) != -1)) log.push({ "id":this.changelog[i].itemId, "status":this.changelog[i].status, "type":this.changelog[i].type });
        }
        return log;
    },

    // ACCOUNT FUNCTIONS

    isValidAccountSetting: function (settings, name) {
        //the only hardcoded account option is "provider", all others are taken from tbSync[provider].getNewAccountEntry())
        return ((name == "provider" || tbSync[settings.provider].getNewAccountEntry().hasOwnProperty(name)));
    },

    getDefaultAccountSetting: function (settings, name) {
        //THIS FUNCTION ASSUMES, THAT THE GIVEN FIELD IS VALID
        return tbSync[settings.provider].getNewAccountEntry()[name];
    },

    addAccount: function (newAccountEntry) {
        this.accounts.sequence++;
        let id = this.accounts.sequence;
        newAccountEntry.account = id.toString(),

        this.accounts.data[id]=newAccountEntry;
        this.saveAccounts();
        return id;
    },

    removeAccount: function (account) {
        //check if account is known
        if (this.accounts.data.hasOwnProperty(account) == false ) {
            throw "Unknown account!" + "\nThrown by db.removeAccount("+account+ ")";
        } else {
            delete(this.accounts.data[account]);
            this.saveAccounts();
        }
    },

    setAccountSetting: function (account , name, value) {
        // if the requested account does not exist, getAccount() will fail
        let settings = this.getAccount(account);

        //check if field is allowed, and set given value
        if (this.isValidAccountSetting(settings, name)) {
            this.accounts.data[account][name] = value.toString();
        } else {
            throw "Unknown account setting!" + "\nThrown by db.setAccountSetting("+account+", " + name + ", " + value + ")";
        }
        this.saveAccounts();
    },

    getAccounts: function () {
        let accounts = {};
        accounts.IDs = Object.keys(this.accounts.data).sort((a, b) => a - b);
        accounts.data = this.accounts.data;
        return accounts;
    },

    getAccount: function (account) {
        //check if account is known
        if (this.accounts.data.hasOwnProperty(account) == false ) {
            throw "Unknown account!" + "\nThrown by db.getAccount("+account+ ")";
        } else {
            return this.accounts.data[account];
        }
    },

    getAccountSetting: function (account, name) {
        let data = this.getAccount(account);

        //check if field is allowed and get value or default value if setting is not set
        if (this.isValidAccountSetting(data, name)) {
            if (data.hasOwnProperty(name)) return data[name];
            else return this.getDefaultAccountSetting(data, name);
        }
        else throw "Unknown account setting!" + "\nThrown by db.getAccountSetting("+account+", " + name + ")";
    },

    // FOLDER FUNCTIONS

    isValidFolderSetting: function (account, field) {
        let provider = this.getAccountSetting(account, "provider");
        return tbSync[provider].getNewFolderEntry().hasOwnProperty(field);
    },

    getDefaultFolderSetting: function (account, field) {
        //THIS FUNCTION ASSUMES, THAT THE GIVEN FIELD IS VALID
        let provider = this.getAccountSetting(account, "provider");
        return tbSync[provider].getNewFolderEntry()[field];
    },

    addFolder: function(data) {
        let account = parseInt(data.account);
        if (!this.folders.hasOwnProperty(account)) this.folders[account] = {};

        this.folders[account][data.folderID] = data;
        this.saveFolders();
    },

    deleteFolder: function(account, folderID) {
        delete (this.folders[account][folderID]);
        //if there are no more folders, delete entire account entry
        if (Object.keys(this.folders[account]).length === 0) delete (this.folders[account]);
        this.saveFolders();
    },

    //get all folders of a given account.
    getFolders: function (account) {
        if (!this.folders.hasOwnProperty(account)) this.folders[account] = {};
        return this.folders[account];
    },

    //get a specific folder
    getFolder: function(account, folderID) {
        let folders = this.getFolders(account);
        //does the folder exist?
        if (folders.hasOwnProperty(folderID)) return folders[folderID];
        else return null;
    },

    getFolderSetting: function(account, folderID, field) {
        let folder = this.getFolder(account, folderID);
        //does the field exist?
        if (folder === null || !this.isValidFolderSetting(account, field)) throw "Unknown folder field!" + "\nThrown by db.getFolderSetting("+account+", " + folderID + ", " + field + ")";
        else {
            if (folder.hasOwnProperty(field)) return folder[field];
            else return this.getDefaultFolderSetting(account, field); //TODO: Actually set the default setting, so that the folder OBJ has the value as well?
        }
    },

    findFoldersWithSetting: function (_folderFields, _folderValues, _accountFields = [], _accountValues = []) {
        //Find values based on one (string) or more (array) field conditions in folder and account data.
        //folderValues element may contain "," to seperate multiple field values for matching (OR)
        let data = [];
        let folderFields = [];
        let folderValues = [];
        let accountFields = [];
        let accountValues = [];

        //turn string parameters into arrays
        if (Array.isArray(_folderFields)) folderFields = _folderFields; else folderFields.push(_folderFields);
        if (Array.isArray(_folderValues)) folderValues = _folderValues; else folderValues.push(_folderValues);
        if (Array.isArray(_accountFields)) accountFields = _accountFields; else accountFields.push(_accountFields);
        if (Array.isArray(_accountValues)) accountValues = _accountValues; else accountValues.push(_accountValues);

        //fallback to old interface (name, value, account = "")
        if (accountFields.length == 1 && accountValues.length == 0) {
            accountValues.push(accountFields[0]);
            accountFields[0] = "account";
        }

        for (let aID in this.folders) {
            //is this a leftover folder list of an account, which no longer there?
            if (!this.accounts.data.hasOwnProperty(aID)) {
              delete (this.folders[aID]);
              this.saveFolders();
              continue;
            }

            //does this account match account search options?
            let accountmatch = true;
            for (let a = 0; a < accountFields.length && accountmatch; a++) {
                accountmatch = (this.getAccountSetting(aID, accountFields[a]) == accountValues[a]);
            }

            if (accountmatch) {
                for (let fID in this.folders[aID]) {
                    //does this folder match folder search options?
                    let foldermatch = true;
                    for (let f = 0; f < folderFields.length && foldermatch; f++) {
                        foldermatch = folderValues[f].split(",").includes(this.getFolderSetting(aID, fID, folderFields[f]));
                    }
                    if (foldermatch) data.push(this.folders[aID][fID]);
                }
            }
        }

        //still a reference to the original data
        return data;
    },

    setFolderSetting: function(account, folderID, field, value) {
        //this function can update ALL folders for a given account (if folderID == "") or just a specific folder
        //folders will contain all folders, which need to be updated;
        if (this.isValidFolderSetting(account, field)) {
            let folders = this.getFolders(account);

            if (folderID == "") {
                for (let fID in folders) {
                    folders[fID][field] = value.toString();
                }
            } else {
                folders[folderID][field] = value.toString();
            }

            this.saveFolders();
        } else {
            throw "Unknown folder field!" + "\nThrown by db.setFolderSetting("+account+", " + folderID + ", " + field + ", " + value + ")";
        }
    },

    init: Task.async (function* ()  {

        tbSync.dump("INIT","DB");

        //DB Concept:
        //-- on application start, data is read async from json file into object
        //-- AddOn only works on object
        //-- each time data is changed, an async write job is initiated 2s in the future and is resceduled, if another request arrives within that time

        //load changelog from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.changelogFile));
            db.changelog = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

        //load accounts from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.accountsFile));
            db.accounts = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

        //load folders from file
        try {
            let data = yield OS.File.read(tbSync.getAbsolutePath(db.foldersFile));
            db.folders = JSON.parse(tbSync.decoder.decode(data));
        } catch (ex) {
            //if there is no file, there is no file...
        }

    }),

};
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var AnimationComponent = require('../../gameobjects/components/Animation');
var Class = require('../../utils/Class');
var Components = require('./components');
var GameObject = require('../../gameobjects/GameObject');
var GetFastValue = require('../../utils/object/GetFastValue');
var Pipeline = require('../../gameobjects/components/Pipeline');
var Sprite = require('../../gameobjects/sprite/Sprite');
var Vector2 = require('../../math/Vector2');

/**
 * @classdesc
 * A Matter Physics Sprite Game Object.
 *
 * A Sprite Game Object is used for the display of both static and animated images in your game.
 * Sprites can have input events and physics bodies. They can also be tweened, tinted, scrolled
 * and animated.
 *
 * The main difference between a Sprite and an Image Game Object is that you cannot animate Images.
 * As such, Sprites take a fraction longer to process and have a larger API footprint due to the Animation
 * Component. If you do not require animation then you can safely use Images to replace Sprites in all cases.
 *
 * @class Sprite
 * @extends Phaser.GameObjects.Sprite
 * @memberof Phaser.Physics.Matter
 * @constructor
 * @since 3.0.0
 *
 * @extends Phaser.Physics.Matter.Components.Bounce
 * @extends Phaser.Physics.Matter.Components.Collision
 * @extends Phaser.Physics.Matter.Components.Force
 * @extends Phaser.Physics.Matter.Components.Friction
 * @extends Phaser.Physics.Matter.Components.Gravity
 * @extends Phaser.Physics.Matter.Components.Mass
 * @extends Phaser.Physics.Matter.Components.Sensor
 * @extends Phaser.Physics.Matter.Components.SetBody
 * @extends Phaser.Physics.Matter.Components.Sleep
 * @extends Phaser.Physics.Matter.Components.Static
 * @extends Phaser.Physics.Matter.Components.Transform
 * @extends Phaser.Physics.Matter.Components.Velocity
 * @extends Phaser.GameObjects.Components.Alpha
 * @extends Phaser.GameObjects.Components.BlendMode
 * @extends Phaser.GameObjects.Components.Depth
 * @extends Phaser.GameObjects.Components.Flip
 * @extends Phaser.GameObjects.Components.GetBounds
 * @extends Phaser.GameObjects.Components.Origin
 * @extends Phaser.GameObjects.Components.Pipeline
 * @extends Phaser.GameObjects.Components.ScrollFactor
 * @extends Phaser.GameObjects.Components.Size
 * @extends Phaser.GameObjects.Components.Texture
 * @extends Phaser.GameObjects.Components.Tint
 * @extends Phaser.GameObjects.Components.Transform
 * @extends Phaser.GameObjects.Components.Visible
 *
 * @param {Phaser.Physics.Matter.World} world - A reference to the Matter.World instance that this body belongs to.
 * @param {number} x - The horizontal position of this Game Object in the world.
 * @param {number} y - The vertical position of this Game Object in the world.
 * @param {(string|Phaser.Textures.Texture)} texture - The key, or instance of the Texture this Game Object will use to render with, as stored in the Texture Manager.
 * @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
 * @param {Phaser.Types.Physics.Matter.MatterBodyConfig} [options] - An optional Body configuration object that is used to set initial Body properties on creation.
 */
var MatterSprite = new Class({

    Extends: Sprite,

    Mixins: [
        Components.Bounce,
        Components.Collision,
        Components.Force,
        Components.Friction,
        Components.Gravity,
        Components.Mass,
        Components.Sensor,
        Components.SetBody,
        Components.Sleep,
        Components.Static,
        Components.Transform,
        Components.Velocity,
        Pipeline
    ],

    initialize:

    function MatterSprite (world, x, y, texture, frame, options)
    {
        GameObject.call(this, world.scene, 'Sprite');

        /**
         * The internal crop data object, as used by `setCrop` and passed to the `Frame.setCropUVs` method.
         *
         * @name Phaser.Physics.Matter.Sprite#_crop
         * @type {object}
         * @private
         * @since 3.24.0
         */
        this._crop = this.resetCropObject();

        this.anims = new AnimationComponent(this);

        this.setTexture(texture, frame);
        this.setSizeToFrame();
        this.setOrigin();

        /**
         * A reference to the Matter.World instance that this body belongs to.
         *
         * @name Phaser.Physics.Matter.Sprite#world
         * @type {Phaser.Physics.Matter.World}
         * @since 3.0.0
         */
        this.world = world;

        /**
         * An internal temp vector used for velocity and force calculations.
         *
         * @name Phaser.Physics.Matter.Sprite#_tempVec2
         * @type {Phaser.Math.Vector2}
         * @private
         * @since 3.0.0
         */
        this._tempVec2 = new Vector2(x, y);

        var shape = GetFastValue(options, 'shape', null);

        if (shape)
        {
            this.setBody(shape, options);
        }
        else
        {
            this.setRectangle(this.width, this.height, options);
        }

        this.setPosition(x, y);

        this.initPipeline('MultiPipeline');
    }

});

module.exports = MatterSprite;
<commit_msg>Fixed reference<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var AnimationState = require('../../gameobjects/components/AnimationState');
var Class = require('../../utils/Class');
var Components = require('./components');
var GameObject = require('../../gameobjects/GameObject');
var GetFastValue = require('../../utils/object/GetFastValue');
var Pipeline = require('../../gameobjects/components/Pipeline');
var Sprite = require('../../gameobjects/sprite/Sprite');
var Vector2 = require('../../math/Vector2');

/**
 * @classdesc
 * A Matter Physics Sprite Game Object.
 *
 * A Sprite Game Object is used for the display of both static and animated images in your game.
 * Sprites can have input events and physics bodies. They can also be tweened, tinted, scrolled
 * and animated.
 *
 * The main difference between a Sprite and an Image Game Object is that you cannot animate Images.
 * As such, Sprites take a fraction longer to process and have a larger API footprint due to the Animation
 * Component. If you do not require animation then you can safely use Images to replace Sprites in all cases.
 *
 * @class Sprite
 * @extends Phaser.GameObjects.Sprite
 * @memberof Phaser.Physics.Matter
 * @constructor
 * @since 3.0.0
 *
 * @extends Phaser.Physics.Matter.Components.Bounce
 * @extends Phaser.Physics.Matter.Components.Collision
 * @extends Phaser.Physics.Matter.Components.Force
 * @extends Phaser.Physics.Matter.Components.Friction
 * @extends Phaser.Physics.Matter.Components.Gravity
 * @extends Phaser.Physics.Matter.Components.Mass
 * @extends Phaser.Physics.Matter.Components.Sensor
 * @extends Phaser.Physics.Matter.Components.SetBody
 * @extends Phaser.Physics.Matter.Components.Sleep
 * @extends Phaser.Physics.Matter.Components.Static
 * @extends Phaser.Physics.Matter.Components.Transform
 * @extends Phaser.Physics.Matter.Components.Velocity
 * @extends Phaser.GameObjects.Components.Alpha
 * @extends Phaser.GameObjects.Components.BlendMode
 * @extends Phaser.GameObjects.Components.Depth
 * @extends Phaser.GameObjects.Components.Flip
 * @extends Phaser.GameObjects.Components.GetBounds
 * @extends Phaser.GameObjects.Components.Origin
 * @extends Phaser.GameObjects.Components.Pipeline
 * @extends Phaser.GameObjects.Components.ScrollFactor
 * @extends Phaser.GameObjects.Components.Size
 * @extends Phaser.GameObjects.Components.Texture
 * @extends Phaser.GameObjects.Components.Tint
 * @extends Phaser.GameObjects.Components.Transform
 * @extends Phaser.GameObjects.Components.Visible
 *
 * @param {Phaser.Physics.Matter.World} world - A reference to the Matter.World instance that this body belongs to.
 * @param {number} x - The horizontal position of this Game Object in the world.
 * @param {number} y - The vertical position of this Game Object in the world.
 * @param {(string|Phaser.Textures.Texture)} texture - The key, or instance of the Texture this Game Object will use to render with, as stored in the Texture Manager.
 * @param {(string|integer)} [frame] - An optional frame from the Texture this Game Object is rendering with.
 * @param {Phaser.Types.Physics.Matter.MatterBodyConfig} [options] - An optional Body configuration object that is used to set initial Body properties on creation.
 */
var MatterSprite = new Class({

    Extends: Sprite,

    Mixins: [
        Components.Bounce,
        Components.Collision,
        Components.Force,
        Components.Friction,
        Components.Gravity,
        Components.Mass,
        Components.Sensor,
        Components.SetBody,
        Components.Sleep,
        Components.Static,
        Components.Transform,
        Components.Velocity,
        Pipeline
    ],

    initialize:

    function MatterSprite (world, x, y, texture, frame, options)
    {
        GameObject.call(this, world.scene, 'Sprite');

        /**
         * The internal crop data object, as used by `setCrop` and passed to the `Frame.setCropUVs` method.
         *
         * @name Phaser.Physics.Matter.Sprite#_crop
         * @type {object}
         * @private
         * @since 3.24.0
         */
        this._crop = this.resetCropObject();

        this.anims = new AnimationState(this);

        this.setTexture(texture, frame);
        this.setSizeToFrame();
        this.setOrigin();

        /**
         * A reference to the Matter.World instance that this body belongs to.
         *
         * @name Phaser.Physics.Matter.Sprite#world
         * @type {Phaser.Physics.Matter.World}
         * @since 3.0.0
         */
        this.world = world;

        /**
         * An internal temp vector used for velocity and force calculations.
         *
         * @name Phaser.Physics.Matter.Sprite#_tempVec2
         * @type {Phaser.Math.Vector2}
         * @private
         * @since 3.0.0
         */
        this._tempVec2 = new Vector2(x, y);

        var shape = GetFastValue(options, 'shape', null);

        if (shape)
        {
            this.setBody(shape, options);
        }
        else
        {
            this.setRectangle(this.width, this.height, options);
        }

        this.setPosition(x, y);

        this.initPipeline('MultiPipeline');
    }

});

module.exports = MatterSprite;
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';
import Box from 'grommet/components/Box';
import Markdown from 'grommet/components/Markdown';
import Animate from 'grommet/components/Animate';
import Headline from 'grommet/components/Headline';
import Button from 'grommet/components/Button';

export default class BlockHero extends Component {
  constructor() {
    super();
    this.setRandomIndex = this.setRandomIndex.bind(this);
    this.calculateRandomIndex = this.calculateRandomIndex.bind(this);
    this.state = {
      currentIndex: 0,
      visible: false,
    };
  }
  componentWillMount() {
    this.setRandomIndex();
  }
  // Recursively calculate next random nextIndex
  calculateRandomIndex() {
    const { carousel } = this.props;
    const randomIndex = Math.floor(Math.random() * carousel.length);
    return randomIndex;
  }
  setRandomIndex() {
    const nextIndex = this.calculateRandomIndex();
    this.setState({
      currentIndex: nextIndex,
      visible: true,
    });
  }
  render() {
    const { carousel, imageSize, headline, content } = this.props;
    const size = imageSize ? imageSize.toLowerCase() : 'large';
    const { currentIndex, visible } = this.state;
    const image = carousel[currentIndex].image;
    const imagePath = image && image.path
      ? image.path
      : '';

    return (
      <Animate
        keep
        visible={visible}
        enter={{ animation: 'fade', duration: 1000, delay: 0 }}
        leave={{ animation: 'fade', duration: 1000, delay: 0 }}
      >
        <Box
          align="center"
          justify="center"
          size={{ height: size, width: size }}
          full={size === 'full'}
          style={{ backgroundSize: 'cover', backgroundPosition: 'center', width: '100vw' }}
          texture={imagePath}
        >
          <Box
            pad="medium"
            align="center"
            justify="center"
            colorIndex="grey-4-a"
          >
            <Headline align="center" size="large" strong>
              {headline || ''}
            </Headline>
            <Markdown
              content={content || ''}
              components={{
                p: { props: { size: 'large', margin: 'small', align: 'center' } },
                h2: { props: { strong: true, align: 'center' } },
              }}
            />
            <Button label="Get Started" path="/brand-central/main" />
          </Box>
        </Box>
      </Animate>
    );
  }
}

BlockHero.propTypes = {
  carousel: PropTypes.array,
  imageSize: PropTypes.string,
  headline: PropTypes.string,
  content: PropTypes.string,
};
<commit_msg>Fix: set block hero visible after timeout<commit_after>import React, { PropTypes, Component } from 'react';
import Box from 'grommet/components/Box';
import Markdown from 'grommet/components/Markdown';
import Animate from 'grommet/components/Animate';
import Headline from 'grommet/components/Headline';
import Button from 'grommet/components/Button';

export default class BlockHero extends Component {
  constructor() {
    super();
    this.setRandomIndex = this.setRandomIndex.bind(this);
    this.calculateRandomIndex = this.calculateRandomIndex.bind(this);
    this.state = {
      currentIndex: 0,
      visible: false
    };
  }
  componentWillMount() {
    this.setRandomIndex();
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({ visible: true });
    }, 1000);
  }
  // Recursively calculate next random nextIndex
  calculateRandomIndex() {
    const { carousel } = this.props;
    const randomIndex = Math.floor(Math.random() * carousel.length);
    return randomIndex;
  }
  setRandomIndex() {
    const nextIndex = this.calculateRandomIndex();
    this.setState({
      currentIndex: nextIndex
    });
  }
  render() {
    const { carousel, imageSize, headline, content } = this.props;
    const size = imageSize ? imageSize.toLowerCase() : 'large';
    const { currentIndex, visible } = this.state;
    const image = carousel[currentIndex].image;
    const imagePath = image && image.path
      ? image.path
      : '';

    return (
      <Animate
        keep
        visible={visible}
        enter={{ animation: 'fade', duration: 1000, delay: 0 }}
        leave={{ animation: 'fade', duration: 1000, delay: 0 }}
      >
        <Box
          align="center"
          justify="center"
          size={{ height: size, width: size }}
          full={size === 'full'}
          style={{ backgroundSize: 'cover', backgroundPosition: 'center', width: '100vw' }}
          texture={imagePath}
        >
          <Box
            pad="medium"
            align="center"
            justify="center"
            colorIndex="grey-4-a"
          >
            <Headline align="center" size="large" strong>
              {headline || ''}
            </Headline>
            <Markdown
              content={content || ''}
              components={{
                'p': { 'props':  { size: 'large', margin: 'small', align: 'center' } },
                'h2': { 'props':  { strong: true, align: 'center' } }
              }}
            />
            <Button label="Get Started" path="/brand-central/main" />
          </Box>
        </Box>
      </Animate>
    );
  }
};

BlockHero.propTypes = {
  carousel: PropTypes.array,
  imageSize: PropTypes.string,
  headline: PropTypes.string,
  content: PropTypes.string
};
<|endoftext|>


<commit_before>// This file is designed to run as a child process, as a workaround to the serialport.close() reliability issue.

var Serialport = require('serialport');
var port = process.argv[2];

// connecting to an AVR109 Leonardo based Arduino at 1200 baud rate resets the device upon disconnect.
var serialPort = new Serialport.SerialPort('/dev/cu.usbmodem1411', {
    baudRate: 1200,
});

// open a connection, then immediately close to perform the reset of the board.
serialPort.on('open', function() {
  serialPort.set({
    rts: true,
    dtr: true
  }, function(err) {
    setTimeout(function clear() {
      serialPort.set({
        rts: false,
        dtr: false
      }, function(err) {
        setTimeout(function done() {
          console.log("arduino reset.");
          serialPort.write('hello');
          console.log(serialPort.isOpen())
        }, 50);
      });
    }, 250);
  });
});
<commit_msg>remove leo-test.js<commit_after><|endoftext|>


<commit_before>angular.module( 'moviematch.match', [] )

.controller( 'MatchController', function( $scope, Match ) {
  $scope.movie = {};
  $scope.session = {};
  $scope.user = {};

  $scope.user.name = "John";
  $scope.user.id = 2;

  $scope.session.name = "Girls Night Out";
  $scope.session.id = 1;

  $scope.movie = {
    name: "Gone With The Wind",
    year: "1939",
    rating: "G",
    runtime: "3h 58m",
    genres: [ "Drama", "Romance", "War" ],
    country: "USA",
    poster_path: "https://www.movieposter.com/posters/archive/main/30/MPW-15446",
    summary: "A manipulative southern belle carries on a turbulent affair with a blockade runner during the American Civil War.",
    director: "Victor Fleming",
    cast: "Clark Cable, Vivian Leigh, Thomas Mitchell",
    id: 1
  }

  $scope.yes = function() { Match.sendVote( $scope.session.id, $scope.user.id, $scope.movie.id, true ); }
  $scope.no = function() { Match.sendVote( $scope.session.id, $scope.user.id, $scope.movie.id, false ); }
} );
<commit_msg>Change sample data back<commit_after>angular.module( 'moviematch.match', [] )

.controller( 'MatchController', function( $scope, Match ) {
  $scope.movie = {};
  $scope.session = {};
  $scope.user = {};

  $scope.user.name = "Julie";
  $scope.user.id = 1;

  $scope.session.name = "Girls Night Out";
  $scope.session.id = 1;

  $scope.movie = {
    name: "Gone With The Wind",
    year: "1939",
    rating: "G",
    runtime: "3h 58m",
    genres: [ "Drama", "Romance", "War" ],
    country: "USA",
    poster_path: "https://www.movieposter.com/posters/archive/main/30/MPW-15446",
    summary: "A manipulative southern belle carries on a turbulent affair with a blockade runner during the American Civil War.",
    director: "Victor Fleming",
    cast: "Clark Cable, Vivian Leigh, Thomas Mitchell",
    id: 1
  }

  $scope.yes = function() { Match.sendVote( $scope.session.id, $scope.user.id, $scope.movie.id, true ); }
  $scope.no = function() { Match.sendVote( $scope.session.id, $scope.user.id, $scope.movie.id, false ); }
} );
<|endoftext|>


<commit_before>requirejs.config({
    baseUrl: "./assets/"
});

define('main', function(require) {
    var angular = require('angular');
    var profile = require('json!profile.json');

    var demo = angular.module('demo', [
        require('elgg/accounts/module').name,
        require('elgg/blog/module').name,
        require('elgg/core/module').name,
        require('elgg/events/module').name,
        require('elgg/photos/module').name,
        require('elgg/posts/module').name,
    ]).value('profile', profile);

    angular.bootstrap(document, [demo.name]);
});
require(['main']);
<commit_msg>feature(appcache): poll for appcache updates<commit_after>requirejs.config({
    baseUrl: "./assets/"
});

define('main', function(require) {
    var angular = require('angular');
    var profile = require('json!profile.json');

    var demo = angular.module('demo', [
        require('elgg/accounts/module').name,
        require('elgg/blog/module').name,
        require('elgg/core/module').name,
        require('elgg/events/module').name,
        require('elgg/photos/module').name,
        require('elgg/posts/module').name,
    ]).value('profile', profile).run(function(profile) {

        profile.appcache = profile.appcache || {};
        // maxAge defaults to once-per-hour
        var maxAge = profile.appcache.maxAge || 1000 * 60 * 60;

        setInterval(function() {
            applicationCache.update();
        }, maxAge);
    });

    angular.bootstrap(document, [demo.name]);
});
require(['main']);
<|endoftext|>


<commit_before>/**
 * Create a new auto complete.
 *
 * @param {Pagelet} pagelet
 * @api private
 */
function autocomplete(pagelet) {
  'use strict';

  var container = $(pagelet.placeholders)
    , target = pagelet.pagelet('target');

  //
  // Add support for adding new services
  //
  var select = container.find('header select').selectize({
    create: false,          // Do not allow creation of new values.
    maxOptions: 15,         // Maximum items in the dropdown.
    onItemAdd: function added(item) {
      var data;

      pagelet.data.services.some(function some(service) {
        if (item === service.name) data = service;
        return !!data;
      });

      target.render(data);
      $(target.placeholders).show();
    }
  })[0];

  //
  // Hide form fields when canceled.
  //
  container.on('click', 'button[name="cancel"]', function click() {
    if (select) {
      select.selectize.clear();       // Reset the auto select/dropdown.
    }

    target.render('');                // Nuke the HTML
    $(target.placeholders).hide();    // Hide the parent element.
  });
}

pipe.on('notifications:target:render', function (pagelet) {
  'use strict';

  var notifications = pagelet.pipe.get('notifications');

  $('input[name="package"]', pagelet.placeholders).selectize({
    valueField: 'name',
    labelField: 'name',
    searchField: 'name',
    maxOptions: 5,          // Maximum items in the dropdown.
    openOnFocus: false,     // Open dropdown on focus.
    createOnBlur: true,     // Blur input, create item.
    maxItems: 1,            // Only allow one module.
    create: true,
    load: function load(query, callback) {
      if (!query.length) return callback();

      notifications.autocomplete(query, function autocomplete(err, results) {
        if (err) return callback();
        callback(results);
      });
    },
    render: {
      option_create: function create(data, escape) {
        return '';
      }
    }
  });
});

pipe.on('notifications:render', autocomplete)
    .on('targets:render', autocomplete);
<commit_msg>[fix] Don't assume autocomplete is available<commit_after>/**
 * Create a new auto complete.
 *
 * @param {Pagelet} pagelet
 * @api private
 */
function autocomplete(pagelet) {
  'use strict';

  var container = $(pagelet.placeholders)
    , target = pagelet.pagelet('target');

  //
  // Add support for adding new services
  //
  var select = container.find('header select').selectize({
    create: false,          // Do not allow creation of new values.
    maxOptions: 15,         // Maximum items in the dropdown.
    onItemAdd: function added(item) {
      var data;

      pagelet.data.services.some(function some(service) {
        if (item === service.name) data = service;
        return !!data;
      });

      target.render(data);
      $(target.placeholders).show();
    }
  })[0];

  //
  // Hide form fields when canceled.
  //
  container.on('click', 'button[name="cancel"]', function click() {
    if (select) {
      select.selectize.clear();       // Reset the auto select/dropdown.
    }

    target.render('');                // Nuke the HTML
    $(target.placeholders).hide();    // Hide the parent element.
  });
}

pipe.on('notifications:target:render', function (pagelet) {
  'use strict';

  var notifications = pagelet.pipe.get('notifications');

  //
  // We're not extended with an autocomplete, bail out.
  //
  if (!('autocomplete' in notifications)) return;

  $('input[name="package"]', pagelet.placeholders).selectize({
    valueField: 'name',
    labelField: 'name',
    searchField: 'name',
    maxOptions: 5,          // Maximum items in the dropdown.
    openOnFocus: false,     // Open dropdown on focus.
    createOnBlur: true,     // Blur input, create item.
    maxItems: 1,            // Only allow one module.
    create: true,
    load: function load(query, callback) {
      if (!query.length) return callback();

      notifications.autocomplete(query, function autocomplete(err, results) {
        if (err) return callback();
        callback(results);
      });
    },
    render: {
      option_create: function create(data, escape) {
        return '';
      }
    }
  });
});

pipe.on('notifications:render', autocomplete)
    .on('targets:render', autocomplete);
<|endoftext|>