<commit_before>var torque = require('./');

var requestAnimationFrame = global.requestAnimationFrame
    || global.mozRequestAnimationFrame
    || global.webkitRequestAnimationFrame
    || global.msRequestAnimationFrame
    || function(callback) { return global.setTimeout(callback, 1000 / 60); };

var cancelAnimationFrame = global.cancelAnimationFrame
    || global.mozCancelAnimationFrame
    || global.webkitCancelAnimationFrame
    || global.msCancelAnimationFrame
    || function(id) { clearTimeout(id); };

  /**
   * options:
   *    animationDuration in seconds
   *    animationDelay in seconds
   */
  function Animator(callback, options) {
    if(!options.steps) {
      throw new Error("steps option missing")
    }
    this.options = options;
    this.running = false;
    this._tick = this._tick.bind(this);
    this._t0 = +new Date();
    this.callback = callback;
    this._time = 0.0;
    this.options = torque.extend({
        animationDelay: 0,
        maxDelta: 0.2,
        loop: options.loop
    }, this.options);

    this.rescale();

  }

  Animator.prototype = {

    start: function() {
      this.running = true;
      requestAnimationFrame(this._tick);
      this.options.onStart && this.options.onStart();
    },

    isRunning: function() {
      return this.running;
    },

    stop: function() {
      this.pause();
      this.time(0);
      this.options.onStop && this.options.onStop();
    },

    // real animation time
    time: function(_) {
      if (!arguments.length) return this._time;
      this._time = _;
      var t = this.range(this.domain(this._time));
      this.callback(t);
    },

    toggle: function() {
      if (this.running) {
        this.pause()
      } else {
        this.start()
      }
    },

    rescale: function() {
      this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration);
      this.domain = this.domainInv.invert();
      this.range = torque.math.linear(0, this.options.steps);
      this.rangeInv = this.range.invert();
      this.time(this._time);
      return this;
    },

    duration: function(_) {
      if (!arguments.length)  return this.options.animationDuration;
      this.options.animationDuration = _;
      if (this.time() > _) {
        this.time(0);
      }
      this.rescale();
      return this;
    },

    steps: function(_) {
      this.options.steps = _;
      return this.rescale();
    },

    step: function(s) {
      if(arguments.length === 0) return this.range(this.domain(this._time));
      this._time = this.domainInv(this.rangeInv(s));
    },

    pause: function() {
      this.running = false;
      cancelAnimationFrame(this._tick);
      this.options.onPause && this.options.onPause();
    },

    _tick: function() {
      var t1 = +new Date();
      var delta = (t1 - this._t0)*0.001;
      // if delta is really big means the tab lost the focus
      // at some point, so limit delta change
      delta = Math.min(this.options.maxDelta, delta);
      this._t0 = t1;
      this._time += delta;
      this.time(this._time);
      if(this.step() >= this.options.steps) {
        this._time = 0;
        if(!this.options.loop){
          this.stop();
        }
      }
      if(this.running) {
        requestAnimationFrame(this._tick);
      }
    }

  };

module.exports = Animator;
<commit_msg>check loop condition before render<commit_after>var torque = require('./');

var requestAnimationFrame = global.requestAnimationFrame
    || global.mozRequestAnimationFrame
    || global.webkitRequestAnimationFrame
    || global.msRequestAnimationFrame
    || function(callback) { return global.setTimeout(callback, 1000 / 60); };

var cancelAnimationFrame = global.cancelAnimationFrame
    || global.mozCancelAnimationFrame
    || global.webkitCancelAnimationFrame
    || global.msCancelAnimationFrame
    || function(id) { clearTimeout(id); };

  /**
   * options:
   *    animationDuration in seconds
   *    animationDelay in seconds
   */
  function Animator(callback, options) {
    if(!options.steps) {
      throw new Error("steps option missing")
    }
    this.options = options;
    this.running = false;
    this._tick = this._tick.bind(this);
    this._t0 = +new Date();
    this.callback = callback;
    this._time = 0.0;
    this.options = torque.extend({
        animationDelay: 0,
        maxDelta: 0.2,
        loop: options.loop
    }, this.options);

    this.rescale();

  }

  Animator.prototype = {

    start: function() {
      this.running = true;
      requestAnimationFrame(this._tick);
      this.options.onStart && this.options.onStart();
    },

    isRunning: function() {
      return this.running;
    },

    stop: function() {
      this.pause();
      this.time(0);
      this.options.onStop && this.options.onStop();
    },

    // real animation time
    time: function(_) {
      if (!arguments.length) return this._time;
      this._time = _;
      var t = this.range(this.domain(this._time));
      this.callback(t);
    },

    toggle: function() {
      if (this.running) {
        this.pause()
      } else {
        this.start()
      }
    },

    rescale: function() {
      this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration);
      this.domain = this.domainInv.invert();
      this.range = torque.math.linear(0, this.options.steps);
      this.rangeInv = this.range.invert();
      this.time(this._time);
      return this;
    },

    duration: function(_) {
      if (!arguments.length)  return this.options.animationDuration;
      this.options.animationDuration = _;
      if (this.time() > _) {
        this.time(0);
      }
      this.rescale();
      return this;
    },

    steps: function(_) {
      this.options.steps = _;
      return this.rescale();
    },

    step: function(s) {
      if(arguments.length === 0) return this.range(this.domain(this._time));
      this._time = this.domainInv(this.rangeInv(s));
    },

    pause: function() {
      this.running = false;
      cancelAnimationFrame(this._tick);
      this.options.onPause && this.options.onPause();
    },

    _tick: function() {
      var t1 = +new Date();
      var delta = (t1 - this._t0)*0.001;
      // if delta is really big means the tab lost the focus
      // at some point, so limit delta change
      delta = Math.min(this.options.maxDelta, delta);
      this._t0 = t1;
      this._time += delta;
      if(this.step() >= this.options.steps) {
        this._time = 0;
        if(!this.options.loop){
          this.stop();
        }
      }
      if(this.running) {
        this.time(this._time);
        requestAnimationFrame(this._tick);
      }
    }

  };

module.exports = Animator;
<|endoftext|>


<commit_before>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module requirements.
 */

var Transport = require('../transport')
  , parser = require('../parser');

/**
 * Export the constructor.
 */

exports = module.exports = HTTPTransport;

/**
 * HTTP interface constructor. For all non-websocket transports.
 *
 * @api public
 */

function HTTPTransport (mng, data) {
  Transport.call(this, mng, data);
};

/**
 * Inherits from Transport.
 */

HTTPTransport.prototype.__proto__ = Transport.prototype;

/**
 * Handles a request.
 *
 * @api private
 */

HTTPTransport.prototype.handleRequest = function (req) {
  if (req.method == 'POST') {
    var buffer = ''
      , res = req.res;

    res.on('data', function (data) {
      buffer += data;
    });

    res.on('end', function () {
      self.onData(buffer);
    });
  } else {
    var self = this;

    this.response = req.res;
    this.open = true;

    Transport.prototype.handleRequest.call(this, req);
  }
};

/**
 * Handles data payload.
 *
 * @api private
 */

HTTPTransport.prototype.onData = function (data) {
  var messages = parser.decodeMany(data);

  for (var i = 0, l = messages.length; i < l; i++) {
    this.onMessage(messages[i]);
  }
};

/**
 * Closes the request-response cycle
 *
 * @api private
 */

HTTPTransport.prototype.doClose = function () {
  this.response.end();
};

/**
 * Writes a payload of messages
 *
 * @api private
 */

HTTPTransport.prototype.payload = function (msgs) {
  this.write(parser.encodePayload(msgs));
};
<commit_msg>Fixed handling of incoming POST requests to a XHR transport. Fixed payloading encoding.<commit_after>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module requirements.
 */

var Transport = require('../transport')
  , parser = require('../parser');

/**
 * Export the constructor.
 */

exports = module.exports = HTTPTransport;

/**
 * HTTP interface constructor. For all non-websocket transports.
 *
 * @api public
 */

function HTTPTransport (mng, data) {
  Transport.call(this, mng, data);
};

/**
 * Inherits from Transport.
 */

HTTPTransport.prototype.__proto__ = Transport.prototype;

/**
 * Handles a request.
 *
 * @api private
 */

HTTPTransport.prototype.handleRequest = function (req) {
  if (req.method == 'POST') {
    var buffer = ''
      , res = req.res
      , self = this;

    req.on('data', function (data) {
      buffer += data;
    });

    req.on('end', function () {
      self.onData(buffer);
    });

    res.writeHead(200);
    res.end('');
  } else {
    this.response = req.res;

    Transport.prototype.handleRequest.call(this, req);
  }
};

/**
 * Handles data payload.
 *
 * @api private
 */

HTTPTransport.prototype.onData = function (data) {
  var messages = parser.decodePayload(data);

  for (var i = 0, l = messages.length; i < l; i++) {
    this.onMessage(messages[i]);
  }
};

/**
 * Closes the request-response cycle
 *
 * @api private
 */

HTTPTransport.prototype.doClose = function () {
  this.response.end();
};

/**
 * Writes a payload of messages
 *
 * @api private
 */

HTTPTransport.prototype.payload = function (msgs) {
  this.write(parser.encodePayload(msgs));
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function trimLeadingZero (str) {
    return str.replace(/0(\.\d*)/g, '$1');
};
<commit_msg>Saner regex for finding leading zero.<commit_after>'use strict';

module.exports = function trimLeadingZero (str) {
    return str.replace(/([^\d])0(\.\d*)/g, '$1$2');
};
<|endoftext|>


<commit_before>(function() {

	document.observe('chinachu:reload', function() {
		document.stopObserving('chinachu:reload', arguments.callee);
		document.stopObserving('chinachu:recording', viewRecording);
		document.stopObserving('chinachu:reserves', viewReserves);
		document.stopObserving('chinachu:reserves', viewScheduler);
		clearInterval(viewReservesInterval);
		clearInterval(viewRecordedInterval);
	})

	var loading = new app.ui.ContentLoading({
		onComplete: function() {
			setTimeout(function() {
				loading.remove();
				loading = null;
			}, 50);
		}
	}).render();

	var ul = new Element('ul');
	$('content-body').insert(ul);

	// 録画中の番組を表示
	function viewRecording() {
		Y.Node.all('#content-body > ul > li.recording').remove();

		app.chinachu.recording.each(function(program, i) {
			var id = program.id + new Date().getTime();
			var li = new Element('li', {className: 'recording', id: id});
			ul.insert({top: li});

			var title = program.title;
			if (!program.pid) { title += ' (待機)'; }
			title += '' + program.channel.name + '';

			li.insert(new Element('div', {className: 'foot', title: program.detail || '説明なし'}).insert(title));

			var jump = '録画中リスト';
			jump += '番組情報表示';

			if (program.pid && !program.tuner.isScrambling && app.chinachu.status.feature.streamer) {
				jump += 'ストリーミング再生';
			}

			li.insert(new Element('div', {className: 'jump'}).insert(jump));

			if (program.pid && !program.tuner.isScrambling && app.chinachu.status.feature.streamer) {
				function preview() {
					if (!$(id)) {
						delete preview;
						delete li;
						return;
					}

					new Ajax.Request('./api/recording/' + program.id + '/preview', {
						method    : 'get',
						parameters: {width: 320, height: 180, nonce: new Date().getTime()},
						onSuccess : function(t) {
							li.style.backgroundImage = 'url(' + t.responseText + ')';

							delete t.responseText;
							t = null;

							setTimeout(preview, 5000);
						}
					});
				}
				preview();
			}
		});
	}
	viewRecording();
	document.observe('chinachu:recording', viewRecording);

	loading.update(20);

	// 予約済リスト
	function viewReserves() {
		if ($('overview-reserves')) {
			var li = $('overview-reserves');
		} else {
			var li = new Element('li', {id: 'overview-reserves'});
			ul.insert(li);
		}

		var posTop = 0;
		$$('#overview-reserves > div.list').each(function(a) {
			posTop = a.cumulativeScrollOffset().top;
		});

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			app.chinachu.reserves.length.toString(10) + '件の予約» 予約済リスト'
		));

		var reservesList = new Element('div', {className: 'list'});
		li.insert(reservesList);

		var dt = new Date().getTime();
		app.chinachu.reserves.each(function(program, i) {
			var r = Math.round((program.start - dt) / 1000);
			var u = '秒後';
			var c = 'color-red';

			if (r < 0) { return; }

			if (r >= 60) {
				r = r / 60;
				u = '分後';
				c = 'color-orange';

				if (r >= 60) {
					r = r / 60;
					u = '時間後';
					c = 'color-green';

					if (r >= 24) {
						r = r / 24;
						u = '日後';
						c = '';
					}
				}
			}

			r = Math.round(r * 10) / 10;

			reservesList.insert(
				'' +
				'' + r.toString(10) + u + '' +
				program.title.truncate(16) +
				'' + program.channel.name.truncate(7) + '' +
				''
			);
		});

		reservesList.scrollTop = posTop;
	}
	viewReserves();
	document.observe('chinachu:reserves', viewReserves);
	var viewReservesInterval = setInterval(viewReserves, 10000);

	loading.update(40);

	// 録画済リスト
	function viewRecorded() {
		if ($('overview-recorded')) {
			var li = $('overview-recorded');
		} else {
			var li = new Element('li', {id: 'overview-recorded'});
			ul.insert(li);
		}

		var posTop = 0;
		$$('#overview-recorded > div.list').each(function(a) {
			posTop = a.cumulativeScrollOffset().top;
		});

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			app.chinachu.recorded.length.toString(10) + '件の録画» 録画済リスト'
		));

		var recordedList = new Element('div', {className: 'list'});
		li.insert(recordedList);

		var dt = new Date().getTime();
		app.chinachu.recorded.each(function(program, i) {
			var r = Math.round((dt - program.end) / 1000);
			var u = '秒前';
			var c = 'color-red';

			if (r >= 60) {
				r = r / 60;
				u = '分前';
				c = 'color-orange';

				if (r >= 60) {
					r = r / 60;
					u = '時間前';
					c = 'color-green';

					if (r >= 24) {
						r = r / 24;
						u = '日前';
						c = '';
					}
				}
			}

			r = Math.round(r * 10) / 10;

			recordedList.insert(
				'' +
				'' + r.toString(10) + u + '' +
				program.title.truncate(16) +
				'' + program.channel.name.truncate(7) + '' +
				''
			);
		});

		recordedList.scrollTop = posTop;
	}
	viewRecorded();
	document.observe('chinachu:recorded', viewRecorded);
	var viewRecordedInterval = setInterval(viewRecorded, 10000);

	loading.update(60);

	// スケジューラー実行結果
	function viewScheduler() {
		if ($('overview-scheduler')) {
			var li = $('overview-scheduler');
		} else {
			var li = new Element('li', {id: 'overview-scheduler'});
			ul.insert(li);
		}

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			'スケジューラー実行結果» ルールリスト'
		));

		var list = new Element('div', {className: 'list'});
		li.insert(list);

		new Ajax.Request('./api/scheduler.json', {
			method    : 'get',
			onComplete: function() {
				if (loading) { loading.update(100); }
			},
			onSuccess: function(t) {
				var d = t.responseJSON;

				list.insert('
' + dateFormat(new Date(d.time), 'yyyy/mm/dd HH:MM:ss') + ' 更新 (' + d.reserves.length.toString(10) + '件を予約)
');
				list.insert('
' + d.conflicts.length.toString(10) + '件の衝突
');

				var dt = new Date().getTime();
				d.conflicts.each(function(program, i) {
					list.insert(
						'' +
						'' + dateFormat(new Date(program.start), 'd日 HH:MM') + '' +
						'' + program.title.truncate(16) + '' +
						'' + program.channel.name.truncate(8) + '' +
						''
					);
				});
			}
		});
	}
	viewScheduler();
	document.observe('chinachu:reserves', viewScheduler);

	loading.update(80);

})();<commit_msg>WUI/Client: 表示崩れの修正<commit_after>(function() {

	document.observe('chinachu:reload', function() {
		document.stopObserving('chinachu:reload', arguments.callee);
		document.stopObserving('chinachu:recording', viewRecording);
		document.stopObserving('chinachu:reserves', viewReserves);
		document.stopObserving('chinachu:reserves', viewScheduler);
		clearInterval(viewReservesInterval);
		clearInterval(viewRecordedInterval);
	})

	var loading = new app.ui.ContentLoading({
		onComplete: function() {
			setTimeout(function() {
				loading.remove();
				loading = null;
			}, 50);
		}
	}).render();

	var ul = new Element('ul');
	$('content-body').insert(ul);

	// 録画中の番組を表示
	function viewRecording() {
		Y.Node.all('#content-body > ul > li.recording').remove();

		app.chinachu.recording.each(function(program, i) {
			var id = program.id + new Date().getTime();
			var li = new Element('li', {className: 'recording', id: id});
			ul.insert({top: li});

			var title = program.title;
			if (!program.pid) { title += ' (待機)'; }
			title += '' + program.channel.name + '';

			li.insert(new Element('div', {className: 'foot', title: program.detail || '説明なし'}).insert(title));

			var jump = '録画中リスト';
			jump += '番組情報表示';

			if (program.pid && !program.tuner.isScrambling && app.chinachu.status.feature.streamer) {
				jump += 'ストリーミング再生';
			}

			li.insert(new Element('div', {className: 'jump'}).insert(jump));

			if (program.pid && !program.tuner.isScrambling && app.chinachu.status.feature.streamer) {
				function preview() {
					if (!$(id)) {
						delete preview;
						delete li;
						return;
					}

					new Ajax.Request('./api/recording/' + program.id + '/preview', {
						method    : 'get',
						parameters: {width: 320, height: 180, nonce: new Date().getTime()},
						onSuccess : function(t) {
							li.style.backgroundImage = 'url(' + t.responseText + ')';

							delete t.responseText;
							t = null;

							setTimeout(preview, 5000);
						}
					});
				}
				preview();
			}
		});
	}
	viewRecording();
	document.observe('chinachu:recording', viewRecording);

	loading.update(20);

	// 予約済リスト
	function viewReserves() {
		if ($('overview-reserves')) {
			var li = $('overview-reserves');
		} else {
			var li = new Element('li', {id: 'overview-reserves'});
			ul.insert(li);
		}

		var posTop = 0;
		$$('#overview-reserves > div.list').each(function(a) {
			posTop = a.cumulativeScrollOffset().top;
		});

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			app.chinachu.reserves.length.toString(10) + '件の予約» 予約済リスト'
		));

		var reservesList = new Element('div', {className: 'list'});
		li.insert(reservesList);

		var dt = new Date().getTime();
		app.chinachu.reserves.each(function(program, i) {
			var r = Math.round((program.start - dt) / 1000);
			var u = '秒後';
			var c = 'color-red';

			if (r < 0) { return; }

			if (r >= 60) {
				r = r / 60;
				u = '分後';
				c = 'color-orange';

				if (r >= 60) {
					r = r / 60;
					u = '時間後';
					c = 'color-green';

					if (r >= 24) {
						r = r / 24;
						u = '日後';
						c = '';
					}
				}
			}

			r = Math.round(r * 10) / 10;

			reservesList.insert(
				'' +
				'' + r.toString(10) + u + '' +
				program.title.truncate(16) +
				'' + program.channel.name.truncate(7) + '' +
				''
			);
		});

		reservesList.scrollTop = posTop;
	}
	viewReserves();
	document.observe('chinachu:reserves', viewReserves);
	var viewReservesInterval = setInterval(viewReserves, 10000);

	loading.update(40);

	// 録画済リスト
	function viewRecorded() {
		if ($('overview-recorded')) {
			var li = $('overview-recorded');
		} else {
			var li = new Element('li', {id: 'overview-recorded'});
			ul.insert(li);
		}

		var posTop = 0;
		$$('#overview-recorded > div.list').each(function(a) {
			posTop = a.cumulativeScrollOffset().top;
		});

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			app.chinachu.recorded.length.toString(10) + '件の録画» 録画済リスト'
		));

		var recordedList = new Element('div', {className: 'list'});
		li.insert(recordedList);

		var dt = new Date().getTime();
		app.chinachu.recorded.each(function(program, i) {
			var r = Math.round((dt - program.end) / 1000);
			var u = '秒前';
			var c = 'color-red';

			if (r >= 60) {
				r = r / 60;
				u = '分前';
				c = 'color-orange';

				if (r >= 60) {
					r = r / 60;
					u = '時間前';
					c = 'color-green';

					if (r >= 24) {
						r = r / 24;
						u = '日前';
						c = '';
					}
				}
			}

			r = Math.round(r * 10) / 10;

			recordedList.insert(
				'' +
				'' + r.toString(10) + u + '' +
				program.title.truncate(16) +
				'' + program.channel.name.truncate(7) + '' +
				''
			);
		});

		recordedList.scrollTop = posTop;
	}
	viewRecorded();
	document.observe('chinachu:recorded', viewRecorded);
	var viewRecordedInterval = setInterval(viewRecorded, 10000);

	loading.update(60);

	// スケジューラー実行結果
	function viewScheduler() {
		if ($('overview-scheduler')) {
			var li = $('overview-scheduler');
		} else {
			var li = new Element('li', {id: 'overview-scheduler'});
			ul.insert(li);
		}

		li.update();

		li.insert(new Element('div', {className: 'head'}).insert(
			'スケジューラー実行結果» ルールリスト'
		));

		var list = new Element('div', {className: 'list'});
		li.insert(list);

		new Ajax.Request('./api/scheduler.json', {
			method    : 'get',
			onComplete: function() {
				if (loading) { loading.update(100); }
			},
			onSuccess: function(t) {
				var d = t.responseJSON;

				list.insert('
' + dateFormat(new Date(d.time), 'yyyy/mm/dd HH:MM:ss') + ' 更新 (' + d.reserves.length.toString(10) + '件を予約)
');
				list.insert('
' + d.conflicts.length.toString(10) + '件の衝突
');

				var dt = new Date().getTime();
				d.conflicts.each(function(program, i) {
					list.insert(
						'' +
						'' + dateFormat(new Date(program.start), 'd日 HH:MM') + '' +
						'' + program.title.truncate(16) + '' +
						'' + program.channel.name.truncate(7) + '' +
						''
					);
				});
			}
		});
	}
	viewScheduler();
	document.observe('chinachu:reserves', viewScheduler);

	loading.update(80);

})();<|endoftext|>


<commit_before>"use strict";
var GamePlay;

/**
 * The GamePlay class provides the runtime environment for the plugins that
 * provide services, API and handle actions in a way that the user can play the
 * game. The GamePlay class handles event delivery for event-driven plugins and
 * running the scheduled plugins in regular time periods call "ticks".
 *
 * The GamePlay object is initialized by an GameLoader class instance. You
 * shouldn't create instances of this class unless you really know what you are
 * doing.
 *
 * @param {Array} plugins Array of plugins instances. Plugins usually extend
 *        the ScheduledPlugin class, the EventDrivenPlugin class or the
 *        MixedPlugin class (for plugins that are both scheduled and
 *        event-driven).
 *
The schedules plugins are plugins that should be executed in
 *        regular periods called as "ticks". The duration of a tick is
 *        specified in the settings. The scheduled plugins can produce events,
 *        but they cannot receive them.

 *
The event-driven plugins that are executed whenever they receive
 *        an event. These plugins can also produce events. A typical use of
 *        these plugins are plugins handling user's interaction with the UI or
 *        plugins computing statistics of the current situation on the
 *        battlefield.

 * @param {Settings} settings Settings object. The class usually uses the
 *        global instance, but it is possible to pass a custom settings object
 *        for debugging and/or testing purposes.
 */
GamePlay = function (plugins, settings) {
    var thread, threadInterval, scheduledPlugins, lastTick, tickOverflow,
            eventDeliveryPlugin, eventDrivenPlugins, eventQueue,
            singleTickScheduledPlugins;

    // --------------------- background thread logic --------------------------

    thread = function () {
        var i, j, now, tickCount;
        now = (new Date()).getTime();
        tickCount = (now - lastTick) / settings.tickDuration + tickOverflow;
        tickOverflow = tickCount - Math.floor(tickCount);
        tickCount = Math.floor(tickCount);
        lastTick = now;
        for (i = Math.min(tickCount, settings.maxTicks); i--;) {
            for (j = scheduledPlugins.length; j--;) {
                scheduledPlugins[j].handleTick();
            }
        }
        for (i = singleTickScheduledPlugins.length; i--;) {
            singleTickScheduledPlugins[i].handleTick();
        }
    };

    // --------------------- event delivery plugin ----------------------------

    (function () {
        var PluginConstructor;

        /**
         * Constructor for the event delivery plugin.
         */
        PluginConstructor = function () {
            this.handleTick = function () {
                var currentEvents, i, eventListeningPlugins, j, currentEvent;
                // We create a new queue for events registered during the
                // delivery of the events in the current queue. This prevents
                // us from getting stuck in a possibly infinite loop.
                currentEvents = eventQueue;
                eventQueue = [];

                // deliver the events
                for (i = currentEvents.length; i--;) {
                    currentEvent = currentEvents[i];
                    eventListeningPlugins =
                            eventDrivenPlugins[currentEvent.name];
                    if (eventListeningPlugins) {
                        for (j = eventListeningPlugins.length; j--;) {
                            eventListeningPlugins[j].handleEvent(
                                currentEvent.name,
                                currentEvent.data
                            );
                        }
                    }
                }
            };
        };
        PluginConstructor.prototype = new ScheduledPlugin();

        eventDeliveryPlugin = new PluginConstructor();
    }())

    // -------------------------- public API ----------------------------------

    /**
     * Sends an event to plugins listening for events of the specified name.
     *
     * @param {String} eventName Name of the event to send.
     * @param {Object} eventData Any data to send with the event. Can be of any
     *        type.
     */
    this.sendEvent = function (eventName, eventData) {
        eventQueue.push({
            name: eventName,
            data: eventData
        });
    };

    /**
     * Starts the GamePlay daemon, its background thread, scheduled plugins and
     * event delivery. All event-driven plugins will receive the "start" event
     * with null as event data.
     */
    this.start = function () {
        if (threadInterval) {
            throw new Error('GamePlay daemon is already running');
        }
        lastTick = (new Date()).getTime();
        tickOverflow = 0;
        threadInterval = setInterval(thread, settings.tickDuration);
        this.sendEvent("start", null);
        eventDeliveryPlugin.handleTick(); // deliver the event right now
        this.sendEvent("running", null);
    };

    /**
     * Stops the GamePlay daemon, stopping the background thread, scheduled
     * plugins and event delivery. All event-driven plugins receive the "stop"
     * event with null as event data right before the event
     * delivery is terminated.
     */
    this.stop = function () {
        if (!threadInterval) {
            throw new Error('GamePlay daemon is not running');
        }
        clearInterval(threadInterval);
        this.sendEvent("stop", null);
        eventDeliveryPlugin.handleTick(); // deliver the event right now
        threadInterval = null;
    };

    // -------------------------- constructor ---------------------------------

    (function () {
        var i, plugin, registerEventDrivenPlugin;
        eventQueue = [];
        scheduledPlugins = [];
        singleTickScheduledPlugins = [];
        eventDrivenPlugins = {};

        /**
         * Retrieves the list of observed events from the plugin and registers
         * the plugin as a listener of all the event specified by the plugin.
         *
         * @param {EventDrivenPlugin|MixedPlugin} plugin The plugin to
         *        register as event listener.
         */
        registerEventDrivenPlugin = function (plugin) {
            var observedEvents, i, eventName;
            observedEvents = plugin.getObservedEvents();
            for (i = observedEvents.length; i--;) {
                eventName = observedEvents[i];
                if (!eventDrivenPlugins[eventName]) {
                    eventDrivenPlugins[eventName] = [];
                }
                eventDrivenPlugins[eventName].push(plugin);
            }
        };

        for (i = plugins.length; i--;) {
            plugin = plugins[i];
            plugin.setGamePlay(this);
            if (plugin instanceof ScheduledPlugin) {
                if (plugin.ignoresExtraTicks()) {
                    singleTickScheduledPlugins.push(plugin);
                } else {
                    scheduledPlugins.push(plugin);
                }
                if (plugin instanceof MixedPlugin) {
                    registerEventDrivenPlugin(plugin);
                }
            } else if (plugin instanceof EventDrivenPlugin) {
                registerEventDrivenPlugin(plugin);
            } else {
                throw new Error('The provided object ' + plugin +
                        ' is not a valid plugin');
            }
        }

        scheduledPlugins.push(eventDeliveryPlugin);
    }.call(this));
};
<commit_msg>fixed the order in which the gameplay events are delivered<commit_after>"use strict";
var GamePlay;

/**
 * The GamePlay class provides the runtime environment for the plugins that
 * provide services, API and handle actions in a way that the user can play the
 * game. The GamePlay class handles event delivery for event-driven plugins and
 * running the scheduled plugins in regular time periods call "ticks".
 *
 * The GamePlay object is initialized by an GameLoader class instance. You
 * shouldn't create instances of this class unless you really know what you are
 * doing.
 *
 * @param {Array} plugins Array of plugins instances. Plugins usually extend
 *        the ScheduledPlugin class, the EventDrivenPlugin class or the
 *        MixedPlugin class (for plugins that are both scheduled and
 *        event-driven).
 *
The schedules plugins are plugins that should be executed in
 *        regular periods called as "ticks". The duration of a tick is
 *        specified in the settings. The scheduled plugins can produce events,
 *        but they cannot receive them.

 *
The event-driven plugins that are executed whenever they receive
 *        an event. These plugins can also produce events. A typical use of
 *        these plugins are plugins handling user's interaction with the UI or
 *        plugins computing statistics of the current situation on the
 *        battlefield.

 * @param {Settings} settings Settings object. The class usually uses the
 *        global instance, but it is possible to pass a custom settings object
 *        for debugging and/or testing purposes.
 */
GamePlay = function (plugins, settings) {
    var thread, threadInterval, scheduledPlugins, lastTick, tickOverflow,
            eventDeliveryPlugin, eventDrivenPlugins, eventQueue,
            singleTickScheduledPlugins;

    // --------------------- background thread logic --------------------------

    thread = function () {
        var i, j, now, tickCount;
        now = (new Date()).getTime();
        tickCount = (now - lastTick) / settings.tickDuration + tickOverflow;
        tickOverflow = tickCount - Math.floor(tickCount);
        tickCount = Math.floor(tickCount);
        lastTick = now;
        for (i = Math.min(tickCount, settings.maxTicks); i--;) {
            for (j = scheduledPlugins.length; j--;) {
                scheduledPlugins[j].handleTick();
            }
        }
        for (i = singleTickScheduledPlugins.length; i--;) {
            singleTickScheduledPlugins[i].handleTick();
        }
    };

    // --------------------- event delivery plugin ----------------------------

    (function () {
        var PluginConstructor;

        /**
         * Constructor for the event delivery plugin.
         */
        PluginConstructor = function () {
            this.handleTick = function () {
                var currentEvents, i, eventListeningPlugins, j, currentEvent,
                        eventCount;
                // We create a new queue for events registered during the
                // delivery of the events in the current queue. This prevents
                // us from getting stuck in a possibly infinite loop.
                currentEvents = eventQueue;
                eventQueue = [];

                // deliver the events
                eventCount = currentEvents.length;
                for (i = 0; i < eventCount; i++) {
                    currentEvent = currentEvents[i];
                    eventListeningPlugins =
                            eventDrivenPlugins[currentEvent.name];
                    if (eventListeningPlugins) {
                        for (j = eventListeningPlugins.length; j--;) {
                            eventListeningPlugins[j].handleEvent(
                                currentEvent.name,
                                currentEvent.data
                            );
                        }
                    }
                }
            };
        };
        PluginConstructor.prototype = new ScheduledPlugin();

        eventDeliveryPlugin = new PluginConstructor();
    }());

    // -------------------------- public API ----------------------------------

    /**
     * Sends an event to plugins listening for events of the specified name.
     *
     * @param {String} eventName Name of the event to send.
     * @param {Object} eventData Any data to send with the event. Can be of any
     *        type.
     */
    this.sendEvent = function (eventName, eventData) {
        eventQueue.push({
            name: eventName,
            data: eventData
        });
    };

    /**
     * Starts the GamePlay daemon, its background thread, scheduled plugins and
     * event delivery. All event-driven plugins will receive the "start" event
     * with null as event data.
     */
    this.start = function () {
        if (threadInterval) {
            throw new Error('GamePlay daemon is already running');
        }
        lastTick = (new Date()).getTime();
        tickOverflow = 0;
        threadInterval = setInterval(thread, settings.tickDuration);
        this.sendEvent("start", null);
        eventDeliveryPlugin.handleTick(); // deliver the event right now
        this.sendEvent("running", null);
    };

    /**
     * Stops the GamePlay daemon, stopping the background thread, scheduled
     * plugins and event delivery. All event-driven plugins receive the "stop"
     * event with null as event data right before the event
     * delivery is terminated.
     */
    this.stop = function () {
        if (!threadInterval) {
            throw new Error('GamePlay daemon is not running');
        }
        clearInterval(threadInterval);
        this.sendEvent("stop", null);
        eventDeliveryPlugin.handleTick(); // deliver the event right now
        threadInterval = null;
    };

    // -------------------------- constructor ---------------------------------

    (function () {
        var i, plugin, registerEventDrivenPlugin;
        eventQueue = [];
        scheduledPlugins = [];
        singleTickScheduledPlugins = [];
        eventDrivenPlugins = {};

        /**
         * Retrieves the list of observed events from the plugin and registers
         * the plugin as a listener of all the event specified by the plugin.
         *
         * @param {EventDrivenPlugin|MixedPlugin} plugin The plugin to
         *        register as event listener.
         */
        registerEventDrivenPlugin = function (plugin) {
            var observedEvents, i, eventName;
            observedEvents = plugin.getObservedEvents();
            for (i = observedEvents.length; i--;) {
                eventName = observedEvents[i];
                if (!eventDrivenPlugins[eventName]) {
                    eventDrivenPlugins[eventName] = [];
                }
                eventDrivenPlugins[eventName].push(plugin);
            }
        };

        for (i = plugins.length; i--;) {
            plugin = plugins[i];
            plugin.setGamePlay(this);
            if (plugin instanceof ScheduledPlugin) {
                if (plugin.ignoresExtraTicks()) {
                    singleTickScheduledPlugins.push(plugin);
                } else {
                    scheduledPlugins.push(plugin);
                }
                if (plugin instanceof MixedPlugin) {
                    registerEventDrivenPlugin(plugin);
                }
            } else if (plugin instanceof EventDrivenPlugin) {
                registerEventDrivenPlugin(plugin);
            } else {
                throw new Error('The provided object ' + plugin +
                        ' is not a valid plugin');
            }
        }

        scheduledPlugins.push(eventDeliveryPlugin);
    }.call(this));
};
<|endoftext|>


<commit_before>'use strict';

// See documentation here: http://www.microsoft.com/typography/otspec/name.htm

var _ = require('lodash');
var jDataView = require('jDataView');
var Str = require('../../str');

var TTF_NAMES = {
  COPYRIGHT: 0,
  FONT_FAMILY: 1,
  ID: 3,
  DESCRIPTION: 10,
  URL_VENDOR: 11
};

function tableSize(names) {
  var result = 6; // table header
  _.forEach(names, function (name) {
    result += 12 + name.data.length; //name header and data
  });
  return result;
}

function getStrings(name, id) {
  var result = [];
  var str = new Str(name);
  result.push({ data: str.toUTF8Bytes(), id: id, platformID : 1, encodingID : 0, languageID : 0 } ); //mac standard
  result.push({ data: str.toUCS2Bytes(), id: id, platformID : 3, encodingID : 1, languageID : 0x409 } ); //windows standard
  return result;
}

// Collect font names
function getNames(font) {
  var result = [];
  if (font.copyright) {
    result.push.apply(result, getStrings(font.copyright, TTF_NAMES.COPYRIGHT));
  }
  if (font.familyName) {
    result.push.apply(result, getStrings(font.familyName, TTF_NAMES.FONT_FAMILY));
  }
  if (font.id) {
    result.push.apply(result, getStrings(font.id, TTF_NAMES.ID));
  }
  result.push.apply(result, getStrings('васяGenerated by svg2ttf from Fontello project.', TTF_NAMES.DESCRIPTION));
  result.push.apply(result, getStrings('http://fontello.com', TTF_NAMES.URL_VENDOR));

  _.forEach(font.sfntNames, function (sfntName) {
    result.push.apply(result, getStrings(sfntName.value, sfntName.id));
  });

  result.sort(function (a, b) {
    var orderFields = ['platformID', 'encodingID', 'language', 'id'];
    var i;
    for (i = 0; i < orderFields.length; i++) {
      if (a[orderFields[i]] !== b[orderFields[i]]) {
        return a[orderFields[i]] < b[orderFields[i]] ? -1 : 1;
      }
    }
    return 0;
  });

  return result;
}

function createNameTable(font) {

  var names = getNames(font);

  var buf = new jDataView(tableSize(names));

  buf.writeUint16(0); // formatSelector
  buf.writeUint16(names.length); // nameRecordsCount
  var offsetPosition = buf.tell();
  buf.writeUint16(0); // offset, will be filled later
  var nameOffset = 0;
  _.forEach(names, function (name) {
    buf.writeUint16(name.platformID); // platformID
    buf.writeUint16(name.encodingID); // platEncID
    buf.writeUint16(name.languageID); // languageID, English (USA)
    buf.writeUint16(name.id); // nameID
    buf.writeUint16(name.data.length); // reclength
    buf.writeUint16(nameOffset); // offset
    nameOffset += name.data.length;
  });
  var actualStringDataOffset = buf.tell();
  //Array of bytes with actual string data
  _.forEach(names, function (name) {
    buf.writeBytes(name.data);
  });

  //write actual string data offset
  buf.seek(offsetPosition);
  buf.writeUint16(actualStringDataOffset); // offset

  return buf;
}

module.exports = createNameTable;
<commit_msg>Fixed wrong description in NAME ttf table.<commit_after>'use strict';

// See documentation here: http://www.microsoft.com/typography/otspec/name.htm

var _ = require('lodash');
var jDataView = require('jDataView');
var Str = require('../../str');

var TTF_NAMES = {
  COPYRIGHT: 0,
  FONT_FAMILY: 1,
  ID: 3,
  DESCRIPTION: 10,
  URL_VENDOR: 11
};

function tableSize(names) {
  var result = 6; // table header
  _.forEach(names, function (name) {
    result += 12 + name.data.length; //name header and data
  });
  return result;
}

function getStrings(name, id) {
  var result = [];
  var str = new Str(name);
  result.push({ data: str.toUTF8Bytes(), id: id, platformID : 1, encodingID : 0, languageID : 0 } ); //mac standard
  result.push({ data: str.toUCS2Bytes(), id: id, platformID : 3, encodingID : 1, languageID : 0x409 } ); //windows standard
  return result;
}

// Collect font names
function getNames(font) {
  var result = [];
  if (font.copyright) {
    result.push.apply(result, getStrings(font.copyright, TTF_NAMES.COPYRIGHT));
  }
  if (font.familyName) {
    result.push.apply(result, getStrings(font.familyName, TTF_NAMES.FONT_FAMILY));
  }
  if (font.id) {
    result.push.apply(result, getStrings(font.id, TTF_NAMES.ID));
  }
  result.push.apply(result, getStrings('Generated by svg2ttf from Fontello project.', TTF_NAMES.DESCRIPTION));
  result.push.apply(result, getStrings('http://fontello.com', TTF_NAMES.URL_VENDOR));

  _.forEach(font.sfntNames, function (sfntName) {
    result.push.apply(result, getStrings(sfntName.value, sfntName.id));
  });

  result.sort(function (a, b) {
    var orderFields = ['platformID', 'encodingID', 'language', 'id'];
    var i;
    for (i = 0; i < orderFields.length; i++) {
      if (a[orderFields[i]] !== b[orderFields[i]]) {
        return a[orderFields[i]] < b[orderFields[i]] ? -1 : 1;
      }
    }
    return 0;
  });

  return result;
}

function createNameTable(font) {

  var names = getNames(font);

  var buf = new jDataView(tableSize(names));

  buf.writeUint16(0); // formatSelector
  buf.writeUint16(names.length); // nameRecordsCount
  var offsetPosition = buf.tell();
  buf.writeUint16(0); // offset, will be filled later
  var nameOffset = 0;
  _.forEach(names, function (name) {
    buf.writeUint16(name.platformID); // platformID
    buf.writeUint16(name.encodingID); // platEncID
    buf.writeUint16(name.languageID); // languageID, English (USA)
    buf.writeUint16(name.id); // nameID
    buf.writeUint16(name.data.length); // reclength
    buf.writeUint16(nameOffset); // offset
    nameOffset += name.data.length;
  });
  var actualStringDataOffset = buf.tell();
  //Array of bytes with actual string data
  _.forEach(names, function (name) {
    buf.writeBytes(name.data);
  });

  //write actual string data offset
  buf.seek(offsetPosition);
  buf.writeUint16(actualStringDataOffset); // offset

  return buf;
}

module.exports = createNameTable;
<|endoftext|>


<commit_before>/*global namespace*/
(function () {
    var shim = namespace.shim;
    var bind = shim.bind;
    var forEach = shim.forEach;
    var filter = shim.filter;
    var map = shim.map;
    var trim = shim.trim;
    var reduce = shim.reduce;
    var getKeys = shim.getKeys;

    var utils = namespace.utils;
    var truncateStack = utils.truncateStack;
    var extend = utils.extend;
    var levenshteinDistance = utils.levenshteinDistance;
    var isArray = utils.isArray;

    function Assertion(expect, subject, testDescription, flags, args) {
        this.expect = expect;
        this.obj = subject; // deprecated
        this.equal = bind(expect.equal, expect); // deprecated
        this.eql = this.equal; // deprecated
        this.inspect = bind(expect.inspect, expect); // deprecated
        this.subject = subject;
        this.testDescription = testDescription;
        this.flags = flags;
        this.args = args;
        this.errorMode = 'default';
    }

    Assertion.prototype.standardErrorMessage = function () {
        var expect = this.expect;
        var argsString = map(this.args, function (arg) {
            return expect.inspect(arg);
        }).join(', ');

        if (argsString.length > 0) {
            argsString = ' ' + argsString;
        }

        return 'expected ' +
            expect.inspect(this.subject) +
            ' ' + this.testDescription +
            argsString;
    };

    Assertion.prototype.throwStandardError = function () {
        var err = new Error(this.standardErrorMessage());
        err._isUnexpected = true;
        throw err;
    };

    Assertion.prototype.assert = function (condition) {
        var not = !!this.flags.not;
        condition = !!condition;
        if (condition === not) {
            this.throwStandardError();
        }
    };

    function Unexpected(assertions, types) {
        this.assertions = assertions || {};
        this.types = types || [];
    }

    Unexpected.prototype.equal = function (actual, expected) {
        return namespace.equal(actual, expected, this.types);
    };

    Unexpected.prototype.inspect = function (obj) {
        return namespace.inspect(obj, false, 2, this.types);
    };

    Unexpected.prototype.format = function (message, args) {
        args = map(args, function (arg) {
            return this.inspect(arg);
        }, this);
        message = message.replace(/\{(\d+)\}/g, function (match, n) {
            return args[n] || match;
        });
        return message;
    };

    Unexpected.prototype.fail = function (message) {
        message = message || "explicit failure";
        var args = Array.prototype.slice.call(arguments, 1);
        throw new Error(this.format(message, args));
    };

    Unexpected.prototype.findAssertionSimilarTo = function (text) {
        var editDistrances = [];
        forEach(getKeys(this.assertions), function (assertion) {
            var distance = levenshteinDistance(text, assertion);
            editDistrances.push({
                assertion: assertion,
                distance: distance
            });
        });
        editDistrances.sort(function (x, y) {
            return x.distance - y.distance;
        });
        return map(editDistrances.slice(0, 5), function (editDistrance) {
            return editDistrance.assertion;
        });
    };

    Unexpected.prototype.addAssertion = function () {
        var assertions = this.assertions;
        var patterns = Array.prototype.slice.call(arguments, 0, -1);
        var handler = Array.prototype.slice.call(arguments, -1)[0];
        forEach(patterns, function (pattern) {
            ensureValidPattern(pattern);
            forEach(expandPattern(pattern), function (expandedPattern) {
                assertions[expandedPattern.text] = {
                    handler: handler,
                    flags: expandedPattern.flags
                };
            });
        });

        return this.expect; // for chaining
    };

    Unexpected.prototype.addType = function (obj) {
        this.types.unshift(obj);

        return this.expect;
    };

    Unexpected.prototype.installPlugin = function (plugin) {
        if (typeof plugin !== 'function') {
            throw new Error('Expected first argument given to installPlugin to be a function');
        }

        plugin(this.expect);

        return this.expect; // for chaining
    };

    Unexpected.prototype.sanitize = function (obj, stack) {
        stack = stack || [];

        var i;
        for (i = 0 ; i < stack.length ; i += 1) {
            if (stack[i] === obj) {
                return obj;
            }
        }

        var sanitized;
        for (i = 0 ; i < this.types.length ; i += 1) {
            if (this.types[i].identify(obj)) {
                stack.push(obj);
                sanitized = this.sanitize(this.types[i].toJSON(obj), stack);
                stack.pop();
                return sanitized;
            }
        }
        if (isArray(obj)) {
            stack.push(obj);
            sanitized = map(obj, function (item) {
                return this.sanitize(item, stack);
            }, this);
            stack.pop();
        } else if (typeof obj === 'object' && obj) {
            stack.push(obj);
            sanitized = {};
            forEach(getKeys(obj).sort(), function (key) {
                sanitized[key] = this.sanitize(obj[key], stack);
            }, this);
            stack.pop();
        } else {
            sanitized = obj;
        }
        return sanitized;
    };

    function handleNestedExpects(e, assertion) {
        switch (assertion.errorMode) {
        case 'nested':
            e.message = assertion.standardErrorMessage() + '\n    ' + e.message.replace(/\n/g, '\n    ');
            break;
        case 'default':
            e.message = assertion.standardErrorMessage();
            break;
        case 'bubble':
            break;
        default:
            throw new Error("Unknown error mode: '" + assertion.errorMode + "'");
        }
    }

    function installExpectMethods(unexpected, expectFunction) {
        var expect = bind(expectFunction, unexpected);
        expect.equal = bind(unexpected.equal, unexpected);
        expect.sanitize = bind(unexpected.sanitize, unexpected);
        expect.inspect = bind(unexpected.inspect, unexpected);
        expect.fail = bind(unexpected.fail, unexpected);
        expect.addAssertion = bind(unexpected.addAssertion, unexpected);
        expect.addType = bind(unexpected.addType, unexpected);
        expect.clone = bind(unexpected.clone, unexpected);
        expect.toString = bind(unexpected.toString, unexpected);
        expect.assertions = unexpected.assertions;
        expect.installPlugin = bind(unexpected.installPlugin, unexpected);
        return expect;
    }

    function makeExpectFunction(unexpected) {
        var expect = installExpectMethods(unexpected, unexpected.expect);
        unexpected.expect = expect;
        return expect;
    }

    Unexpected.prototype.expect = function expect(subject, testDescriptionString) {
        var that = this;
        if (arguments.length < 2) {
            throw new Error('The expect functions requires at least two parameters.');
        }
        if (typeof testDescriptionString !== 'string') {
            throw new Error('The expect functions requires second parameter to be a string.');
        }
        var assertionRule = this.assertions[testDescriptionString];
        if (assertionRule) {
            var flags = extend({}, assertionRule.flags);
            var nestingLevel = 0;
            var wrappedExpect = function wrappedExpect(subject, testDescriptionString) {
                testDescriptionString = trim(testDescriptionString.replace(/\[(!?)([^\]]+)\] ?/g, function (match, negate, flag) {
                    negate = !!negate;
                    return flags[flag] !== negate ? flag + ' ' : '';
                }));

                var args = Array.prototype.slice.call(arguments, 2);
                nestingLevel += 1;
                try {
                    that.expect.apply(that, [subject, testDescriptionString].concat(args));
                    nestingLevel -= 1;
                } catch (e) {
                    nestingLevel -= 1;
                    if (e._isUnexpected) {
                        truncateStack(e, wrappedExpect);
                    }
                    if (nestingLevel === 0) {
                        handleNestedExpects(e, assertion);
                    }
                    throw e;
                }
            };

            // Not sure this is the right way to go about this:
            wrappedExpect.equal = this.equal;
            wrappedExpect.types = this.types;
            wrappedExpect.sanitize = this.sanitize;
            wrappedExpect.inspect = this.inspect;

            var args = Array.prototype.slice.call(arguments, 2);
            args.unshift(wrappedExpect, subject);
            var assertion = new Assertion(wrappedExpect, subject, testDescriptionString, flags, args.slice(2));
            var handler = assertionRule.handler;
            try {
                handler.apply(assertion, args);
            } catch (e) {
                if (e._isUnexpected) {
                    truncateStack(e, this.expect);
                }
                throw e;
            }
        } else {
            var similarAssertions = this.findAssertionSimilarTo(testDescriptionString);
            var message =
                'Unknown assertion "' + testDescriptionString + '", ' +
                'did you mean: "' + similarAssertions[0] + '"';
            var err = new Error(message);
            truncateStack(err, this.expect);
            throw err;
        }
    };

    Unexpected.prototype.toString = function () {
        return getKeys(this.assertions).sort().join('\n');
    };

    Unexpected.prototype.clone = function () {
        var unexpected = new Unexpected(extend({}, this.assertions), [].concat(this.types));
        return makeExpectFunction(unexpected);
    };

    Unexpected.create = function () {
        var unexpected = new Unexpected();
        return makeExpectFunction(unexpected);
    };

    var expandPattern = (function () {
        function isFlag(token) {
            return token.slice(0, 1) === '[' && token.slice(-1) === ']';
        }
        function isAlternation(token) {
            return token.slice(0, 1) === '(' && token.slice(-1) === ')';
        }
        function removeEmptyStrings(texts) {
            return filter(texts, function (text) {
                return text !== '';
            });
        }
        function createPermutations(tokens, index) {
            if (index === tokens.length) {
                return [{ text: '', flags: {}}];
            }

            var token = tokens[index];
            var tail = createPermutations(tokens, index + 1);
            if (isFlag(token)) {
                var flag = token.slice(1, -1);
                return map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = true;
                    return {
                        text: flag + ' ' + pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }).concat(map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = false;
                    return {
                        text: pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }));
            } else if (isAlternation(token)) {
                var alternations = token.split(/\(|\)|\|/);
                alternations = removeEmptyStrings(alternations);
                return reduce(alternations, function (result, alternation) {
                    return result.concat(map(tail, function (pattern) {
                        return {
                            text: alternation + pattern.text,
                            flags: pattern.flags
                        };
                    }));
                }, []);
            } else {
                return map(tail, function (pattern) {
                    return {
                        text: token + pattern.text,
                        flags: pattern.flags
                    };
                });
            }
        }
        return function (pattern) {
            pattern = pattern.replace(/(\[[^\]]+\]) ?/g, '$1');
            var splitRegex = /\[[^\]]+\]|\([^\)]+\)/g;
            var tokens = [];
            var m;
            var lastIndex = 0;
            while ((m = splitRegex.exec(pattern))) {
                tokens.push(pattern.slice(lastIndex, m.index));
                tokens.push(pattern.slice(m.index, splitRegex.lastIndex));
                lastIndex = splitRegex.lastIndex;
            }
            tokens.push(pattern.slice(lastIndex));

            tokens = removeEmptyStrings(tokens);
            var permutations = createPermutations(tokens, 0);
            forEach(permutations, function (permutation) {
                permutation.text = trim(permutation.text);
                if (permutation.text === '') {
                    // This can only happen if the pattern only contains flags
                    throw new Error("Assertion patterns must not only contain flags");
                }
            });
            return permutations;
        };
    }());

    function ensureValidUseOfParenthesesOrBrackets(pattern) {
        var counts = {
            '[': 0,
            ']': 0,
            '(': 0,
            ')': 0
        };
        for (var i = 0; i < pattern.length; i += 1) {
            var c = pattern.charAt(i);
            if (c in counts) {
                counts[c] += 1;
            }
            if (c === ']' && counts['['] >= counts[']']) {
                if (counts['['] === counts[']'] + 1) {
                    throw new Error("Assertion patterns must not contain flags with brackets: '" + pattern + "'");
                }

                if (counts['('] !== counts[')']) {
                    throw new Error("Assertion patterns must not contain flags with parentheses: '" + pattern + "'");
                }

                if (pattern.charAt(i - 1) === '[') {
                    throw new Error("Assertion patterns must not contain empty flags: '" + pattern + "'");
                }
            } else if (c === ')' && counts['('] >= counts[')']) {
                if (counts['('] === counts[')'] + 1) {
                    throw new Error("Assertion patterns must not contain alternations with parentheses: '" + pattern + "'");
                }

                if (counts['['] !== counts[']']) {
                    throw new Error("Assertion patterns must not contain alternations with brackets: '" + pattern + "'");
                }
            }

            if ((c === ')' || c === '|') && counts['('] >= counts[')']) {
                if (pattern.charAt(i - 1) === '(' || pattern.charAt(i - 1) === '|') {
                    throw new Error("Assertion patterns must not contain empty alternations: '" + pattern + "'");
                }
            }
        }

        if (counts['['] !== counts[']']) {
            throw new Error("Assertion patterns must not contain unbalanced brackets: '" + pattern + "'");
        }

        if (counts['('] !== counts[')']) {
            throw new Error("Assertion patterns must not contain unbalanced parentheses: '" + pattern + "'");
        }
    }

    function ensureValidPattern(pattern) {
        if (typeof pattern !== 'string' || pattern === '') {
            throw new Error("Assertion patterns must be a non empty string");
        }
        if (pattern.match(/^\s|\s$/)) {
            throw new Error("Assertion patterns can't start or end with whitespace");
        }

        ensureValidUseOfParenthesesOrBrackets(pattern);
    }

    namespace.expect = Unexpected.create();
}());
<commit_msg>Use findFirst in sanitize.<commit_after>/*global namespace*/
(function () {
    var shim = namespace.shim;
    var bind = shim.bind;
    var forEach = shim.forEach;
    var filter = shim.filter;
    var map = shim.map;
    var trim = shim.trim;
    var reduce = shim.reduce;
    var getKeys = shim.getKeys;

    var utils = namespace.utils;
    var truncateStack = utils.truncateStack;
    var extend = utils.extend;
    var levenshteinDistance = utils.levenshteinDistance;
    var isArray = utils.isArray;

    function Assertion(expect, subject, testDescription, flags, args) {
        this.expect = expect;
        this.obj = subject; // deprecated
        this.equal = bind(expect.equal, expect); // deprecated
        this.eql = this.equal; // deprecated
        this.inspect = bind(expect.inspect, expect); // deprecated
        this.subject = subject;
        this.testDescription = testDescription;
        this.flags = flags;
        this.args = args;
        this.errorMode = 'default';
    }

    Assertion.prototype.standardErrorMessage = function () {
        var expect = this.expect;
        var argsString = map(this.args, function (arg) {
            return expect.inspect(arg);
        }).join(', ');

        if (argsString.length > 0) {
            argsString = ' ' + argsString;
        }

        return 'expected ' +
            expect.inspect(this.subject) +
            ' ' + this.testDescription +
            argsString;
    };

    Assertion.prototype.throwStandardError = function () {
        var err = new Error(this.standardErrorMessage());
        err._isUnexpected = true;
        throw err;
    };

    Assertion.prototype.assert = function (condition) {
        var not = !!this.flags.not;
        condition = !!condition;
        if (condition === not) {
            this.throwStandardError();
        }
    };

    function Unexpected(assertions, types) {
        this.assertions = assertions || {};
        this.types = types || [];
    }

    Unexpected.prototype.equal = function (actual, expected) {
        return namespace.equal(actual, expected, this.types);
    };

    Unexpected.prototype.inspect = function (obj) {
        return namespace.inspect(obj, false, 2, this.types);
    };

    Unexpected.prototype.format = function (message, args) {
        args = map(args, function (arg) {
            return this.inspect(arg);
        }, this);
        message = message.replace(/\{(\d+)\}/g, function (match, n) {
            return args[n] || match;
        });
        return message;
    };

    Unexpected.prototype.fail = function (message) {
        message = message || "explicit failure";
        var args = Array.prototype.slice.call(arguments, 1);
        throw new Error(this.format(message, args));
    };

    Unexpected.prototype.findAssertionSimilarTo = function (text) {
        var editDistrances = [];
        forEach(getKeys(this.assertions), function (assertion) {
            var distance = levenshteinDistance(text, assertion);
            editDistrances.push({
                assertion: assertion,
                distance: distance
            });
        });
        editDistrances.sort(function (x, y) {
            return x.distance - y.distance;
        });
        return map(editDistrances.slice(0, 5), function (editDistrance) {
            return editDistrance.assertion;
        });
    };

    Unexpected.prototype.addAssertion = function () {
        var assertions = this.assertions;
        var patterns = Array.prototype.slice.call(arguments, 0, -1);
        var handler = Array.prototype.slice.call(arguments, -1)[0];
        forEach(patterns, function (pattern) {
            ensureValidPattern(pattern);
            forEach(expandPattern(pattern), function (expandedPattern) {
                assertions[expandedPattern.text] = {
                    handler: handler,
                    flags: expandedPattern.flags
                };
            });
        });

        return this.expect; // for chaining
    };

    Unexpected.prototype.addType = function (obj) {
        this.types.unshift(obj);

        return this.expect;
    };

    Unexpected.prototype.installPlugin = function (plugin) {
        if (typeof plugin !== 'function') {
            throw new Error('Expected first argument given to installPlugin to be a function');
        }

        plugin(this.expect);

        return this.expect; // for chaining
    };

    Unexpected.prototype.sanitize = function (obj, stack) {
        stack = stack || [];

        var i;
        for (i = 0 ; i < stack.length ; i += 1) {
            if (stack[i] === obj) {
                return obj;
            }
        }

        var sanitized,
            matchingCustomType = utils.findFirst(this.types || [], function (type) {
                return type.identify(obj);
            });
        if (matchingCustomType) {
            stack.push(obj);
            sanitized = this.sanitize(matchingCustomType.toJSON(obj), stack);
            stack.pop();
            return sanitized;
        }
        if (isArray(obj)) {
            stack.push(obj);
            sanitized = map(obj, function (item) {
                return this.sanitize(item, stack);
            }, this);
            stack.pop();
        } else if (typeof obj === 'object' && obj) {
            stack.push(obj);
            sanitized = {};
            forEach(getKeys(obj).sort(), function (key) {
                sanitized[key] = this.sanitize(obj[key], stack);
            }, this);
            stack.pop();
        } else {
            sanitized = obj;
        }
        return sanitized;
    };

    function handleNestedExpects(e, assertion) {
        switch (assertion.errorMode) {
        case 'nested':
            e.message = assertion.standardErrorMessage() + '\n    ' + e.message.replace(/\n/g, '\n    ');
            break;
        case 'default':
            e.message = assertion.standardErrorMessage();
            break;
        case 'bubble':
            break;
        default:
            throw new Error("Unknown error mode: '" + assertion.errorMode + "'");
        }
    }

    function installExpectMethods(unexpected, expectFunction) {
        var expect = bind(expectFunction, unexpected);
        expect.equal = bind(unexpected.equal, unexpected);
        expect.sanitize = bind(unexpected.sanitize, unexpected);
        expect.inspect = bind(unexpected.inspect, unexpected);
        expect.fail = bind(unexpected.fail, unexpected);
        expect.addAssertion = bind(unexpected.addAssertion, unexpected);
        expect.addType = bind(unexpected.addType, unexpected);
        expect.clone = bind(unexpected.clone, unexpected);
        expect.toString = bind(unexpected.toString, unexpected);
        expect.assertions = unexpected.assertions;
        expect.installPlugin = bind(unexpected.installPlugin, unexpected);
        return expect;
    }

    function makeExpectFunction(unexpected) {
        var expect = installExpectMethods(unexpected, unexpected.expect);
        unexpected.expect = expect;
        return expect;
    }

    Unexpected.prototype.expect = function expect(subject, testDescriptionString) {
        var that = this;
        if (arguments.length < 2) {
            throw new Error('The expect functions requires at least two parameters.');
        }
        if (typeof testDescriptionString !== 'string') {
            throw new Error('The expect functions requires second parameter to be a string.');
        }
        var assertionRule = this.assertions[testDescriptionString];
        if (assertionRule) {
            var flags = extend({}, assertionRule.flags);
            var nestingLevel = 0;
            var wrappedExpect = function wrappedExpect(subject, testDescriptionString) {
                testDescriptionString = trim(testDescriptionString.replace(/\[(!?)([^\]]+)\] ?/g, function (match, negate, flag) {
                    negate = !!negate;
                    return flags[flag] !== negate ? flag + ' ' : '';
                }));

                var args = Array.prototype.slice.call(arguments, 2);
                nestingLevel += 1;
                try {
                    that.expect.apply(that, [subject, testDescriptionString].concat(args));
                    nestingLevel -= 1;
                } catch (e) {
                    nestingLevel -= 1;
                    if (e._isUnexpected) {
                        truncateStack(e, wrappedExpect);
                    }
                    if (nestingLevel === 0) {
                        handleNestedExpects(e, assertion);
                    }
                    throw e;
                }
            };

            // Not sure this is the right way to go about this:
            wrappedExpect.equal = this.equal;
            wrappedExpect.types = this.types;
            wrappedExpect.sanitize = this.sanitize;
            wrappedExpect.inspect = this.inspect;

            var args = Array.prototype.slice.call(arguments, 2);
            args.unshift(wrappedExpect, subject);
            var assertion = new Assertion(wrappedExpect, subject, testDescriptionString, flags, args.slice(2));
            var handler = assertionRule.handler;
            try {
                handler.apply(assertion, args);
            } catch (e) {
                if (e._isUnexpected) {
                    truncateStack(e, this.expect);
                }
                throw e;
            }
        } else {
            var similarAssertions = this.findAssertionSimilarTo(testDescriptionString);
            var message =
                'Unknown assertion "' + testDescriptionString + '", ' +
                'did you mean: "' + similarAssertions[0] + '"';
            var err = new Error(message);
            truncateStack(err, this.expect);
            throw err;
        }
    };

    Unexpected.prototype.toString = function () {
        return getKeys(this.assertions).sort().join('\n');
    };

    Unexpected.prototype.clone = function () {
        var unexpected = new Unexpected(extend({}, this.assertions), [].concat(this.types));
        return makeExpectFunction(unexpected);
    };

    Unexpected.create = function () {
        var unexpected = new Unexpected();
        return makeExpectFunction(unexpected);
    };

    var expandPattern = (function () {
        function isFlag(token) {
            return token.slice(0, 1) === '[' && token.slice(-1) === ']';
        }
        function isAlternation(token) {
            return token.slice(0, 1) === '(' && token.slice(-1) === ')';
        }
        function removeEmptyStrings(texts) {
            return filter(texts, function (text) {
                return text !== '';
            });
        }
        function createPermutations(tokens, index) {
            if (index === tokens.length) {
                return [{ text: '', flags: {}}];
            }

            var token = tokens[index];
            var tail = createPermutations(tokens, index + 1);
            if (isFlag(token)) {
                var flag = token.slice(1, -1);
                return map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = true;
                    return {
                        text: flag + ' ' + pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }).concat(map(tail, function (pattern) {
                    var flags = {};
                    flags[flag] = false;
                    return {
                        text: pattern.text,
                        flags: extend(flags, pattern.flags)
                    };
                }));
            } else if (isAlternation(token)) {
                var alternations = token.split(/\(|\)|\|/);
                alternations = removeEmptyStrings(alternations);
                return reduce(alternations, function (result, alternation) {
                    return result.concat(map(tail, function (pattern) {
                        return {
                            text: alternation + pattern.text,
                            flags: pattern.flags
                        };
                    }));
                }, []);
            } else {
                return map(tail, function (pattern) {
                    return {
                        text: token + pattern.text,
                        flags: pattern.flags
                    };
                });
            }
        }
        return function (pattern) {
            pattern = pattern.replace(/(\[[^\]]+\]) ?/g, '$1');
            var splitRegex = /\[[^\]]+\]|\([^\)]+\)/g;
            var tokens = [];
            var m;
            var lastIndex = 0;
            while ((m = splitRegex.exec(pattern))) {
                tokens.push(pattern.slice(lastIndex, m.index));
                tokens.push(pattern.slice(m.index, splitRegex.lastIndex));
                lastIndex = splitRegex.lastIndex;
            }
            tokens.push(pattern.slice(lastIndex));

            tokens = removeEmptyStrings(tokens);
            var permutations = createPermutations(tokens, 0);
            forEach(permutations, function (permutation) {
                permutation.text = trim(permutation.text);
                if (permutation.text === '') {
                    // This can only happen if the pattern only contains flags
                    throw new Error("Assertion patterns must not only contain flags");
                }
            });
            return permutations;
        };
    }());

    function ensureValidUseOfParenthesesOrBrackets(pattern) {
        var counts = {
            '[': 0,
            ']': 0,
            '(': 0,
            ')': 0
        };
        for (var i = 0; i < pattern.length; i += 1) {
            var c = pattern.charAt(i);
            if (c in counts) {
                counts[c] += 1;
            }
            if (c === ']' && counts['['] >= counts[']']) {
                if (counts['['] === counts[']'] + 1) {
                    throw new Error("Assertion patterns must not contain flags with brackets: '" + pattern + "'");
                }

                if (counts['('] !== counts[')']) {
                    throw new Error("Assertion patterns must not contain flags with parentheses: '" + pattern + "'");
                }

                if (pattern.charAt(i - 1) === '[') {
                    throw new Error("Assertion patterns must not contain empty flags: '" + pattern + "'");
                }
            } else if (c === ')' && counts['('] >= counts[')']) {
                if (counts['('] === counts[')'] + 1) {
                    throw new Error("Assertion patterns must not contain alternations with parentheses: '" + pattern + "'");
                }

                if (counts['['] !== counts[']']) {
                    throw new Error("Assertion patterns must not contain alternations with brackets: '" + pattern + "'");
                }
            }

            if ((c === ')' || c === '|') && counts['('] >= counts[')']) {
                if (pattern.charAt(i - 1) === '(' || pattern.charAt(i - 1) === '|') {
                    throw new Error("Assertion patterns must not contain empty alternations: '" + pattern + "'");
                }
            }
        }

        if (counts['['] !== counts[']']) {
            throw new Error("Assertion patterns must not contain unbalanced brackets: '" + pattern + "'");
        }

        if (counts['('] !== counts[')']) {
            throw new Error("Assertion patterns must not contain unbalanced parentheses: '" + pattern + "'");
        }
    }

    function ensureValidPattern(pattern) {
        if (typeof pattern !== 'string' || pattern === '') {
            throw new Error("Assertion patterns must be a non empty string");
        }
        if (pattern.match(/^\s|\s$/)) {
            throw new Error("Assertion patterns can't start or end with whitespace");
        }

        ensureValidUseOfParenthesesOrBrackets(pattern);
    }

    namespace.expect = Unexpected.create();
}());
<|endoftext|>


<commit_before>Checklist.ChecklistForm = Em.View.extend({
  tagName: 'form',
  controller: null,
  filtersController: null,

  templateName: "checklist_form",

  submit: function(event) {
    event.preventDefault();

    this.get('filtersController').set('page', 1);

    var params = this.get('filtersController').toParams();
    Checklist.get('router').transitionTo('search', {redraw: false, params: $.param(params)});
  }

});

/*
 * An extended TextField for use in scientific name search.
 *
 * Handles text change events and creates an autocomplete box for the text.
 */
Checklist.SearchTextField = Em.TextField.extend({
  value: '',

  attributeBindings: ['autocomplete'],

  keyUp: function(event) {
    var filtersController = Checklist.get('router').get('filtersController');
    filtersController.set('scientific_name', $(event.target).val());
  },

  click: function(event) {
    var params = {
      param_name: 'scientific_name',
      value: event.value,
      visibility: 'checklist',
      locale: Em.I18n.currentLocale,
      per_page: 10
    };

    var url = Checklist.CONFIG.backend_url + 'taxon_concepts/autocomplete';

    if ($('.typeahead').length <= 0) {
      $('#scientific_name').typeahead(
        {
          source: {url: url, params: params},
          parser: this.parser,
          highlighter: this.highlighter,
          updater: this.updater,
          menu: '

',
          location: '#autocomplete-dropdown'
        }
      );
    }

    if (this.$().val() === this.get('placeholder')) {
      this.$().val('');
    }

    this.$().attr('placeholder', '');
  },

  focusOut: function(event) {
    if ($.browser.msie) {
      if (this.$().val().length === 0) {
        this.$().val(this.get('placeholder'));
      }
    }

    this.$().attr('placeholder', this.get('placeholder'));
  },

  updater: function(item) {
    // Remove synonyms when an item is selected
    return item.replace(/(.*)( \(\=.*\))/, "$1");
  },

  highlighter: function(item) {
    var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var transform = function ($1, match) {
      return '' + match + '';
    };
    return item
      .replace(new RegExp('^(' + query + ')', 'i'), transform)
      .replace(new RegExp('=(' + query + ')', 'ig'), transform);
  },

  parser: function(data) {
    var content = data;
    var results = {};

    // Extract the names of each result row for use by typeahead.js
    content.forEach(function(item,i) {
      if (!(item.rank_name in results)) {
        results[item.rank_name] = [];
      }

      var entry = item.full_name;
      if (item.matching_names.length > 0) {
        entry += " (=" + item.matching_names.join(", ") + ")";
      }
      results[item.rank_name].push(entry);
    });

    return results;
  },

  didInsertElement: function() {
    if ($.browser.msie) {
      this.$().val(this.$().attr('placeholder'));
    }
  }
});

Checklist.SearchTextField.reopen(Em.I18n.TranslateableAttributes);

/*
 * An extended TextField for use in location search.
 *
 * Handles text change events and creates an autocomplete box for the text.
 */
Checklist.GeoEntityTextField = Em.TextField.extend({
  value: '',

  attributeBindings: ['autocomplete'],

  click: function() {
    if (this.$().val() === this.get('placeholder')) {
      this.$().val('');
    }

    this.$().attr('placeholder', '');
  },

  focusOut: function(event) {
    if ($.browser.msie) {
      if (this.$().val().length === 0) {
        this.$().val(this.get('placeholder'));
      }
    }

    this.$().attr('placeholder', this.get('placeholder'));
  },

  keyUp: function(event) {
    var controller = Checklist.get('router').get('filtersController');
    var pattern = new RegExp("(^| )"+event.currentTarget.value,"i");
    controller.set(
      'autoCompleteCountriesContent',
      controller.get('countriesContent').filter(
        function(item, index, enumerable){
          return (pattern.test(item.get('name')));
        }
      )
    );

    pattern = new RegExp("^[0-9]- "+event.currentTarget.value,"i");
    controller.set(
      'autoCompleteRegionsContent',
      controller.get('regionsContent').filter(
        function(item, index, enumerable){
          return (pattern.test(item.get('name')));
        }
      )
    );
  },

  didInsertElement: function() {
    if ($.browser.msie) {
      this.$().val(this.$().attr('placeholder'));
    }
  }
});

Checklist.GeoEntityTextField.reopen(Em.I18n.TranslateableAttributes);
<commit_msg>Fixed geo_entity autocomplete which now considers parentheses<commit_after>Checklist.ChecklistForm = Em.View.extend({
  tagName: 'form',
  controller: null,
  filtersController: null,

  templateName: "checklist_form",

  submit: function(event) {
    event.preventDefault();

    this.get('filtersController').set('page', 1);

    var params = this.get('filtersController').toParams();
    Checklist.get('router').transitionTo('search', {redraw: false, params: $.param(params)});
  }

});

/*
 * An extended TextField for use in scientific name search.
 *
 * Handles text change events and creates an autocomplete box for the text.
 */
Checklist.SearchTextField = Em.TextField.extend({
  value: '',

  attributeBindings: ['autocomplete'],

  keyUp: function(event) {
    var filtersController = Checklist.get('router').get('filtersController');
    filtersController.set('scientific_name', $(event.target).val());
  },

  click: function(event) {
    var params = {
      param_name: 'scientific_name',
      value: event.value,
      visibility: 'checklist',
      locale: Em.I18n.currentLocale,
      per_page: 10
    };

    var url = Checklist.CONFIG.backend_url + 'taxon_concepts/autocomplete';

    if ($('.typeahead').length <= 0) {
      $('#scientific_name').typeahead(
        {
          source: {url: url, params: params},
          parser: this.parser,
          highlighter: this.highlighter,
          updater: this.updater,
          menu: '

',
          location: '#autocomplete-dropdown'
        }
      );
    }

    if (this.$().val() === this.get('placeholder')) {
      this.$().val('');
    }

    this.$().attr('placeholder', '');
  },

  focusOut: function(event) {
    if ($.browser.msie) {
      if (this.$().val().length === 0) {
        this.$().val(this.get('placeholder'));
      }
    }

    this.$().attr('placeholder', this.get('placeholder'));
  },

  updater: function(item) {
    // Remove synonyms when an item is selected
    return item.replace(/(.*)( \(\=.*\))/, "$1");
  },

  highlighter: function(item) {
    var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var transform = function ($1, match) {
      return '' + match + '';
    };
    return item
      .replace(new RegExp('^(' + query + ')', 'i'), transform)
      .replace(new RegExp('=(' + query + ')', 'ig'), transform);
  },

  parser: function(data) {
    var content = data;
    var results = {};

    // Extract the names of each result row for use by typeahead.js
    content.forEach(function(item,i) {
      if (!(item.rank_name in results)) {
        results[item.rank_name] = [];
      }

      var entry = item.full_name;
      if (item.matching_names.length > 0) {
        entry += " (=" + item.matching_names.join(", ") + ")";
      }
      results[item.rank_name].push(entry);
    });

    return results;
  },

  didInsertElement: function() {
    if ($.browser.msie) {
      this.$().val(this.$().attr('placeholder'));
    }
  }
});

Checklist.SearchTextField.reopen(Em.I18n.TranslateableAttributes);

/*
 * An extended TextField for use in location search.
 *
 * Handles text change events and creates an autocomplete box for the text.
 */
Checklist.GeoEntityTextField = Em.TextField.extend({
  value: '',

  attributeBindings: ['autocomplete'],

  click: function() {
    if (this.$().val() === this.get('placeholder')) {
      this.$().val('');
    }

    this.$().attr('placeholder', '');
  },

  focusOut: function(event) {
    if ($.browser.msie) {
      if (this.$().val().length === 0) {
        this.$().val(this.get('placeholder'));
      }
    }

    this.$().attr('placeholder', this.get('placeholder'));
  },

  keyUp: function(event) {
    var controller = Checklist.get('router').get('filtersController');
    var pattern = new RegExp("(^|\\(| )"+event.currentTarget.value,"i");
    controller.set(
      'autoCompleteCountriesContent',
      controller.get('countriesContent').filter(
        function(item, index, enumerable){
          return (pattern.test(item.get('name')));
        }
      )
    );

    pattern = new RegExp("^[0-9]- "+event.currentTarget.value,"i");
    controller.set(
      'autoCompleteRegionsContent',
      controller.get('regionsContent').filter(
        function(item, index, enumerable){
          return (pattern.test(item.get('name')));
        }
      )
    );
  },

  didInsertElement: function() {
    if ($.browser.msie) {
      this.$().val(this.$().attr('placeholder'));
    }
  }
});

Checklist.GeoEntityTextField.reopen(Em.I18n.TranslateableAttributes);
<|endoftext|>


<commit_before>const merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { commonConfig } = require('./webpack.common.js')
const { GenerateSW } = require('workbox-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = () => {
  const CHUNKS = {
    MAP:
      'leaflet|leaflet-draw|leaflet-rotatedmarker|leaflet.markercluster|leaflet.nontiledlayer|proj4|proj4leaflet',
    DATAPUNT: '@datapunt',
    STYLED: 'styled-components|polished|style-loader|css-loader|sass-loader|postcss-loader',
    PANORAMA: 'marzipano',
    POLYFILL: '@babel/polyfill|objectFitPolyfill',
    ANGULAR: 'angular|angular-aria|angular-sanitize|react-angular',
    REACT:
      'react|react-dom|redux-first-router|redux-first-router-link|redux-first-router-restore-scroll|reselect|redux|@?redux-saga|react-redux|react-helmet|prop-types',
  }

  const getTestRegex = path => new RegExp(`/node_modules/(${path})/`)

  return merge(commonConfig(), {
    output: {
      filename: '[name].js?id=[chunkhash]',
      chunkFilename: '[name].bundle.js?id=[chunkhash]',
    },
    mode: 'production',
    devtool: 'source-map',
    optimization: {
      minimizer: [new TerserPlugin()],
      splitChunks: {
        chunks: 'all',
        minSize: 30000,
        minChunks: 1,
        maxAsyncRequests: 5,
        maxInitialRequests: 3,
        name: true,
        cacheGroups: {
          vendor: {
            test: new RegExp(
              `/node_modules/(?!${[
                CHUNKS.DATAPUNT,
                CHUNKS.POLYFILL,
                CHUNKS.MAP,
                CHUNKS.STYLED,
                CHUNKS.REACT,
                CHUNKS.PANORAMA,
                CHUNKS.BBGA,
                CHUNKS.ANGULAR,
              ].join('|')})/`,
            ),
            name: 'vendor',
            chunks: 'all',
          },
          datapunt: {
            test: getTestRegex(CHUNKS.DATAPUNT),
            name: 'datapunt',
            chunks: 'all',
            enforce: true,
          },
          polyfill: {
            test: getTestRegex(CHUNKS.POLYFILL),
            name: 'polyfill',
            chunks: 'all',
            enforce: true,
          },
          map: {
            test: getTestRegex(CHUNKS.MAP),
            name: 'map',
            chunks: 'async',
            enforce: true,
          },
          bbga: {
            test: getTestRegex(CHUNKS.BBGA),
            name: 'bbga',
            chunks: 'async',
            enforce: true,
          },
          panorama: {
            test: getTestRegex(CHUNKS.PANORAMA),
            name: 'panorama',
            chunks: 'async',
            enforce: true,
          },
          styled: {
            test: getTestRegex(CHUNKS.STYLED),
            name: 'styled',
            chunks: 'all',
            enforce: true,
          },
          react: {
            test: getTestRegex(CHUNKS.REACT),
            name: 'react',
            chunks: 'all',
            enforce: true,
          },
          angular: {
            test: getTestRegex(CHUNKS.ANGULAR),
            name: 'angular',
            chunks: 'async',
            enforce: true,
          },
          main: {
            chunks: 'all',
            minChunks: 2,
            reuseExistingChunk: true,
          },
        },
      },
      runtimeChunk: true,
    },
    plugins: [
      new MiniCssExtractPlugin('main.[contenthash].css'),
      new GenerateSW({
        clientsClaim: true,
        skipWaiting: true,
        exclude: [/\.map$/, /\.json$/],
        navigateFallbackDenylist: [
          // Exclude any URLs whose last part seems to be a file extension
          // as they're likely a resource and not a SPA route.
          // URLs containing a "?" character won't be blacklisted as they're likely
          // a route with query params (e.g. auth callbacks).
          new RegExp('/[^/?]+\\.[^/]+$'),
        ],
        cleanupOutdatedCaches: true,
        // Temporary disabled this, since we do not want to cache responses that require authorization
        //
        // runtimeCaching: [
        //   {
        //     urlPattern: new RegExp(apiUrl),
        //     handler: 'StaleWhileRevalidate',
        //     options: {
        //       cacheName: 'api',
        //       expiration: {
        //         maxAgeSeconds: 60 * 60 * 12, // 12h
        //       },
        //       cacheableResponse: {
        //         statuses: [0, 200],
        //       },
        //     },
        //   },
        //   {
        //     urlPattern: new RegExp(`${cmsUrl}(?!/jsonapi/node/notification)`),
        //     handler: 'StaleWhileRevalidate',
        //     options: {
        //       cacheName: 'cms',
        //       expiration: {
        //         maxAgeSeconds: 60 * 60 * 12, // 12h
        //       },
        //       cacheableResponse: {
        //         statuses: [0, 200],
        //       },
        //     },
        //   },
        // ],
      }),
    ],
  })
}
<commit_msg>Removed "skipWaiting" option from workbox<commit_after>const merge = require('webpack-merge')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { commonConfig } = require('./webpack.common.js')
const { GenerateSW } = require('workbox-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = () => {
  const CHUNKS = {
    MAP:
      'leaflet|leaflet-draw|leaflet-rotatedmarker|leaflet.markercluster|leaflet.nontiledlayer|proj4|proj4leaflet',
    DATAPUNT: '@datapunt',
    STYLED: 'styled-components|polished|style-loader|css-loader|sass-loader|postcss-loader',
    PANORAMA: 'marzipano',
    POLYFILL: '@babel/polyfill|objectFitPolyfill',
    ANGULAR: 'angular|angular-aria|angular-sanitize|react-angular',
    REACT:
      'react|react-dom|redux-first-router|redux-first-router-link|redux-first-router-restore-scroll|reselect|redux|@?redux-saga|react-redux|react-helmet|prop-types',
  }

  const getTestRegex = path => new RegExp(`/node_modules/(${path})/`)

  return merge(commonConfig(), {
    output: {
      filename: '[name].js?id=[chunkhash]',
      chunkFilename: '[name].bundle.js?id=[chunkhash]',
    },
    mode: 'production',
    devtool: 'source-map',
    optimization: {
      minimizer: [new TerserPlugin()],
      splitChunks: {
        chunks: 'all',
        minSize: 30000,
        minChunks: 1,
        maxAsyncRequests: 5,
        maxInitialRequests: 3,
        name: true,
        cacheGroups: {
          vendor: {
            test: new RegExp(
              `/node_modules/(?!${[
                CHUNKS.DATAPUNT,
                CHUNKS.POLYFILL,
                CHUNKS.MAP,
                CHUNKS.STYLED,
                CHUNKS.REACT,
                CHUNKS.PANORAMA,
                CHUNKS.BBGA,
                CHUNKS.ANGULAR,
              ].join('|')})/`,
            ),
            name: 'vendor',
            chunks: 'all',
          },
          datapunt: {
            test: getTestRegex(CHUNKS.DATAPUNT),
            name: 'datapunt',
            chunks: 'all',
            enforce: true,
          },
          polyfill: {
            test: getTestRegex(CHUNKS.POLYFILL),
            name: 'polyfill',
            chunks: 'all',
            enforce: true,
          },
          map: {
            test: getTestRegex(CHUNKS.MAP),
            name: 'map',
            chunks: 'async',
            enforce: true,
          },
          bbga: {
            test: getTestRegex(CHUNKS.BBGA),
            name: 'bbga',
            chunks: 'async',
            enforce: true,
          },
          panorama: {
            test: getTestRegex(CHUNKS.PANORAMA),
            name: 'panorama',
            chunks: 'async',
            enforce: true,
          },
          styled: {
            test: getTestRegex(CHUNKS.STYLED),
            name: 'styled',
            chunks: 'all',
            enforce: true,
          },
          react: {
            test: getTestRegex(CHUNKS.REACT),
            name: 'react',
            chunks: 'all',
            enforce: true,
          },
          angular: {
            test: getTestRegex(CHUNKS.ANGULAR),
            name: 'angular',
            chunks: 'async',
            enforce: true,
          },
          main: {
            chunks: 'all',
            minChunks: 2,
            reuseExistingChunk: true,
          },
        },
      },
      runtimeChunk: true,
    },
    plugins: [
      new MiniCssExtractPlugin('main.[contenthash].css'),
      new GenerateSW({
        clientsClaim: true,
        exclude: [/\.map$/, /\.json$/],
        navigateFallbackDenylist: [
          // Exclude any URLs whose last part seems to be a file extension
          // as they're likely a resource and not a SPA route.
          // URLs containing a "?" character won't be blacklisted as they're likely
          // a route with query params (e.g. auth callbacks).
          new RegExp('/[^/?]+\\.[^/]+$'),
        ],
        cleanupOutdatedCaches: true,
        // Temporary disabled this, since we do not want to cache responses that require authorization
        //
        // runtimeCaching: [
        //   {
        //     urlPattern: new RegExp(apiUrl),
        //     handler: 'StaleWhileRevalidate',
        //     options: {
        //       cacheName: 'api',
        //       expiration: {
        //         maxAgeSeconds: 60 * 60 * 12, // 12h
        //       },
        //       cacheableResponse: {
        //         statuses: [0, 200],
        //       },
        //     },
        //   },
        //   {
        //     urlPattern: new RegExp(`${cmsUrl}(?!/jsonapi/node/notification)`),
        //     handler: 'StaleWhileRevalidate',
        //     options: {
        //       cacheName: 'cms',
        //       expiration: {
        //         maxAgeSeconds: 60 * 60 * 12, // 12h
        //       },
        //       cacheableResponse: {
        //         statuses: [0, 200],
        //       },
        //     },
        //   },
        // ],
      }),
    ],
  })
}
<|endoftext|>


<commit_before><commit_msg>[EDIT] 更新queryUserInfo<commit_after><|endoftext|>


<commit_before>'use strict';

function TurtleCtrl() {
}

angular.module('turtleApp').controller('TurtleCtrl', TurtleCtrl);
<commit_msg>Remove useless file.<commit_after><|endoftext|>