<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2012, Olivier BIOT
 * http://www.melonjs.org
 *
 * Tile QT 0.7.x format
 * http://www.mapeditor.org/
 *
 */

(function($, undefined) {

	/**
	 * a basic level object skeleton
	 * @class
	 * @memberOf me
	 * @constructor
	 */
	me.TileMap = Object.extend({
		// constructor
		init: function(x, y) {
			// map default position
			this.pos = new me.Vector2d(x, y);

			// map default z order
			this.z = 0;

			/**
			 * name of the tilemap
			 * @public
			 * @type String
			 * @name me.TileMap#name
			 */
			this.name = null;

			/**
			 * width of the tilemap in Tile
			 * @public
			 * @type Int
			 * @name me.TileMap#width
			 */
			this.width = 0;

			/**
			 * height of the tilemap in Tile
			 * @public
			 * @type Int
			 * @name me.TileMap#height
			 */
			this.height = 0;

			/**
			 * width of the tilemap in pixels
			 * @public
			 * @type Int
			 * @name me.TileMap#realwidth
			 */
			this.realwidth = -1;

			/**
			 * height of the tilemap in pixels
			 * @public
			 * @type Int
			 * @name me.TileMap#realheight
			 */
			this.realheight = -1;

			/**
			 * Tile width
			 * @public
			 * @type Int
			 * @name me.TileMap#tilewidth
			 */
			this.tilewidth = 0;

			/**
			 * Tile height
			 * @public
			 * @type Int
			 * @name me.TileMap#tileheight
			 */
			this.tileheight = 0;

			// corresponding tileset for this map
			this.tilesets = null;

			// map layers
			this.mapLayers = [];

			// map Object
			this.objectGroups = [];

			// loading flag
			this.initialized = false;

		},

		/**
		 * a dummy update function
		 * @private
		 */
		reset : function() {
			this.tilesets = null;
			this.mapLayers.length = 0;
			this.objectGroups.length = 0;
			this.initialized = false;
		},

		/**
		 * return the specified object group
		 * @private
		 */
		getObjectGroupByName : function(name) {
			return this.objectGroups[name];
		},

		/**
		 * return all the object group
		 * @private
		 */
		getObjectGroups : function() {
			return this.objectGroups;
		},

		/**
		 * return all the existing layers
		 * @name me.TileMap#getLayers
		 * @public
		 * @function
		 * @return {me.TiledLayer[]} Array of Layers
		 */
		getLayers : function() {
			return this.mapLayers;
		},

		/**
		 * return the specified layer object
		 * @name me.TileMap#getLayerByName
		 * @public
		 * @function
		 * @param {String} name Layer Name
		 * @return {me.TiledLayer} Layer Object
		 */
		getLayerByName : function(name) {
			var layer = null;

			// normalize name
			name = name.trim().toLowerCase();
			for ( var i = this.mapLayers.length; i--;) {
				if (this.mapLayers[i].name.toLowerCase().contains(name)) {
					layer = this.mapLayers[i];
					break;
				}
			};

			// return a fake collision layer if not found
			if ((name.toLowerCase().contains(me.LevelConstants.COLLISION_MAP)) && (layer == null)) {
				layer = new CollisionTiledLayer(me.game.currentLevel.realwidth,	me.game.currentLevel.realheight);
			}

			return layer;
		},

		/**
		 * clear the tile at the specified position from all layers
		 * @name me.TileMap#clearTile
		 * @public
		 * @function
		 * @param {Integer} x x position
		 * @param {Integer} y y position
		 */
		clearTile : function(x, y) {
			// add all layers
			for ( var i = this.mapLayers.length; i--;) {
				// that are visible
				if (this.mapLayers[i].visible && (this.mapLayers[i] instanceof me.TiledLayer ) ) {
					this.mapLayers[i].clearTile(x, y);
				}
			};
		}

	});

	/**
	 * a TMX Tile Map Object
	 * Tile QT 0.7.x format
	 * @class
	 * @extends me.TileMap
	 * @memberOf me
	 * @constructor
	 */
	me.TMXTileMap = me.TileMap.extend({
		// constructor
		init: function(xmlfile, x, y) {
			// call the constructor
			this.parent(x, y);

			this.xmlMap = me.loader.getXML(xmlfile);

			if (!this.xmlMap) {
				throw "melonJS:" + xmlfile + " TMX map not found";
			};

			// tilemap version
			this.version = "";

			// map type (only orthogonal format supported)
			this.orientation = "";

			// tileset(s)
			this.tilesets = null;

		},

		/**
		 * a dummy update function
		 * @private
		 */
		reset : function() {
			if (this.initialized === true) {
				// reset/clear all layers
				for ( var i = this.mapLayers.length; i--;) {
					this.mapLayers[i].reset();
					this.mapLayers[i] = null;
				};
				// reset object groups
				for ( var i = this.objectGroups.length; i--;) {
					this.objectGroups[i].reset();
					this.objectGroups[i] = null;
				};
				// call parent reset function
				this.parent();
				// set back as not initialized
				this.initialized = false;
			}
		},

		/**
		 * Load & initialize the Tile Map
		 * @private
		 */
		load : function() {
			// if already loaded, do nothing
			if (this.initialized)
				return;

			// to automatically increment z index
			var zOrder = 0;
			// default layer scrolling ratio
			var lratio = 0.25; // 1/4

			// init the parser
			me.XMLParser.parseFromString(this.xmlMap);

			// retreive all the elements of the XML file
			var xmlElements = me.XMLParser.getAllTagElements();

			// parse all tags
			for ( var i = 0; i < xmlElements.length; i++) {
				// check each Tag
				var tagName = xmlElements.item(i).nodeName;

				switch (tagName) {
				// get the map information
				case me.TMX_TAG_MAP: {
				   var map = xmlElements.item(i);
				   this.version = me.XMLParser.getStringAttribute(map, me.TMX_TAG_VERSION);
				   this.orientation = me.XMLParser.getStringAttribute(map, me.TMX_TAG_ORIENTATION);
				   this.width = me.XMLParser.getIntAttribute(map, me.TMX_TAG_WIDTH);
				   this.height = me.XMLParser.getIntAttribute(map, me.TMX_TAG_HEIGHT);
				   this.tilewidth = me.XMLParser.getIntAttribute(map,	me.TMX_TAG_TILEWIDTH);
				   this.tileheight = me.XMLParser.getIntAttribute(map, me.TMX_TAG_TILEHEIGHT);
				   this.realwidth = this.width * this.tilewidth;
				   this.realheight = this.height * this.tileheight;
				   this.backgroundcolor = me.XMLParser.getStringAttribute(map, me.TMX_BACKGROUND_COLOR);
				   this.z = zOrder++;

				   // center the map if smaller than the current viewport
				   if ((this.realwidth < me.game.viewport.width) ||
					   (this.realheight < me.game.viewport.height)) {
						var shiftX =  ~~( (me.game.viewport.width - this.realwidth) / 2);
						var shiftY =  ~~( (me.game.viewport.height - this.realheight) / 2);
						// update the map default screen position
						this.pos.add({x:shiftX > 0 ? shiftX : 0 , y:shiftY > 0 ? shiftY : 0} );
				   }

				   // set the map properties (if any)
				   me.TMXUtils.setTMXProperties(this, map);

				   // check if a user-defined background color is defined
				   this.background_color = this.backgroundcolor ? this.backgroundcolor : this.background_color;
				   if (this.background_color) {
						this.mapLayers.push(new me.ColorLayer("background_color",
															  this.background_color,
															  zOrder++));
				   }

				   // check if a background image is defined
				   if (this.background_image) {
						// add a new image layer
						this.mapLayers.push(new me.ImageLayer("background_image",
															  this.width, this.height,
															  this.background_image,
															  zOrder++));
				   }
				   break;
				}

				// get the tileset information
				case me.TMX_TAG_TILESET: {
				   // Initialize our object if not yet done
				   if (!this.tilesets) {
					  this.tilesets = new me.TMXTilesetGroup();
				   }
				   // add the new tileset
				   this.tilesets.add(new me.TMXTileset(xmlElements.item(i)));
				   break;
				}

				// get image layer information
				case me.TMX_TAG_IMAGE_LAYER: {

					// extract layer information
					var iln = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);
					var ilw = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_WIDTH);
					var ilh = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_HEIGHT);
					var ilsrc = xmlElements.item(i).getElementsByTagName(me.TMX_TAG_IMAGE)[0].getAttribute(me.TMX_TAG_SOURCE);

					// create the layer
					var ilayer = new me.ImageLayer(iln, ilw * this.tilewidth, ilh * this.tileheight, ilsrc, zOrder++);

					// set some additional flags
					ilayer.visible = (me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_VISIBLE, 1) == 1);
					ilayer.opacity = me.XMLParser.getFloatAttribute(xmlElements.item(i), me.TMX_TAG_OPACITY, 1.0);

					// check if we have any properties
					me.TMXUtils.setTMXProperties(ilayer, xmlElements.item(i));

					// add the new layer
					this.mapLayers.push(ilayer);
					break;
				}

				// get the layer(s) information
				case me.TMX_TAG_LAYER: {
					// try to identify specific layer type based on the naming convention
					var layer_name = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);

					// keep this for now for backward-compatibility
					if (layer_name.toLowerCase().contains(me.LevelConstants.PARALLAX_MAP)) {

						// extract layer information
						var ilw = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_WIDTH);
						var ilh = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_HEIGHT);

						// get the layer properties
						var properties = {};
						me.TMXUtils.setTMXProperties(properties, xmlElements.item(i));

						// cherck if a ratio property is defined
						if (properties.ratio) {
							lratio = properties.ratio;
						}

						// create the layer
						var ilayer = new me.ImageLayer(layer_name, ilw * this.tilewidth, ilh * this.tileheight, properties.imagesrc, zOrder++, lratio );

						// apply default TMX properties
						ilayer.visible = (me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_VISIBLE, 1) == 1);
						ilayer.opacity = me.XMLParser.getFloatAttribute(xmlElements.item(i), me.TMX_TAG_OPACITY, 1.0);

						// apply other user defined properties
						me.TMXUtils.mergeProperties(ilayer, properties, false);

						// default increment for next layer
						lratio += lratio * lratio;

						// add the new layer
						this.mapLayers.push(ilayer);
					}
					else {
					  // regular layer or collision layer
					  this.mapLayers.push(new me.TMXLayer(xmlElements.item(i), this.tilewidth, this.tileheight, this.orientation, this.tilesets, zOrder++));
				   }
				   break;
				}

				// get the object groups information
				case me.TMX_TAG_OBJECTGROUP: {
				   var name = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);
				   this.objectGroups.push(new me.TMXOBjectGroup(name, xmlElements.item(i), this.tilesets, zOrder++));
				   break;
				}

				} // end switch
			} // end for

			// free the XMLParser ressource
			me.XMLParser.free();

			// flag as loaded
			this.initialized = true;

		}

	});

	/*---------------------------------------------------------*/
	// END END END
	/*---------------------------------------------------------*/
})(window);
<commit_msg>Issue 33 : fixed map position vector not being resetted<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2012, Olivier BIOT
 * http://www.melonjs.org
 *
 * Tile QT 0.7.x format
 * http://www.mapeditor.org/
 *
 */

(function($, undefined) {

	/**
	 * a basic level object skeleton
	 * @class
	 * @memberOf me
	 * @constructor
	 */
	me.TileMap = Object.extend({
		// constructor
		init: function(x, y) {
			// map default position
			this.pos = new me.Vector2d(x, y);

			// map default z order
			this.z = 0;

			/**
			 * name of the tilemap
			 * @public
			 * @type String
			 * @name me.TileMap#name
			 */
			this.name = null;

			/**
			 * width of the tilemap in Tile
			 * @public
			 * @type Int
			 * @name me.TileMap#width
			 */
			this.width = 0;

			/**
			 * height of the tilemap in Tile
			 * @public
			 * @type Int
			 * @name me.TileMap#height
			 */
			this.height = 0;

			/**
			 * width of the tilemap in pixels
			 * @public
			 * @type Int
			 * @name me.TileMap#realwidth
			 */
			this.realwidth = -1;

			/**
			 * height of the tilemap in pixels
			 * @public
			 * @type Int
			 * @name me.TileMap#realheight
			 */
			this.realheight = -1;

			/**
			 * Tile width
			 * @public
			 * @type Int
			 * @name me.TileMap#tilewidth
			 */
			this.tilewidth = 0;

			/**
			 * Tile height
			 * @public
			 * @type Int
			 * @name me.TileMap#tileheight
			 */
			this.tileheight = 0;

			// corresponding tileset for this map
			this.tilesets = null;

			// map layers
			this.mapLayers = [];

			// map Object
			this.objectGroups = [];

			// loading flag
			this.initialized = false;

		},

		/**
		 * a dummy update function
		 * @private
		 */
		reset : function() {
			this.tilesets = null;
			this.mapLayers.length = 0;
			this.objectGroups.length = 0;
			this.pos.set(0,0);
			this.initialized = false;
		},

		/**
		 * return the specified object group
		 * @private
		 */
		getObjectGroupByName : function(name) {
			return this.objectGroups[name];
		},

		/**
		 * return all the object group
		 * @private
		 */
		getObjectGroups : function() {
			return this.objectGroups;
		},

		/**
		 * return all the existing layers
		 * @name me.TileMap#getLayers
		 * @public
		 * @function
		 * @return {me.TiledLayer[]} Array of Layers
		 */
		getLayers : function() {
			return this.mapLayers;
		},

		/**
		 * return the specified layer object
		 * @name me.TileMap#getLayerByName
		 * @public
		 * @function
		 * @param {String} name Layer Name
		 * @return {me.TiledLayer} Layer Object
		 */
		getLayerByName : function(name) {
			var layer = null;

			// normalize name
			name = name.trim().toLowerCase();
			for ( var i = this.mapLayers.length; i--;) {
				if (this.mapLayers[i].name.toLowerCase().contains(name)) {
					layer = this.mapLayers[i];
					break;
				}
			};

			// return a fake collision layer if not found
			if ((name.toLowerCase().contains(me.LevelConstants.COLLISION_MAP)) && (layer == null)) {
				layer = new CollisionTiledLayer(me.game.currentLevel.realwidth,	me.game.currentLevel.realheight);
			}

			return layer;
		},

		/**
		 * clear the tile at the specified position from all layers
		 * @name me.TileMap#clearTile
		 * @public
		 * @function
		 * @param {Integer} x x position
		 * @param {Integer} y y position
		 */
		clearTile : function(x, y) {
			// add all layers
			for ( var i = this.mapLayers.length; i--;) {
				// that are visible
				if (this.mapLayers[i].visible && (this.mapLayers[i] instanceof me.TiledLayer ) ) {
					this.mapLayers[i].clearTile(x, y);
				}
			};
		}

	});

	/**
	 * a TMX Tile Map Object
	 * Tile QT 0.7.x format
	 * @class
	 * @extends me.TileMap
	 * @memberOf me
	 * @constructor
	 */
	me.TMXTileMap = me.TileMap.extend({
		// constructor
		init: function(xmlfile, x, y) {
			// call the constructor
			this.parent(x, y);

			this.xmlMap = me.loader.getXML(xmlfile);

			if (!this.xmlMap) {
				throw "melonJS:" + xmlfile + " TMX map not found";
			};

			// tilemap version
			this.version = "";

			// map type (only orthogonal format supported)
			this.orientation = "";

			// tileset(s)
			this.tilesets = null;

		},

		/**
		 * a dummy update function
		 * @private
		 */
		reset : function() {
			if (this.initialized === true) {
				// reset/clear all layers
				for ( var i = this.mapLayers.length; i--;) {
					this.mapLayers[i].reset();
					this.mapLayers[i] = null;
				};
				// reset object groups
				for ( var i = this.objectGroups.length; i--;) {
					this.objectGroups[i].reset();
					this.objectGroups[i] = null;
				};
				// call parent reset function
				this.parent();
				// set back as not initialized
				this.initialized = false;
			}
		},

		/**
		 * Load & initialize the Tile Map
		 * @private
		 */
		load : function() {
			// if already loaded, do nothing
			if (this.initialized)
				return;

			// to automatically increment z index
			var zOrder = 0;
			// default layer scrolling ratio
			var lratio = 0.25; // 1/4

			// init the parser
			me.XMLParser.parseFromString(this.xmlMap);

			// retreive all the elements of the XML file
			var xmlElements = me.XMLParser.getAllTagElements();

			// parse all tags
			for ( var i = 0; i < xmlElements.length; i++) {
				// check each Tag
				var tagName = xmlElements.item(i).nodeName;

				switch (tagName) {
				// get the map information
				case me.TMX_TAG_MAP: {
				   var map = xmlElements.item(i);
				   this.version = me.XMLParser.getStringAttribute(map, me.TMX_TAG_VERSION);
				   this.orientation = me.XMLParser.getStringAttribute(map, me.TMX_TAG_ORIENTATION);
				   this.width = me.XMLParser.getIntAttribute(map, me.TMX_TAG_WIDTH);
				   this.height = me.XMLParser.getIntAttribute(map, me.TMX_TAG_HEIGHT);
				   this.tilewidth = me.XMLParser.getIntAttribute(map,	me.TMX_TAG_TILEWIDTH);
				   this.tileheight = me.XMLParser.getIntAttribute(map, me.TMX_TAG_TILEHEIGHT);
				   this.realwidth = this.width * this.tilewidth;
				   this.realheight = this.height * this.tileheight;
				   this.backgroundcolor = me.XMLParser.getStringAttribute(map, me.TMX_BACKGROUND_COLOR);
				   this.z = zOrder++;

				   // center the map if smaller than the current viewport
				   if ((this.realwidth < me.game.viewport.width) ||
					   (this.realheight < me.game.viewport.height)) {
						var shiftX =  ~~( (me.game.viewport.width - this.realwidth) / 2);
						var shiftY =  ~~( (me.game.viewport.height - this.realheight) / 2);
						// update the map default screen position
						this.pos.add({x:shiftX > 0 ? shiftX : 0 , y:shiftY > 0 ? shiftY : 0} );
				   }

				   // set the map properties (if any)
				   me.TMXUtils.setTMXProperties(this, map);

				   // check if a user-defined background color is defined
				   this.background_color = this.backgroundcolor ? this.backgroundcolor : this.background_color;
				   if (this.background_color) {
						this.mapLayers.push(new me.ColorLayer("background_color",
															  this.background_color,
															  zOrder++));
				   }

				   // check if a background image is defined
				   if (this.background_image) {
						// add a new image layer
						this.mapLayers.push(new me.ImageLayer("background_image",
															  this.width, this.height,
															  this.background_image,
															  zOrder++));
				   }
				   break;
				}

				// get the tileset information
				case me.TMX_TAG_TILESET: {
				   // Initialize our object if not yet done
				   if (!this.tilesets) {
					  this.tilesets = new me.TMXTilesetGroup();
				   }
				   // add the new tileset
				   this.tilesets.add(new me.TMXTileset(xmlElements.item(i)));
				   break;
				}

				// get image layer information
				case me.TMX_TAG_IMAGE_LAYER: {

					// extract layer information
					var iln = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);
					var ilw = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_WIDTH);
					var ilh = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_HEIGHT);
					var ilsrc = xmlElements.item(i).getElementsByTagName(me.TMX_TAG_IMAGE)[0].getAttribute(me.TMX_TAG_SOURCE);

					// create the layer
					var ilayer = new me.ImageLayer(iln, ilw * this.tilewidth, ilh * this.tileheight, ilsrc, zOrder++);

					// set some additional flags
					ilayer.visible = (me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_VISIBLE, 1) == 1);
					ilayer.opacity = me.XMLParser.getFloatAttribute(xmlElements.item(i), me.TMX_TAG_OPACITY, 1.0);

					// check if we have any properties
					me.TMXUtils.setTMXProperties(ilayer, xmlElements.item(i));

					// add the new layer
					this.mapLayers.push(ilayer);
					break;
				}

				// get the layer(s) information
				case me.TMX_TAG_LAYER: {
					// try to identify specific layer type based on the naming convention
					var layer_name = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);

					// keep this for now for backward-compatibility
					if (layer_name.toLowerCase().contains(me.LevelConstants.PARALLAX_MAP)) {

						// extract layer information
						var ilw = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_WIDTH);
						var ilh = me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_HEIGHT);

						// get the layer properties
						var properties = {};
						me.TMXUtils.setTMXProperties(properties, xmlElements.item(i));

						// cherck if a ratio property is defined
						if (properties.ratio) {
							lratio = properties.ratio;
						}

						// create the layer
						var ilayer = new me.ImageLayer(layer_name, ilw * this.tilewidth, ilh * this.tileheight, properties.imagesrc, zOrder++, lratio );

						// apply default TMX properties
						ilayer.visible = (me.XMLParser.getIntAttribute(xmlElements.item(i), me.TMX_TAG_VISIBLE, 1) == 1);
						ilayer.opacity = me.XMLParser.getFloatAttribute(xmlElements.item(i), me.TMX_TAG_OPACITY, 1.0);

						// apply other user defined properties
						me.TMXUtils.mergeProperties(ilayer, properties, false);

						// default increment for next layer
						lratio += lratio * lratio;

						// add the new layer
						this.mapLayers.push(ilayer);
					}
					else {
					  // regular layer or collision layer
					  this.mapLayers.push(new me.TMXLayer(xmlElements.item(i), this.tilewidth, this.tileheight, this.orientation, this.tilesets, zOrder++));
				   }
				   break;
				}

				// get the object groups information
				case me.TMX_TAG_OBJECTGROUP: {
				   var name = me.XMLParser.getStringAttribute(xmlElements.item(i), me.TMX_TAG_NAME);
				   this.objectGroups.push(new me.TMXOBjectGroup(name, xmlElements.item(i), this.tilesets, zOrder++));
				   break;
				}

				} // end switch
			} // end for

			// free the XMLParser ressource
			me.XMLParser.free();

			// flag as loaded
			this.initialized = true;

		}

	});

	/*---------------------------------------------------------*/
	// END END END
	/*---------------------------------------------------------*/
})(window);
<|endoftext|>


<commit_before>var TXT_ALC_ACTION_ATTENDRE;
var gameId;
var message;
var prevText;
var path = 'alc-notifier.js';
var alcNotifier = document.createElement('script');
var startInterval = () => {
	chrome.storage.sync.get('delayMS', ({delayMS}) => {
		alcNotifier.dispatchEvent(new CustomEvent('alc-interval', {
			detail: {
				action: 'start',
				delayMS: delayMS || 7000
			}
		}));
	});
}
var stopInterval = () => alcNotifier.dispatchEvent(new CustomEvent('alc-interval', {
	detail: {
		action: 'stop'
	}
}));
var mutation = new MutationObserver(() => {
	var text = message.textContent;

	if (prevText == text) {
		return;
	}

	if (prevText == TXT_ALC_ACTION_ATTENDRE) {
		stopInterval();
		chrome.storage.sync.get('notify-text', ({'notify-text': notifyText}) => {
			chrome.runtime.sendMessage(null, notifyText ? notifyText.replace(/%id/g, gameId) : 'It is your turn (' + gameId + ')');
		});
	} else if (text == TXT_ALC_ACTION_ATTENDRE) {
		startInterval();
	}

	prevText = text;
});
var ready = event => {
	// listen to this event only once
	alcNotifier.removeEventListener('alc-notifier-ready', ready, false);

	TXT_ALC_ACTION_ATTENDRE = event.detail['waiting-text'];
	gameId = event.detail['game-id'];
	message = document.getElementById('message');
	if (message == null) return;
	prevText = message.textContent;

	mutation.observe(message, {
		attributes: false,
		characterData: true,
		childList: true
	});

	if (prevText == TXT_ALC_ACTION_ATTENDRE) {
		startInterval();
	}
};

alcNotifier.addEventListener('alc-notifier-ready', ready, false);

alcNotifier.async = true;
alcNotifier.id = path.replace(/\.js$/, '');
alcNotifier.src = chrome.extension.getURL(path);
alcNotifier.type = 'text/javascript';

document.body.appendChild(alcNotifier);
<commit_msg>Syntax readability: create event before dispatch.<commit_after>var TXT_ALC_ACTION_ATTENDRE;
var gameId;
var message;
var prevText;
var path = 'alc-notifier.js';
var alcNotifier = document.createElement('script');
var startInterval = () => {
	chrome.storage.sync.get('delayMS', ({delayMS}) => {
		var alcIntervalEvent = new CustomEvent('alc-interval', {
			detail: {
				action: 'start',
				delayMS: delayMS || 7000
			}
		});

		alcNotifier.dispatchEvent(alcIntervalEvent);
	});
};
var stopInterval = () => {
	var alcIntervalEvent = new CustomEvent('alc-interval', {
		detail: {
			action: 'stop'
		}
	});

	alcNotifier.dispatchEvent(alcIntervalEvent);
};
var mutation = new MutationObserver(() => {
	var text = message.textContent;

	if (prevText == text) {
		return;
	}

	if (prevText == TXT_ALC_ACTION_ATTENDRE) {
		stopInterval();
		chrome.storage.sync.get('notify-text', ({'notify-text': notifyText}) => {
			chrome.runtime.sendMessage(null, notifyText ? notifyText.replace(/%id/g, gameId) : 'It is your turn (' + gameId + ')');
		});
	} else if (text == TXT_ALC_ACTION_ATTENDRE) {
		startInterval();
	}

	prevText = text;
});
var ready = event => {
	// listen to this event only once
	alcNotifier.removeEventListener('alc-notifier-ready', ready, false);

	TXT_ALC_ACTION_ATTENDRE = event.detail['waiting-text'];
	gameId = event.detail['game-id'];
	message = document.getElementById('message');
	if (message == null) return;
	prevText = message.textContent;

	mutation.observe(message, {
		attributes: false,
		characterData: true,
		childList: true
	});

	if (prevText == TXT_ALC_ACTION_ATTENDRE) {
		startInterval();
	}
};

alcNotifier.addEventListener('alc-notifier-ready', ready, false);

alcNotifier.async = true;
alcNotifier.id = path.replace(/\.js$/, '');
alcNotifier.src = chrome.extension.getURL(path);
alcNotifier.type = 'text/javascript';

document.body.appendChild(alcNotifier);
<|endoftext|>


<commit_before>var JSM = function () {
	this.mainVersion = 0;
	this.subVersion = 36;
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

/**
* Function: IsZero
* Description: Determines if the given value is near zero. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

/**
* Function: IsPositive
* Description: Determines if the given value is positive. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

/**
* Function: IsNegative
* Description: Determines if the given value is negative. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

/**
* Function: IsLower
* Description: Determines if a value is lower than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

/**
* Function: IsGreater
* Description: Determines if a value is greater than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

/**
* Function: IsEqual
* Description: Determines if two values are equal. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

/**
* Function: IsEqualWithEps
* Description: Determines if two values are equal. Uses the given epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
*	eps {number} epsilon value
* Returns:
*	{boolean} the result
*/
JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

/**
* Function: IsLowerOrEqual
* Description: Determines if a value is lower or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: IsGreaterOrEqual
* Description: Determines if a value is greater or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: Minimum
* Description: Returns the minimum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

/**
* Function: Maximum
* Description: Returns the maximum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

/**
* Function: ArcSin
* Description: Calculates the arcus sinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

/**
* Function: ArcCos
* Description: Calculates the arcus cosinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

/**
* Function: RandomNumber
* Description: Generates a random number between two numbers.
* Parameters:
*	from {number} lowest random result
*	to {number} highest random result
* Returns:
*	{number} the result
*/
JSM.RandomNumber = function (from, to)
{
	return Math.random () * (to - from) + from;
};

/**
* Function: RandomInt
* Description: Generates a random integer between two integers.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
* Returns:
*	{integer} the result
*/
JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

/**
* Function: SeededRandomInt
* Description: Generates a random integer between two integers. A seed number can be specified.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
*	seed {integer} seed value
* Returns:
*	{integer} the result
*/
JSM.SeededRandomInt = function (from, to, seed)
{
    var random = ((seed * 9301 + 49297) % 233280) / 233280;
	return Math.floor ((random * (to - from + 1)) + from);
};

/**
* Function: ValueOrDefault
* Description: Returns the given value, or a default if it is undefined.
* Parameters:
*	val {anything} new value
*	def {anything} default value
* Returns:
*	{anything} the result
*/
JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};

/**
* Function: CopyObjectProperties
* Description: Copies one object properties to another object.
* Parameters:
*	source {anything} source object
*	target {anything} target object
*	overwrite {boolean} overwrite existing properties
*/
JSM.CopyObjectProperties = function (source, target, overwrite)
{
	if (source === undefined || source === null ||
		target === undefined || target === null)
	{
		return;
	}

	var property;
	for (property in source) {
		if (source.hasOwnProperty (property)) {
			if (overwrite || target[property] === undefined || target[property] === null) {
				target[property] = source[property];
			}
		}
	}
};

/**
* Function: Assert
* Description: Shows up an alert with the given message if the condition is false.
* Parameters:
*	condition {boolean} the condition to check
*	message {string} error message
*/
JSM.Assert = function (condition, message)
{
	if (!condition) {
		var alertText = 'Assertion failed.';
		if (message !== undefined && message !== null) {
			alertText += ' ' + message;
		}
		alert (alertText);
	}
};
<commit_msg>Update version in development branch.<commit_after>var JSM = function () {
	this.mainVersion = 0;
	this.subVersion = 37;
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

/**
* Function: IsZero
* Description: Determines if the given value is near zero. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

/**
* Function: IsPositive
* Description: Determines if the given value is positive. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

/**
* Function: IsNegative
* Description: Determines if the given value is negative. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

/**
* Function: IsLower
* Description: Determines if a value is lower than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

/**
* Function: IsGreater
* Description: Determines if a value is greater than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

/**
* Function: IsEqual
* Description: Determines if two values are equal. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

/**
* Function: IsEqualWithEps
* Description: Determines if two values are equal. Uses the given epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
*	eps {number} epsilon value
* Returns:
*	{boolean} the result
*/
JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

/**
* Function: IsLowerOrEqual
* Description: Determines if a value is lower or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: IsGreaterOrEqual
* Description: Determines if a value is greater or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: Minimum
* Description: Returns the minimum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

/**
* Function: Maximum
* Description: Returns the maximum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

/**
* Function: ArcSin
* Description: Calculates the arcus sinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

/**
* Function: ArcCos
* Description: Calculates the arcus cosinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

/**
* Function: RandomNumber
* Description: Generates a random number between two numbers.
* Parameters:
*	from {number} lowest random result
*	to {number} highest random result
* Returns:
*	{number} the result
*/
JSM.RandomNumber = function (from, to)
{
	return Math.random () * (to - from) + from;
};

/**
* Function: RandomInt
* Description: Generates a random integer between two integers.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
* Returns:
*	{integer} the result
*/
JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

/**
* Function: SeededRandomInt
* Description: Generates a random integer between two integers. A seed number can be specified.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
*	seed {integer} seed value
* Returns:
*	{integer} the result
*/
JSM.SeededRandomInt = function (from, to, seed)
{
    var random = ((seed * 9301 + 49297) % 233280) / 233280;
	return Math.floor ((random * (to - from + 1)) + from);
};

/**
* Function: ValueOrDefault
* Description: Returns the given value, or a default if it is undefined.
* Parameters:
*	val {anything} new value
*	def {anything} default value
* Returns:
*	{anything} the result
*/
JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};

/**
* Function: CopyObjectProperties
* Description: Copies one object properties to another object.
* Parameters:
*	source {anything} source object
*	target {anything} target object
*	overwrite {boolean} overwrite existing properties
*/
JSM.CopyObjectProperties = function (source, target, overwrite)
{
	if (source === undefined || source === null ||
		target === undefined || target === null)
	{
		return;
	}

	var property;
	for (property in source) {
		if (source.hasOwnProperty (property)) {
			if (overwrite || target[property] === undefined || target[property] === null) {
				target[property] = source[property];
			}
		}
	}
};

/**
* Function: Assert
* Description: Shows up an alert with the given message if the condition is false.
* Parameters:
*	condition {boolean} the condition to check
*	message {string} error message
*/
JSM.Assert = function (condition, message)
{
	if (!condition) {
		var alertText = 'Assertion failed.';
		if (message !== undefined && message !== null) {
			alertText += ' ' + message;
		}
		alert (alertText);
	}
};
<|endoftext|>


<commit_before>var JSM = {
	mainVersion : 0,
	subVersion : 32
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

/**
* Function: IsZero
* Description: Determines if the given value is near zero. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

/**
* Function: IsPositive
* Description: Determines if the given value is positive. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

/**
* Function: IsNegative
* Description: Determines if the given value is negative. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

/**
* Function: IsLower
* Description: Determines if a value is lower than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

/**
* Function: IsGreater
* Description: Determines if a value is greater than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

/**
* Function: IsEqual
* Description: Determines if two values are equal. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

/**
* Function: IsEqualWithEps
* Description: Determines if two values are equal. Uses the given epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
*	eps {number} epsilon value
* Returns:
*	{boolean} the result
*/
JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

/**
* Function: IsLowerOrEqual
* Description: Determines if a value is lower or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: IsGreaterOrEqual
* Description: Determines if a value is greater or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: Minimum
* Description: Returns the minimum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

/**
* Function: Maximum
* Description: Returns the maximum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

/**
* Function: ArcSin
* Description: Calculates the arcus sinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

/**
* Function: ArcCos
* Description: Calculates the arcus cosinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

/**
* Function: RandomNumber
* Description: Generates a random number between two numbers.
* Parameters:
*	from {number} lowest random result
*	to {number} highest random result
* Returns:
*	{number} the result
*/
JSM.RandomNumber = function (from, to)
{
	return Math.random () * (to - from) + from;
};

/**
* Function: RandomInt
* Description: Generates a random integer between two integers.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
* Returns:
*	{integer} the result
*/
JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

/**
* Function: SeededRandomInt
* Description: Generates a random integer between two integers. A seed number can be specified.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
*	seed {integer} seed value
* Returns:
*	{integer} the result
*/
JSM.SeededRandomInt = function (from, to, seed)
{
    var random = ((seed * 9301 + 49297) % 233280) / 233280;
	return Math.floor ((random * (to - from + 1)) + from);
};

/**
* Function: ValueOrDefault
* Description: Returns the given value, or a default if it is undefined.
* Parameters:
*	val {anything} new value
*	def {anything} default value
* Returns:
*	{anything} the result
*/
JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};

/**
* Function: Assert
* Description: Shows up an alert with the given message if the condition is false.
* Parameters:
*	condition {boolean} the condition to check
*	message {string} error message
*/
JSM.Assert = function (condition, message)
{
	if (!condition) {
		var alertText = 'Assertion failed.';
		if (message !== undefined && message !== null) {
			alertText += ' ' + message;
		}
		alert (alertText);
	}
};
<commit_msg>Update version in development branch.<commit_after>var JSM = {
	mainVersion : 0,
	subVersion : 33
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

/**
* Function: IsZero
* Description: Determines if the given value is near zero. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

/**
* Function: IsPositive
* Description: Determines if the given value is positive. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

/**
* Function: IsNegative
* Description: Determines if the given value is negative. Uses epsilon for comparison.
* Parameters:
*	a {number} the value
* Returns:
*	{boolean} the result
*/
JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

/**
* Function: IsLower
* Description: Determines if a value is lower than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

/**
* Function: IsGreater
* Description: Determines if a value is greater than an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

/**
* Function: IsEqual
* Description: Determines if two values are equal. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

/**
* Function: IsEqualWithEps
* Description: Determines if two values are equal. Uses the given epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
*	eps {number} epsilon value
* Returns:
*	{boolean} the result
*/
JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

/**
* Function: IsLowerOrEqual
* Description: Determines if a value is lower or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: IsGreaterOrEqual
* Description: Determines if a value is greater or equal to an other. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{boolean} the result
*/
JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

/**
* Function: Minimum
* Description: Returns the minimum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

/**
* Function: Maximum
* Description: Returns the maximum of two values. Uses epsilon for comparison.
* Parameters:
*	a {number} first value
*	b {number} second value
* Returns:
*	{number} the result
*/
JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

/**
* Function: ArcSin
* Description: Calculates the arcus sinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

/**
* Function: ArcCos
* Description: Calculates the arcus cosinus value.
* Parameters:
*	value {number} the value
* Returns:
*	{number} the result
*/
JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

/**
* Function: RandomNumber
* Description: Generates a random number between two numbers.
* Parameters:
*	from {number} lowest random result
*	to {number} highest random result
* Returns:
*	{number} the result
*/
JSM.RandomNumber = function (from, to)
{
	return Math.random () * (to - from) + from;
};

/**
* Function: RandomInt
* Description: Generates a random integer between two integers.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
* Returns:
*	{integer} the result
*/
JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

/**
* Function: SeededRandomInt
* Description: Generates a random integer between two integers. A seed number can be specified.
* Parameters:
*	from {integer} lowest random result
*	to {integer} highest random result
*	seed {integer} seed value
* Returns:
*	{integer} the result
*/
JSM.SeededRandomInt = function (from, to, seed)
{
    var random = ((seed * 9301 + 49297) % 233280) / 233280;
	return Math.floor ((random * (to - from + 1)) + from);
};

/**
* Function: ValueOrDefault
* Description: Returns the given value, or a default if it is undefined.
* Parameters:
*	val {anything} new value
*	def {anything} default value
* Returns:
*	{anything} the result
*/
JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};

/**
* Function: Assert
* Description: Shows up an alert with the given message if the condition is false.
* Parameters:
*	condition {boolean} the condition to check
*	message {string} error message
*/
JSM.Assert = function (condition, message)
{
	if (!condition) {
		var alertText = 'Assertion failed.';
		if (message !== undefined && message !== null) {
			alertText += ' ' + message;
		}
		alert (alertText);
	}
};
<|endoftext|>


<commit_before>var JSM = {
	mainVersion : 0,
	subVersion : 19
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};
<commit_msg>Upgrade version in development branch.<commit_after>var JSM = {
	mainVersion : 0,
	subVersion : 20
};

JSM.Eps = 0.00000001;
JSM.Inf = 9999999999;
JSM.RadDeg = 57.29577951308232;
JSM.DegRad = 0.017453292519943;

JSM.IsZero = function (a)
{
	return Math.abs (a) < JSM.Eps;
};

JSM.IsPositive = function (a)
{
	return a > JSM.Eps;
};

JSM.IsNegative = function (a)
{
	return a < -JSM.Eps;
};

JSM.IsLower = function (a, b)
{
	return b - a > JSM.Eps;
};

JSM.IsGreater = function (a, b)
{
	return a - b > JSM.Eps;
};

JSM.IsEqual = function (a, b)
{
	return Math.abs (b - a) < JSM.Eps;
};

JSM.IsEqualWithEps = function (a, b, eps)
{
	return Math.abs (b - a) < eps;
};

JSM.IsLowerOrEqual = function (a, b)
{
	return JSM.IsLower (a, b) || JSM.IsEqual (a, b);
};

JSM.IsGreaterOrEqual = function (a, b)
{
	return JSM.IsGreater (a, b) || JSM.IsEqual (a, b);
};

JSM.Minimum = function (a, b)
{
	return JSM.IsLower (a, b) ? a : b;
};

JSM.Maximum = function (a, b)
{
	return JSM.IsGreater (a, b) ? a : b;
};

JSM.ArcSin = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return Math.PI / 2.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return - Math.PI / 2.0;
	}

	return Math.asin (value);
};

JSM.ArcCos = function (value)
{
	if (JSM.IsGreaterOrEqual (value, 1.0)) {
		return 0.0;
	} else if (JSM.IsLowerOrEqual (value, -1.0)) {
		return Math.PI;
	}

	return Math.acos (value);
};

JSM.RandomInt = function (from, to)
{
	return Math.floor ((Math.random () * (to - from + 1)) + from);
};

JSM.ValueOrDefault = function (val, def)
{
	if (val === undefined || val === null) {
		return def;
	}
	return val;
};
<|endoftext|>


<commit_before>/*requires knockout, knockout.mapping, knockout.validation, jquery, lodash*/
/*jslint nomen: true, vars: true*/
(function (root, factory) {
    'use strict';
    /*global define*/
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports', 'knockout', 'knockout-mapping', 'jquery', 'lodash'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        factory(exports, require('knockout'), require('knockout-mapping'), require('jquery'), require('lodash'));
    } else {
        // Browser globals
        if (!root.ko || !root.ko.mapping || !root.$ || !root._) {
            throw new Error('knockout.js & knockout-mapping & jQuery & Lodash is required');
        }
        root.coverlet = {};
        factory(root.coverlet, root.ko, root.ko.mapping, root.$, root._);
    }
}(this, function (exports, ko, mapping, $, _) {
    'use strict';

    var Rest = (function () {
        function Class(url) {
            // http://jsperf.com/remove-last-char/2
            this.url = (url.indexOf('/') === (url.length - 1)) ?
                    url.substr(0, url.length - 1) :
                    url;
        }

        Class.prototype.get = function (id) {
            var that = this;
            return $.ajax({
                type: 'GET',
                url: that.url + (id ? '/' + id : ''),
                dataType: 'json'
            });
        };

        Class.prototype.post = function (item) {
            var that = this;
            return $.ajax({
                type: 'POST',
                url: that.url,
                dataType: 'json',
                contentType: 'application/json',
                data: JSON.stringify(item)
            });
        };

        Class.prototype.put = function (item) {
            var that = this;
            return $.ajax({
                type: 'PUT',
                url: that.url + '/' + item.id,
                dataType: 'json',
                contentType: 'application/json',
                data: JSON.stringify(item)
            });
        };

        Class.prototype.del = function (id) {
            var that = this;
            return $.ajax({
                type: 'DELETE',
                url: that.url + '/' + id,
                dataType: 'text'
            });
        };

        return Class;
    }());

    var RestStub = (function () {
        function Class(StubModel, collectionSize) {
            var that = this;
            that.StubModel = StubModel;
            that.data = _.times(collectionSize, function (i) {
                return new StubModel(i);
            });
        }

        Class.prototype.get = function (id) {
            var that = this;
            return $.when(_.clone(_.find(that.data, {'id': id}), true));
        };

        Class.prototype.post = function (item) {
            var that = this;
            item.id = item.id || (that.data[that.data.length - 1].id + 1);
            var clone = _.clone(item, true);
            that.data.push(clone);
            return $.when(clone);
        };

        Class.prototype.put = function (item) {
            var that = this;
            var clone = _.clone(item, true);
            that.data[_.findIndex(that.data, {'id': item.id})] = clone;
            return $.when(clone);
        };

        Class.prototype.del = function (id) {
            var that = this;
            _.remove(that.data, {'id': id});
            return $.when(true);
        };
        return Class;
    }());

    var LocalStorageRestDecorator = (function () {
        /*global localStorage*/
        function Class(base, key, TTL) {
            this.base = base;
            this.TTL = TTL;
            this.key = key;
        }

        function isLocalStorageSupports() {
            var test = '__test';
            try {
                localStorage.setItem(test, test);
                localStorage.removeItem(test);
                return true;
            } catch (e) {
                return false;
            }
        }

        if (!isLocalStorageSupports()) {
            return Class;
        }

        var fetch = function () {
            var that = this;
            return that.base.get()
                .then(function (newCollection) {
                    localStorage.setItem(that.key, JSON.stringify(newCollection));
                    localStorage.setItem(that.key + '_timeout', (new Date().getTime()) + that.TTL);
                    return newCollection;
                });
        };

        var fetchIfNotExist = function () {
            var that = this,
                cacheTimeout = JSON.parse(localStorage.getItem(that.key + '_timeout'));
            if (cacheTimeout < ((new Date().getTime()) + that.TTL)) {
                return $.when(fetch.call(that));
            }
            return $.when(JSON.parse(localStorage.getItem(that.key)));
        };

        Class.prototype.get = function (id) {
            var that = this;
            return fetchIfNotExist.call(that)
                .then(function (collection) {
                    if (typeof id === 'number') {
                        return _.find(collection, {'id': id});
                    }
                    return collection;
                });
        };
        Class.prototype.post = function (item) {
            var that = this;
            return that.base.post(item)
                .then(function (newItem) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                cache.push(newItem);
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return newItem;
                });
        };
        Class.prototype.put = function (item) {
            var that = this;
            return that.base.put(item)
                .then(function (newItem) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                var oldIndex = _.findIndex(cache, {'id': newItem.id});
                                cache[oldIndex] = newItem;
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return newItem;
                });
        };
        Class.prototype.del = function (id) {
            var that = this;
            return that.base.del(id)
                .then(function (data) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                var oldIndex = _.findIndex(cache, {'id': id});
                                cache.splice(oldIndex, 1);
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return data;
                });
        };

        return Class;
    }());

    var CachedRestDecorator = (function () {
        function Class(base, TTL) {
            this.data = [];
            this.cacheTimeout = 0;
            this.base = base;
            this.TTL = TTL;
        }

        var fetch = function () {
            var that = this;
            return that.base.get()
                .then(function (newCollection) {
                    that.data = newCollection;
                    that.cacheTimeout = (new Date().getTime()) + that.TTL;
                    return newCollection;
                });
        };

        var fetchIfNotExist = function () {
            var that = this;
            return $.when(that.data || fetch.call(that));
        };

        Class.prototype.get = function (id) {
            var that = this;
            return fetchIfNotExist.call(that)
                .then(function (cache) {
                    if (typeof id === 'number') {
                        return _.find(cache, {'id': id});
                    }
                    return cache;
                });
        };

        Class.prototype.post = function (item) {
            var that = this;
            return that.base.post(item)
                .then(function (newItem) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            cache.push(newItem);
                            that.data = cache;
                            return newItem;
                        });
                });
        };

        Class.prototype.put = function (item) {
            var that = this;
            return that.base.put(item)
                .then(function (newItem) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            var oldIndex = _.findIndex(cache, {'id': newItem.id});
                            cache[oldIndex] = newItem;
                            that.data = cache;
                            return newItem;
                        });
                });
        };

        Class.prototype.del = function (id) {
            var that = this;
            return that.base.del(id)
                .then(function (data) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            var oldIndex = _.findIndex(cache, {'id': id});
                            cache.splice(oldIndex, 1);
                            that.data = cache;
                            return data;
                        });
                });
        };

        return Class;
    }());

    var Model = (function () {
        function Class(data, restClient, options) {
            var that = this;
            data = data || {};

            that.restClient = restClient;

            that.options = options || {};
            _.defaults(that.options, {
                id: null,
                indexes: null,
                immediateCommit: false,
                rateLimit: 200,
                validators: {}
            });

            that.model = mapping.fromJS(data);

            _.forOwn(options.validators, function (validator, key) {
                that.model[key] = that.model[key].extend(validator);
            });

            that.isValid = ko.computed(function () {
                return (!ko.validation.group(that.model)().length);
            });

            var lastValue = ko.observable(ko.toJSON(that.model));
            that.isDirty = ko.computed({
                read: function () {
                    return ko.toJSON(that.model) !== lastValue();
                },
                write: function (newValue) {
                    if (newValue) {
                        lastValue('');
                    } else {
                        lastValue(ko.toJSON(that.model));
                    }
                }
            });
            that.isImmediateCommit = ko.observable(options.immediateCommit);
            ko.computed(function () {
                if (that.isImmediateCommit() && that.isDirty() && that.isValid()) {
                    that.commit();
                }
            }).extend({rateLimit: that.options.rateLimit});
        }

        Class.prototype.map = function (data) {
            var that = this;
            mapping.fromJS(data, that.model);
            that.isDirty(false);
            return that;
        };

        Class.prototype.commit = function (invalid) {
            var that = this;
            if (!invalid && !that.isValid()) {
                return $.Deffered().reject('model is invalid');
            }
            return that.restClient[that.model[that.options.id]() ? 'put' : 'post'](ko.toJSON(that.model))
                .then(function (newData) {
                    if (newData) {
                        that.map(newData);
                    }
                    that.isDirty(false);
                    return that;
                });
        };

        Class.prototype.fetch = function () {
            var that = this;
            return that.restClient.get(that.model[that.options.id]())
                .then(function (data) {
                    that.map(data);
                    return that;
                });
        };

        Class.prototype.del = function () {
            var that = this;
            return that.restClient.del(that.model[that.options.id]())
                .then(function () {
                    that.model[that.options.id](null);
                });
        };

        return Class;
    }());

    var Collection = (function () {
        function Class(data, restClient, options) {
            var that = this;

            data = data || [];

            that.restClient = restClient;

            that.options = options || {};
            _.defaults(that.options, {
                id: null,
                indexes: null,
                immediateCommit: false,
                rateLimit: 200,
                validators: {}
            });

            that.collection = ko.observableArray(_.map(data, function (item) {
                return new Model(item, that.restClient, that.options);
            }));

            that.index = {};
            if (that.options.id) {
                that.index.id = ko.computed(function () {
                    return _.indexBy(that.collection(), function (item) {
                        var idProperty = item.model[that.options.id];
                        return idProperty && idProperty();
                    });
                });
            }

            function manyToManyMap(source, first, second) {
                return _.each(_.groupBy(source, first), function (group, key, collection) {
                    collection[key] = _.indexBy(group, second);
                });
            }

            _.forEach(that.options.indexes, function (index) {
                if (_.isArray(index) && index.length === 2) {
                    that.index[index[0] + ':' + index[1]] = ko.computed(function () {
                        return manyToManyMap(that.collection(), function (item) {
                            var indexProperty = item.model[index[0]];
                            return indexProperty && indexProperty();
                        }, function (item) {
                            var indexProperty = item.model[index[1]];
                            return indexProperty && indexProperty();
                        });
                    });
                } else {
                    that.index[index] = ko.computed(function () {
                        _.indexBy(that.collection(), function (item) {
                            var indexProperty = item.model[index];
                            return indexProperty && indexProperty();
                        });
                    });
                }
            });
        }

        Class.prototype.map = function (data) {
            var that = this;
            var toDelete = _.difference(_.keys(that.index.id()), _.pluck(data, that.options.id));
            _.forEach(toDelete, function (id) {
                that.collection.remove(that.index.id()[id]);
            });
            _.forEach(data, function (newItem) {
                var oldItem = that.index.id()[newItem[that.options.id]];
                if (!oldItem) {
                    that.collection.push(new Model(newItem, that.restClient, that.options));
                } else {
                    oldItem.map(newItem);
                }
            });
            return that;
        };

        Class.prototype.commit = function () {
            var that = this;
            _.forEach(that.collection(), function (item) {
                if (item.isDirty()) {
                    item.commit();
                }
            });
        };

        Class.prototype.fetch = function () {
            var that = this;
            return that.restClient.get()
                .then(function (newData) {
                    that.map(newData);
                    return that;
                });
        };

        Class.prototype.create = function (data) {
            var that = this;
            var newItem = new Model(data, that.restClient, that.options);
            that.collection.push(newItem);
            return newItem;
        };

        Class.prototype.del = function (id) {
            var that = this;
            if (!id) {
                throw new Error('"id" argument is required');
            }
            var item = that.index.id()[id];
            item.del();
            that.collection.remove(item);
            return item;
        };

        return Class;
    }());

    exports.Rest = Rest;
    exports.RestStub = RestStub;

    exports.LocalStorageRestDecorator = LocalStorageRestDecorator;
    exports.CachedRestDecorator = CachedRestDecorator;

    exports.Model = Model;
    exports.Collection = Collection;
}));<commit_msg>fix mapping to json<commit_after>/*requires knockout, knockout.mapping, knockout.validation, jquery, lodash*/
/*jslint nomen: true, vars: true*/
(function (root, factory) {
    'use strict';
    /*global define*/
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports', 'knockout', 'knockout-mapping', 'jquery', 'lodash'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        factory(exports, require('knockout'), require('knockout-mapping'), require('jquery'), require('lodash'));
    } else {
        // Browser globals
        if (!root.ko || !root.ko.mapping || !root.$ || !root._) {
            throw new Error('knockout.js & knockout-mapping & jQuery & Lodash is required');
        }
        root.coverlet = {};
        factory(root.coverlet, root.ko, root.ko.mapping, root.$, root._);
    }
}(this, function (exports, ko, mapping, $, _) {
    'use strict';

    var Rest = (function () {
        function Class(url) {
            // http://jsperf.com/remove-last-char/2
            this.url = (url.indexOf('/') === (url.length - 1)) ?
                    url.substr(0, url.length - 1) :
                    url;
        }

        Class.prototype.get = function (id) {
            var that = this;
            return $.ajax({
                type: 'GET',
                url: that.url + (id ? '/' + id : ''),
                dataType: 'json'
            });
        };

        Class.prototype.post = function (item) {
            var that = this;
            return $.ajax({
                type: 'POST',
                url: that.url,
                dataType: 'json',
                contentType: 'application/json',
                data: mapping.toJSON(item)
            });
        };

        Class.prototype.put = function (item) {
            var that = this;
            return $.ajax({
                type: 'PUT',
                url: that.url + '/' + item.id,
                dataType: 'json',
                contentType: 'application/json',
                data: mapping.toJSON(item)
            });
        };

        Class.prototype.del = function (id) {
            var that = this;
            return $.ajax({
                type: 'DELETE',
                url: that.url + '/' + id,
                dataType: 'text'
            });
        };

        return Class;
    }());

    var RestStub = (function () {
        function Class(StubModel, collectionSize) {
            var that = this;
            that.StubModel = StubModel;
            that.data = _.times(collectionSize, function (i) {
                return new StubModel(i);
            });
        }

        Class.prototype.get = function (id) {
            var that = this;
            return $.when(_.clone(_.find(that.data, {'id': id}), true));
        };

        Class.prototype.post = function (item) {
            var that = this;
            item.id = item.id || (that.data[that.data.length - 1].id + 1);
            var clone = _.clone(item, true);
            that.data.push(clone);
            return $.when(clone);
        };

        Class.prototype.put = function (item) {
            var that = this;
            var clone = _.clone(item, true);
            that.data[_.findIndex(that.data, {'id': item.id})] = clone;
            return $.when(clone);
        };

        Class.prototype.del = function (id) {
            var that = this;
            _.remove(that.data, {'id': id});
            return $.when(true);
        };
        return Class;
    }());

    var LocalStorageRestDecorator = (function () {
        /*global localStorage*/
        function Class(base, key, TTL) {
            this.base = base;
            this.TTL = TTL;
            this.key = key;
        }

        function isLocalStorageSupports() {
            var test = '__test';
            try {
                localStorage.setItem(test, test);
                localStorage.removeItem(test);
                return true;
            } catch (e) {
                return false;
            }
        }

        if (!isLocalStorageSupports()) {
            return Class;
        }

        var fetch = function () {
            var that = this;
            return that.base.get()
                .then(function (newCollection) {
                    localStorage.setItem(that.key, JSON.stringify(newCollection));
                    localStorage.setItem(that.key + '_timeout', (new Date().getTime()) + that.TTL);
                    return newCollection;
                });
        };

        var fetchIfNotExist = function () {
            var that = this,
                cacheTimeout = JSON.parse(localStorage.getItem(that.key + '_timeout'));
            if (cacheTimeout < ((new Date().getTime()) + that.TTL)) {
                return $.when(fetch.call(that));
            }
            return $.when(JSON.parse(localStorage.getItem(that.key)));
        };

        Class.prototype.get = function (id) {
            var that = this;
            return fetchIfNotExist.call(that)
                .then(function (collection) {
                    if (typeof id === 'number') {
                        return _.find(collection, {'id': id});
                    }
                    return collection;
                });
        };
        Class.prototype.post = function (item) {
            var that = this;
            return that.base.post(item)
                .then(function (newItem) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                cache.push(newItem);
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return newItem;
                });
        };
        Class.prototype.put = function (item) {
            var that = this;
            return that.base.put(item)
                .then(function (newItem) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                var oldIndex = _.findIndex(cache, {'id': newItem.id});
                                cache[oldIndex] = newItem;
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return newItem;
                });
        };
        Class.prototype.del = function (id) {
            var that = this;
            return that.base.del(id)
                .then(function (data) {
                    setTimeout(function () {
                        fetchIfNotExist.call(that)
                            .then(function (cache) {
                                var oldIndex = _.findIndex(cache, {'id': id});
                                cache.splice(oldIndex, 1);
                                localStorage.setItem(that.key, JSON.stringify(cache));
                            });
                    }, 0);
                    return data;
                });
        };

        return Class;
    }());

    var CachedRestDecorator = (function () {
        function Class(base, TTL) {
            this.data = [];
            this.cacheTimeout = 0;
            this.base = base;
            this.TTL = TTL;
        }

        var fetch = function () {
            var that = this;
            return that.base.get()
                .then(function (newCollection) {
                    that.data = newCollection;
                    that.cacheTimeout = (new Date().getTime()) + that.TTL;
                    return newCollection;
                });
        };

        var fetchIfNotExist = function () {
            var that = this;
            return $.when(that.data || fetch.call(that));
        };

        Class.prototype.get = function (id) {
            var that = this;
            return fetchIfNotExist.call(that)
                .then(function (cache) {
                    if (typeof id === 'number') {
                        return _.find(cache, {'id': id});
                    }
                    return cache;
                });
        };

        Class.prototype.post = function (item) {
            var that = this;
            return that.base.post(item)
                .then(function (newItem) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            cache.push(newItem);
                            that.data = cache;
                            return newItem;
                        });
                });
        };

        Class.prototype.put = function (item) {
            var that = this;
            return that.base.put(item)
                .then(function (newItem) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            var oldIndex = _.findIndex(cache, {'id': newItem.id});
                            cache[oldIndex] = newItem;
                            that.data = cache;
                            return newItem;
                        });
                });
        };

        Class.prototype.del = function (id) {
            var that = this;
            return that.base.del(id)
                .then(function (data) {
                    return fetchIfNotExist.call(that)
                        .then(function (cache) {
                            var oldIndex = _.findIndex(cache, {'id': id});
                            cache.splice(oldIndex, 1);
                            that.data = cache;
                            return data;
                        });
                });
        };

        return Class;
    }());

    var Model = (function () {
        function Class(data, restClient, options) {
            var that = this;
            data = data || {};

            that.restClient = restClient;

            that.options = options || {};
            _.defaults(that.options, {
                id: null,
                indexes: null,
                immediateCommit: false,
                rateLimit: 200,
                validators: {}
            });

            that.model = mapping.fromJS(data);

            _.forOwn(options.validators, function (validator, key) {
                that.model[key] = that.model[key].extend(validator);
            });

            that.isValid = ko.computed(function () {
                return (!ko.validation.group(that.model)().length);
            });

            var lastValue = ko.observable(mapping.toJSON(that.model));
            that.isDirty = ko.computed({
                read: function () {
                    return mapping.toJSON(that.model) !== lastValue();
                },
                write: function (newValue) {
                    if (newValue) {
                        lastValue('');
                    } else {
                        lastValue(mapping.toJSON(that.model));
                    }
                }
            });
            that.isImmediateCommit = ko.observable(options.immediateCommit);
            ko.computed(function () {
                if (that.isImmediateCommit() && that.isDirty() && that.isValid()) {
                    that.commit();
                }
            }).extend({rateLimit: that.options.rateLimit});
        }

        Class.prototype.map = function (data) {
            var that = this;
            mapping.fromJS(data, that.model);
            that.isDirty(false);
            return that;
        };

        Class.prototype.commit = function (invalid) {
            var that = this;
            if (!invalid && !that.isValid()) {
                return $.Deffered().reject('model is invalid');
            }
            return that.restClient[that.model[that.options.id]() ? 'put' : 'post'](mapping.toJSON(that.model))
                .then(function (newData) {
                    if (newData) {
                        that.map(newData);
                    }
                    that.isDirty(false);
                    return that;
                });
        };

        Class.prototype.fetch = function () {
            var that = this;
            return that.restClient.get(that.model[that.options.id]())
                .then(function (data) {
                    that.map(data);
                    return that;
                });
        };

        Class.prototype.del = function () {
            var that = this;
            return that.restClient.del(that.model[that.options.id]())
                .then(function () {
                    that.model[that.options.id](null);
                });
        };

        return Class;
    }());

    var Collection = (function () {
        function Class(data, restClient, options) {
            var that = this;

            data = data || [];

            that.restClient = restClient;

            that.options = options || {};
            _.defaults(that.options, {
                id: null,
                indexes: null,
                immediateCommit: false,
                rateLimit: 200,
                validators: {}
            });

            that.collection = ko.observableArray(_.map(data, function (item) {
                return new Model(item, that.restClient, that.options);
            }));

            that.index = {};
            if (that.options.id) {
                that.index.id = ko.computed(function () {
                    return _.indexBy(that.collection(), function (item) {
                        var idProperty = item.model[that.options.id];
                        return idProperty && idProperty();
                    });
                });
            }

            function manyToManyMap(source, first, second) {
                return _.each(_.groupBy(source, first), function (group, key, collection) {
                    collection[key] = _.indexBy(group, second);
                });
            }

            _.forEach(that.options.indexes, function (index) {
                if (_.isArray(index) && index.length === 2) {
                    that.index[index[0] + ':' + index[1]] = ko.computed(function () {
                        return manyToManyMap(that.collection(), function (item) {
                            var indexProperty = item.model[index[0]];
                            return indexProperty && indexProperty();
                        }, function (item) {
                            var indexProperty = item.model[index[1]];
                            return indexProperty && indexProperty();
                        });
                    });
                } else {
                    that.index[index] = ko.computed(function () {
                        _.indexBy(that.collection(), function (item) {
                            var indexProperty = item.model[index];
                            return indexProperty && indexProperty();
                        });
                    });
                }
            });
        }

        Class.prototype.map = function (data) {
            var that = this;
            var toDelete = _.difference(_.keys(that.index.id()), _.pluck(data, that.options.id));
            _.forEach(toDelete, function (id) {
                that.collection.remove(that.index.id()[id]);
            });
            _.forEach(data, function (newItem) {
                var oldItem = that.index.id()[newItem[that.options.id]];
                if (!oldItem) {
                    that.collection.push(new Model(newItem, that.restClient, that.options));
                } else {
                    oldItem.map(newItem);
                }
            });
            return that;
        };

        Class.prototype.commit = function () {
            var that = this;
            _.forEach(that.collection(), function (item) {
                if (item.isDirty()) {
                    item.commit();
                }
            });
        };

        Class.prototype.fetch = function () {
            var that = this;
            return that.restClient.get()
                .then(function (newData) {
                    that.map(newData);
                    return that;
                });
        };

        Class.prototype.create = function (data) {
            var that = this;
            var newItem = new Model(data, that.restClient, that.options);
            that.collection.push(newItem);
            return newItem;
        };

        Class.prototype.del = function (id) {
            var that = this;
            if (!id) {
                throw new Error('"id" argument is required');
            }
            var item = that.index.id()[id];
            item.del();
            that.collection.remove(item);
            return item;
        };

        return Class;
    }());

    exports.Rest = Rest;
    exports.RestStub = RestStub;

    exports.LocalStorageRestDecorator = LocalStorageRestDecorator;
    exports.CachedRestDecorator = CachedRestDecorator;

    exports.Model = Model;
    exports.Collection = Collection;
}));<|endoftext|>


<commit_before>import {
  ensAbiArray,
  auctionRegistrarAbiArray,
  deedAbiArray,
  fifsRegistrarAbiArray,
  resolverAbiArray,
  reverseRegistrarAbiArray
} from './abiArray';

const Web3 = require('web3');
const web3 = new Web3();

console.log("PROVIDER", process.env.REACT_APP_PROVIDER);

web3.setProvider(new web3.providers.HttpProvider(process.env.REACT_APP_PROVIDER));

//TODO: should move to util.js ?
export const getHexHash = (hash) => web3.sha3(hash, {encoding: 'hex'});

export const getHash = (hash) => web3.sha3(hash);

export const getNameHexHash = (name) => {
  let node = '0x0000000000000000000000000000000000000000000000000000000000000000';
  if (name === '') return node;

  for (const label of name.split('.').reverse()) {
    const more = getHash(label).slice(2);
    node = getHexHash(node + more);
  }

  return node;
};

// Get ensContract instance
export const ens = () => {
  const ensContract = web3.eth.contract(ensAbiArray);

  // instantiate by address
  return ensContract.at(process.env.REACT_APP_ENS_ADDRESS);
};

export const ethRegistrar = () => {
  const node = getNameHexHash('eth');
  const address = ens().owner(node);
  const auctionRegistrarContract = web3.eth.contract(auctionRegistrarAbiArray);
  return auctionRegistrarContract.at(address);
};

export const testRegistrar = () => {
  const node = getNameHexHash('test');
  const address = ens().owner(node);
  const fifsRegistrarContract = web3.eth.contract(fifsRegistrarAbiArray);
  return fifsRegistrarContract.at(address);
};

const getResolverContract = () => web3.eth.contract(resolverAbiArray);

export const getAddr = (name) => {
  const node = getNameHexHash(name);
  const resolverAddress = ens().resolver(node);
  const defaultAddress = '0x0000000000000000000000000000000000000000';

  return (resolverAddress === defaultAddress)
    ? defaultAddress
    : getResolverContract().at(resolverAddress).addr(node);
};

export const publicResolver = () => {
  const publicResolverAddress = process.env.REACT_APP_PUBLIC_RESOLVER || getAddr('resolver.eth');
  return getResolverContract().at(publicResolverAddress);
};

export const reverseRegistrar = () => {
  const node = getNameHexHash('addr.reverse');
  const address = ens().owner(node);
  const reverseRegistrarContract = web3.eth.contract(reverseRegistrarAbiArray);
  return  reverseRegistrarContract.at(address);
};

export const getContent = (name) => {
  const node = getNameHexHash(name);
  const resolverAddress =  ens().resolver(node);
  const defaultAddress = '0x0000000000000000000000000000000000000000';
  const defaultContent = '0x0000000000000000000000000000000000000000000000000000000000000000';

  return (resolverAddress === defaultAddress)
    ? defaultContent
    : getResolverContract().at(resolverAddress).content(node);
};

function Contracts() {}

Contracts.prototype.namehash = function(name) {
    var node = '0x0000000000000000000000000000000000000000000000000000000000000000';
    if (name !== '') {
        var labels = name.split(".");
        for(var i = labels.length - 1; i >= 0; i--) {
            node = web3.sha3(node + web3.sha3(labels[i]).slice(2), {encoding: 'hex'});
        }
    }
    return node.toString();
}

const ensContract = web3.eth.contract(ensAbiArray);

Contracts.prototype.ens = ensContract.at(process.env.REACT_APP_ENS_ADDRESS);

const auctionRegistrarContract = web3.eth.contract(auctionRegistrarAbiArray);

Contracts.prototype.ethRegistrar = auctionRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('eth')));

const deedContract = web3.eth.contract(deedAbiArray);

const fifsRegistrarContract = web3.eth.contract(fifsRegistrarAbiArray);

Contracts.prototype.testRegistrar = fifsRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('test')));

const resolverContract = web3.eth.contract(resolverAbiArray);

Contracts.prototype.getAddr = function(name) {
  var node = Contracts.prototype.namehash(name)
  var resolverAddress = Contracts.prototype.ens.resolver(node);
  console.log("resolverAddress", resolverAddress);
  if (resolverAddress === '0x0000000000000000000000000000000000000000') {
    return resolverAddress;
  }
  return resolverContract.at(resolverAddress).addr(node);
}

let publicResolverAddress = process.env.REACT_APP_PUBLIC_RESOLVER || Contracts.prototype.getAddr('resolver.eth');
Contracts.prototype.publicResolver = resolverContract.at(publicResolverAddress);

const reverseRegistrarContract = web3.eth.contract(reverseRegistrarAbiArray);
Contracts.prototype.reverseRegistrar = reverseRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('addr.reverse')));

Contracts.prototype.getContent = function(name) {
  var node = Contracts.prototype.namehash(name)
  var resolverAddress = Contracts.prototype.ens.resolver(node);
  if (resolverAddress === '0x0000000000000000000000000000000000000000') {
    return "0x0000000000000000000000000000000000000000000000000000000000000000";
  }
  return resolverContract.at(resolverAddress).content(node);
}

export const contracts = new Contracts();
<commit_msg>Make the warning view can be displayed.<commit_after>import {
  ensAbiArray,
  auctionRegistrarAbiArray,
  deedAbiArray,
  fifsRegistrarAbiArray,
  resolverAbiArray,
  reverseRegistrarAbiArray
} from './abiArray';

const Web3 = require('web3');
const web3 = new Web3();

console.log("REACT_APP_PROVIDER", process.env.REACT_APP_PROVIDER);

//TODO: error handling.
if (process.env.REACT_APP_PROVIDER) {
  web3.setProvider(new web3.providers.HttpProvider(process.env.REACT_APP_PROVIDER));
}

export const getHexHash = (hash) => web3.sha3(hash, {encoding: 'hex'});

export const getHash = (hash) => web3.sha3(hash);

export const getNameHexHash = (name) => {
  let node = '0x0000000000000000000000000000000000000000000000000000000000000000';
  if (name === '') return node;

  for (const label of name.split('.').reverse()) {
    const more = getHash(label).slice(2);
    node = getHexHash(node + more);
  }

  return node;
};

// Get ensContract instance
export const ens = () => {
  const ensContract = web3.eth.contract(ensAbiArray);

  // instantiate by address
  return ensContract.at(process.env.REACT_APP_ENS_ADDRESS);
};

export const ethRegistrar = () => {
  const node = getNameHexHash('eth');
  const address = ens().owner(node);
  const auctionRegistrarContract = web3.eth.contract(auctionRegistrarAbiArray);
  return auctionRegistrarContract.at(address);
};

export const testRegistrar = () => {
  const node = getNameHexHash('test');
  const address = ens().owner(node);
  const fifsRegistrarContract = web3.eth.contract(fifsRegistrarAbiArray);
  return fifsRegistrarContract.at(address);
};

const getResolverContract = () => web3.eth.contract(resolverAbiArray);

export const getAddr = (name) => {
  const node = getNameHexHash(name);
  const resolverAddress = ens().resolver(node);
  const defaultAddress = '0x0000000000000000000000000000000000000000';

  return (resolverAddress === defaultAddress)
    ? defaultAddress
    : getResolverContract().at(resolverAddress).addr(node);
};

export const publicResolver = () => {
  const publicResolverAddress = process.env.REACT_APP_PUBLIC_RESOLVER || getAddr('resolver.eth');
  return getResolverContract().at(publicResolverAddress);
};

export const reverseRegistrar = () => {
  const node = getNameHexHash('addr.reverse');
  const address = ens().owner(node);
  const reverseRegistrarContract = web3.eth.contract(reverseRegistrarAbiArray);
  return  reverseRegistrarContract.at(address);
};

export const getContent = (name) => {
  const node = getNameHexHash(name);
  const resolverAddress =  ens().resolver(node);
  const defaultAddress = '0x0000000000000000000000000000000000000000';
  const defaultContent = '0x0000000000000000000000000000000000000000000000000000000000000000';

  return (resolverAddress === defaultAddress)
    ? defaultContent
    : getResolverContract().at(resolverAddress).content(node);
};

function Contracts() {}

Contracts.prototype.namehash = function(name) {
    var node = '0x0000000000000000000000000000000000000000000000000000000000000000';
    if (name !== '') {
        var labels = name.split(".");
        for(var i = labels.length - 1; i >= 0; i--) {
            node = web3.sha3(node + web3.sha3(labels[i]).slice(2), {encoding: 'hex'});
        }
    }
    return node.toString();
}

const ensContract = web3.eth.contract(ensAbiArray);

Contracts.prototype.ens = ensContract.at(process.env.REACT_APP_ENS_ADDRESS);

const auctionRegistrarContract = web3.eth.contract(auctionRegistrarAbiArray);

Contracts.prototype.ethRegistrar = auctionRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('eth')));

const deedContract = web3.eth.contract(deedAbiArray);

const fifsRegistrarContract = web3.eth.contract(fifsRegistrarAbiArray);

Contracts.prototype.testRegistrar = fifsRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('test')));

const resolverContract = web3.eth.contract(resolverAbiArray);

Contracts.prototype.getAddr = function(name) {
  var node = Contracts.prototype.namehash(name)
  var resolverAddress = Contracts.prototype.ens.resolver(node);
  console.log("resolverAddress", resolverAddress);
  if (resolverAddress === '0x0000000000000000000000000000000000000000') {
    return resolverAddress;
  }
  return resolverContract.at(resolverAddress).addr(node);
}

let publicResolverAddress = process.env.REACT_APP_PUBLIC_RESOLVER || Contracts.prototype.getAddr('resolver.eth');
Contracts.prototype.publicResolver = resolverContract.at(publicResolverAddress);

const reverseRegistrarContract = web3.eth.contract(reverseRegistrarAbiArray);
Contracts.prototype.reverseRegistrar = reverseRegistrarContract.at(Contracts.prototype.ens.owner(Contracts.prototype.namehash('addr.reverse')));

Contracts.prototype.getContent = function(name) {
  var node = Contracts.prototype.namehash(name)
  var resolverAddress = Contracts.prototype.ens.resolver(node);
  if (resolverAddress === '0x0000000000000000000000000000000000000000') {
    return "0x0000000000000000000000000000000000000000000000000000000000000000";
  }
  return resolverContract.at(resolverAddress).content(node);
}

export const contracts = new Contracts();
<|endoftext|>