<commit_before>import { FileLoader, Vector2 } from '../Three';
import { Cfg } from '../core/lib';

function EPSG4326TileSet( tileSetReady, crs ) {

	this.CRS = crs;
	this.transform = proj4( crs, 'EPSG:4326' ); // eslint-disable-line no-undef

	const self = this;

	const accessToken = Cfg.value( 'cesiumAccessToken', 'no access token' );
	const url = 'https://api.cesium.com/v1/assets/1/endpoint?access_token=' + accessToken;

	new FileLoader().setResponseType( 'text' ).load( url, _getEndpoint, function () {}, _apiError );

	function _getEndpoint ( text ) {

		const endpoint = JSON.parse( text );

		self.url = endpoint.url;
		self.accessToken = endpoint.accessToken;

		tileSetReady();

	}

	function _apiError ( ) {

		console.warn( 'cesium api error' );

	}

}

EPSG4326TileSet.defaultTileSet = {
	title: 'Cesium',
	dtmMaxZoom: 16,
	maxZoom: 16,
	minZoom: 10,
	divisions: 1,
	directory: null,
	subdirectory: null,
	dtmScale: 64,
	minX: 0,
	maxX: 1023,
	minY: 0,
	maxY: 1023,
	attributions: [],
	log: true
};

EPSG4326TileSet.prototype.workerScript = 'webMeshWorker.js';

EPSG4326TileSet.prototype.getTileSets = function () {

	return [ EPSG4326TileSet.defaultTileSet ];

};

EPSG4326TileSet.prototype.getCoverage = function () {

	const min = new Vector2();
	const max = new Vector2();

	return function getCoverage ( limits, zoom ) {

		this.limits = limits;

		const coverage = { zoom: zoom };

		const S = - 90;
		const W = - 180;

		min.copy( limits.min );
		max.copy( limits.max );

		min.copy( this.transform.forward( min ) );
		max.copy( this.transform.forward( max ) );

		const tileCount = Math.pow( 2, zoom ) / 180; // tile count per degree

		coverage.min_x = Math.floor( ( min.x - W ) * tileCount );
		coverage.max_x = Math.floor( ( max.x - W ) * tileCount );

		coverage.min_y = Math.floor( ( min.y - S ) * tileCount );
		coverage.max_y = Math.floor( ( max.y - S ) * tileCount );

		coverage.count = ( coverage.max_x - coverage.min_x + 1 ) * ( coverage.max_y - coverage.min_y + 1 );

		return coverage;

	};

}();

EPSG4326TileSet.prototype.getTileSpec = function ( x, y, z /* limits */ ) {

	// trim excess off sides of tile where overlapping with region

	return {
		tileSet: this.tileSet,
		divisions: 1,
		resolution: 180 / Math.pow( 2, z ),
		x: x,
		y: y,
		z: z,
		clip: this.limits,
		offsets: null,
		flatZ: null,
		displayCRS: this.CRS,
		url: this.url,
		accessToken: this.accessToken,
		clippedFraction: 1
	};

};

export { EPSG4326TileSet };

// EOF<commit_msg>avoid loading tiles that will be clipped<commit_after>import { FileLoader, Box2 } from '../Three';
import { Cfg } from '../core/lib';

function EPSG4326TileSet( tileSetReady, crs ) {

	this.CRS = crs;
	this.transform = proj4( crs, 'EPSG:4326' ); // eslint-disable-line no-undef

	// survey limits

	this.transformedLimits = null;

	const self = this;

	const accessToken = Cfg.value( 'cesiumAccessToken', 'no access token' );
	const url = 'https://api.cesium.com/v1/assets/1/endpoint?access_token=' + accessToken;

	new FileLoader().setResponseType( 'text' ).load( url, _getEndpoint, function () {}, _apiError );

	function _getEndpoint ( text ) {

		const endpoint = JSON.parse( text );

		self.url = endpoint.url;
		self.accessToken = endpoint.accessToken;

		tileSetReady();

	}

	function _apiError ( ) {

		console.warn( 'cesium api error' );

	}

}

EPSG4326TileSet.defaultTileSet = {
	title: 'Cesium',
	dtmMaxZoom: 16,
	maxZoom: 16,
	minZoom: 10,
	divisions: 1,
	directory: null,
	subdirectory: null,
	dtmScale: 64,
	minX: 0,
	maxX: 1023,
	minY: 0,
	maxY: 1023,
	attributions: [],
	log: true
};

EPSG4326TileSet.prototype.workerScript = 'webMeshWorker.js';

EPSG4326TileSet.prototype.getTileSets = function () {

	return [ EPSG4326TileSet.defaultTileSet ];

};

EPSG4326TileSet.prototype.getCoverage = function ( limits, zoom ) {

	const coverage = { zoom: zoom };

	const S = - 90;
	const W = - 180;

	if ( this.transformedLimits === null ) {

		this.transformedLimits = new Box2();

	}

	const transformedLimits =  this.transformedLimits;

	const min = transformedLimits.min;
	const max = transformedLimits.max;

	min.copy( limits.min );
	max.copy( limits.max );

	min.copy( this.transform.forward( min ) );
	max.copy( this.transform.forward( max ) );

	const tileCount = Math.pow( 2, zoom ) / 180; // tile count per degree

	coverage.min_x = Math.floor( ( min.x - W ) * tileCount );
	coverage.max_x = Math.floor( ( max.x - W ) * tileCount );

	coverage.min_y = Math.floor( ( min.y - S ) * tileCount );
	coverage.max_y = Math.floor( ( max.y - S ) * tileCount );

	coverage.count = ( coverage.max_x - coverage.min_x + 1 ) * ( coverage.max_y - coverage.min_y + 1 );

	return coverage;

};

EPSG4326TileSet.prototype.getTileSpec = function ( x, y, z, limits ) {

	const tileBox = new Box2();

	const S = - 90;
	const W = - 180;

	// ensure tile is within survey limits

	const tileSize = 180 / Math.pow( 2, z ); // tileSize

	tileBox.min.x = W + x * tileSize;
	tileBox.min.y = S + y * tileSize;

	tileBox.max.x = W + ( x + 1) * tileSize;
	tileBox.max.y = S + ( y + 1 ) * tileSize;

	if ( ! this.transformedLimits.intersectsBox( tileBox ) ) return null;

	return {
		tileSet: this.tileSet,
		divisions: 1,
		resolution: tileSize,
		x: x,
		y: y,
		z: z,
		clip: limits,
		offsets: null,
		flatZ: null,
		displayCRS: this.CRS,
		url: this.url,
		accessToken: this.accessToken,
		clippedFraction: 1
	};

};

export { EPSG4326TileSet };

// EOF<|endoftext|>


<commit_before>L.Handler.PolyEdit = L.Handler.extend({
	options: {
		icon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon'
		})
	},

	initialize: function (poly, options) {
		this._poly = poly;
		L.Util.setOptions(this, options);
	},

	addHooks: function () {
		if (this._poly._map) {
			if (!this._markerGroup) {
				this._initMarkers();
			}
			this._poly._map.addLayer(this._markerGroup);
		}
	},

	removeHooks: function () {
		if (this._poly._map) {
			this._poly._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
			delete this._markers;
		}
	},

	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		this._markerGroup = new L.LayerGroup();
		this._markers = [];

		var latlngs = this._poly._latlngs,
		    i, j, len, marker;

		// TODO refactor holes implementation in Polygon to support it here

		for (i = 0, len = latlngs.length; i < len; i++) {

			marker = this._createMarker(latlngs[i], i);
			marker.on('click', this._onMarkerClick, this);
			this._markers.push(marker);
		}

		var markerLeft, markerRight;

		for (i = 0, j = len - 1; i < len; j = i++) {
			if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
				continue;
			}

			markerLeft = this._markers[j];
			markerRight = this._markers[i];

			this._createMiddleMarker(markerLeft, markerRight);
			this._updatePrevNext(markerLeft, markerRight);
		}
	},

	_createMarker: function (latlng, index) {
		var marker = new L.Marker(latlng, {
			draggable: true,
			icon: this.options.icon
		});

		marker._origLatLng = latlng;
		marker._index = index;

		marker.on('drag', this._onMarkerDrag, this);
		marker.on('dragend', this._fireEdit, this);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_fireEdit: function () {
		this._poly.fire('edit');
	},

	_onMarkerDrag: function (e) {
		var marker = e.target;

		L.Util.extend(marker._origLatLng, marker._latlng);

		if (marker._middleLeft) {
			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
		}
		if (marker._middleRight) {
			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
		}

		this._poly.redraw();
	},

	_onMarkerClick: function (e) {
		// Default action on marker click is to remove that marker, but if we remove the marker when latlng count < 3, we don't have a valid polyline anymore
		if (this._poly._latlngs.length < 3) {
			return;
		}

		var marker = e.target,
		    i = marker._index;

		// Check existence of previous and next markers since they wouldn't exist for edge points on the polyline
		if (marker._prev && marker._next) {
			this._createMiddleMarker(marker._prev, marker._next);
			this._updatePrevNext(marker._prev, marker._next);
		}

		// The marker itself is guaranteed to exist and present in the layer, since we managed to click on it
		this._markerGroup.removeLayer(marker);
		// Check for the existence of middle left or middle right
		if (marker._middleLeft) {
			this._markerGroup.removeLayer(marker._middleLeft);
		}
		if (marker._middleRight) {
			this._markerGroup.removeLayer(marker._middleRight);
		}
		this._markers.splice(i, 1);
		this._poly.spliceLatLngs(i, 1);
		this._updateIndexes(i, -1);
		this._poly.fire('edit');
	},

	_updateIndexes: function (index, delta) {
		this._markerGroup._iterateLayers(function (marker) {
			if (marker._index > index) {
				marker._index += delta;
			}
		});
	},

	_createMiddleMarker: function (marker1, marker2) {
		var latlng = this._getMiddleLatLng(marker1, marker2),
			marker = this._createMarker(latlng),
			onClick,
			onDragStart,
			onDragEnd;

		marker.setOpacity(0.6);

		marker1._middleRight = marker2._middleLeft = marker;

		onDragStart = function () {
			var i = marker2._index;

			marker._index = i;

			marker
				.off('click', onClick)
				.on('click', this._onMarkerClick, this);

			this._poly.spliceLatLngs(i, 0, latlng);
			this._markers.splice(i, 0, marker);

			marker.setOpacity(1);

			this._updateIndexes(i, 1);
			marker2._index++;
			this._updatePrevNext(marker1, marker);
			this._updatePrevNext(marker, marker2);
		};

		onDragEnd = function () {
			marker.off('dragstart', onDragStart, this);
			marker.off('dragend', onDragEnd, this);

			this._createMiddleMarker(marker1, marker);
			this._createMiddleMarker(marker, marker2);
		};

		onClick = function () {
			onDragStart.call(this);
			onDragEnd.call(this);
			this._poly.fire('edit');
		};

		marker
			.on('click', onClick, this)
			.on('dragstart', onDragStart, this)
			.on('dragend', onDragEnd, this);

		this._markerGroup.addLayer(marker);
	},

	_updatePrevNext: function (marker1, marker2) {
		marker1._next = marker2;
		marker2._prev = marker1;
	},

	_getMiddleLatLng: function (marker1, marker2) {
		var map = this._poly._map,
		    p1 = map.latLngToLayerPoint(marker1.getLatLng()),
		    p2 = map.latLngToLayerPoint(marker2.getLatLng());

		return map.layerPointToLatLng(p1._add(p2).divideBy(2));
	}
});
<commit_msg>polyline: Fix old position of middle point<commit_after>L.Handler.PolyEdit = L.Handler.extend({
	options: {
		icon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon'
		})
	},

	initialize: function (poly, options) {
		this._poly = poly;
		L.Util.setOptions(this, options);
	},

	addHooks: function () {
		if (this._poly._map) {
			if (!this._markerGroup) {
				this._initMarkers();
			}
			this._poly._map.addLayer(this._markerGroup);
		}
	},

	removeHooks: function () {
		if (this._poly._map) {
			this._poly._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
			delete this._markers;
		}
	},

	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		this._markerGroup = new L.LayerGroup();
		this._markers = [];

		var latlngs = this._poly._latlngs,
		    i, j, len, marker;

		// TODO refactor holes implementation in Polygon to support it here

		for (i = 0, len = latlngs.length; i < len; i++) {

			marker = this._createMarker(latlngs[i], i);
			marker.on('click', this._onMarkerClick, this);
			this._markers.push(marker);
		}

		var markerLeft, markerRight;

		for (i = 0, j = len - 1; i < len; j = i++) {
			if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
				continue;
			}

			markerLeft = this._markers[j];
			markerRight = this._markers[i];

			this._createMiddleMarker(markerLeft, markerRight);
			this._updatePrevNext(markerLeft, markerRight);
		}
	},

	_createMarker: function (latlng, index) {
		var marker = new L.Marker(latlng, {
			draggable: true,
			icon: this.options.icon
		});

		marker._origLatLng = latlng;
		marker._index = index;

		marker.on('drag', this._onMarkerDrag, this);
		marker.on('dragend', this._fireEdit, this);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_fireEdit: function () {
		this._poly.fire('edit');
	},

	_onMarkerDrag: function (e) {
		var marker = e.target;

		L.Util.extend(marker._origLatLng, marker._latlng);

		if (marker._middleLeft) {
			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
		}
		if (marker._middleRight) {
			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
		}

		this._poly.redraw();
	},

	_onMarkerClick: function (e) {
		// Default action on marker click is to remove that marker, but if we remove the marker when latlng count < 3, we don't have a valid polyline anymore
		if (this._poly._latlngs.length < 3) {
			return;
		}

		var marker = e.target,
		    i = marker._index;

		// Check existence of previous and next markers since they wouldn't exist for edge points on the polyline
		if (marker._prev && marker._next) {
			this._createMiddleMarker(marker._prev, marker._next);
			this._updatePrevNext(marker._prev, marker._next);
		}

		// The marker itself is guaranteed to exist and present in the layer, since we managed to click on it
		this._markerGroup.removeLayer(marker);
		// Check for the existence of middle left or middle right
		if (marker._middleLeft) {
			this._markerGroup.removeLayer(marker._middleLeft);
		}
		if (marker._middleRight) {
			this._markerGroup.removeLayer(marker._middleRight);
		}
		this._markers.splice(i, 1);
		this._poly.spliceLatLngs(i, 1);
		this._updateIndexes(i, -1);
		this._poly.fire('edit');
	},

	_updateIndexes: function (index, delta) {
		this._markerGroup._iterateLayers(function (marker) {
			if (marker._index > index) {
				marker._index += delta;
			}
		});
	},

	_createMiddleMarker: function (marker1, marker2) {
		var latlng = this._getMiddleLatLng(marker1, marker2),
			marker = this._createMarker(latlng),
			onClick,
			onDragStart,
			onDragEnd;

		marker.setOpacity(0.6);

		marker1._middleRight = marker2._middleLeft = marker;

		onDragStart = function () {
			var i = marker2._index;

			marker._index = i;

			marker
				.off('click', onClick)
				.on('click', this._onMarkerClick, this);

			latlng.lat = marker.getLatLng().lat;
			latlng.lng = marker.getLatLng().lng;
			this._poly.spliceLatLngs(i, 0, latlng);
			this._markers.splice(i, 0, marker);

			marker.setOpacity(1);

			this._updateIndexes(i, 1);
			marker2._index++;
			this._updatePrevNext(marker1, marker);
			this._updatePrevNext(marker, marker2);
		};

		onDragEnd = function () {
			marker.off('dragstart', onDragStart, this);
			marker.off('dragend', onDragEnd, this);

			this._createMiddleMarker(marker1, marker);
			this._createMiddleMarker(marker, marker2);
		};

		onClick = function () {
			onDragStart.call(this);
			onDragEnd.call(this);
			this._poly.fire('edit');
		};

		marker
			.on('click', onClick, this)
			.on('dragstart', onDragStart, this)
			.on('dragend', onDragEnd, this);

		this._markerGroup.addLayer(marker);
	},

	_updatePrevNext: function (marker1, marker2) {
		marker1._next = marker2;
		marker2._prev = marker1;
	},

	_getMiddleLatLng: function (marker1, marker2) {
		var map = this._poly._map,
		    p1 = map.latLngToLayerPoint(marker1.getLatLng()),
		    p2 = map.latLngToLayerPoint(marker2.getLatLng());

		return map.layerPointToLatLng(p1._add(p2).divideBy(2));
	}
});
<|endoftext|>


<commit_before>(function(){
	"use strict";

	window.KC3DataBackup = {
			saveData : function(elementkey,callback){//Save All Data to file
				var fullDBData={};
				var locked=false;
				var fullStorageData={};
				var zip = new JSZip();

				$(elementkey).append("Exporting Data...(0/3)");
				for(var i=0;i<localStorage.length;i++)
				{
					var name = localStorage.key(i);
					fullStorageData[name] = localStorage.getItem(name);
				}

				KC3Database.con.transaction("r", KC3Database.con.tables, function(){
					$(elementkey).append("
Loading Data to array...(1/4)
");
					KC3Database.con.tables.forEach( //access all tables
						function(table){
							table.toArray(function(tablearray) { //add table data tmptext
									while(locked){}
									locked = true;
									fullDBData[table.name] = tablearray;
									locked = false;
							});
					});//foreach
				}).then(function(){//for transaction
					$(elementkey).append("
Loading Data to zip...(2/4)
");
					zip.file("db.json",JSON.stringify(fullDBData));
					zip.file("storage.json",JSON.stringify(fullStorageData));

					$(elementkey).append("
compressing zip....(3/4)
");
					var objurl= URL.createObjectURL(zip.generate({type:"blob", compression: "DEFLATE"}));

					$(elementkey).append("
downloading zip....(4/4)
");
					console.info("downloading file to "+ConfigManager.ss_directory+'/Backup/');

					chrome.downloads.download({
						url: objurl,
						filename: ConfigManager.ss_directory+'/Backup/'+
						"["+PlayerManager.hq.name+"] "+
						dateFormat("yyyy-mm-dd")+".kc3data",
						conflictAction: "uniquify"
					}, function(downloadId){
					});
					callback();
				});//transaction

			},//savedata

			processDB : function(dbstring,overwrite,elementkey,callback){//load data from DB string

				var dbdata = JSON.parse(dbstring);
                $(elementkey).text("");
				var processTables = function(dbdata_){
					var dothing = function(){
						var tableCount = -1;
						console.log("processing tables...");
						KC3Database.init();
						KC3Database.con.open();
            $(elementkey).append("
-DB Transaction Started-
");
						var alertwhenfinished = function() {
								setTimeout(function()
								{
									if(tableCount==0)  callback();
									else alertwhenfinished();
								}
						,1000)};
						alertwhenfinished();

						$.each(dbdata_,function(index,tabledata) {
							var table = KC3Database.con[index];
                console.log(">queued "+index+"『size : "+tabledata.length+"』");
                $(elementkey).append("
queued "+index+" 『size : "+tabledata.length+"』
");
								KC3Database.con.transaction("rw!",table,function(){
								console.log("processing "+index+" 『size : "+tabledata.length+"』");
								$(elementkey+" ."+index).text("processing "+index+" 『size : "+tabledata.length+"』");

								if(tableCount == -1)tableCount=1;
								else tableCount++;

								table.clear();

								tabledata.forEach(function(record)
								{
									var id = record.id;
									delete record.id;
									table.add(record);
								});
								//console.log("processed " + index);
							}).then(function(){
                //console.log("processed " + index);
								$(elementkey+" ."+index).text("processed "+index);
							}).catch($(elementkey+" ."+index).text).finally(function(){tableCount--;});
						});//each
                        $(elementkey+" .datatransaction").text("=DB transaction all queued=");
					};//dothinh
				  dothing();

				};//processTables
				if(overwrite)
					processTables(dbdata);

				else processTables(dbdata);
			},//processDB

			processStorage: function(importedDataString){
				var data = JSON.parse(importedDataString);
				$.each(data, function(index,access){
					localStorage[index]=access;
				});
				console.info("done processing storage");
			},//processStorage

			loadData : function(file_,overwrite,elementkey,callback){
				var zip;
				var reader = new FileReader();
				reader.onload = (function(e) {
							// read the content of the file with JSZip
							zip = new JSZip(e.target.result);
							$.each(zip.files, function (index, zipEntry) {
								switch (zipEntry.name) {
									case "db.json":
										console.info("db.json detected.");
										setTimeout(function(){
                                            KC3DataBackup.processDB(zipEntry.asText(),overwrite,elementkey,callback);
                                        },0);
										break;
									case "storage.json":
										console.info("storage.json detected.");
										if(overwrite)
												setTimeout(function()
												{
                                                     $(elementkey).append("
-storage processing-
");
                                                    window.KC3DataBackup.processStorage(zipEntry.asText());
                                                     $(elementkey+" .localstorageprocess").text("=storage processed=");
                                                },10);
										break;
									default:
										alert("could be wrong file");

									}//swich: zip name
								});//file acces foreach
				});//reader.onload
				reader.readAsArrayBuffer(file_);
			}//loadData
	};
})();
<commit_msg>New loop method<commit_after>(function(){
	"use strict";

	window.KC3DataBackup = {
			saveData : function(elementkey,callback){//Save All Data to file
				var fullDBData={};
				var locked=false;
				var fullStorageData={};
				var zip = new JSZip();

				$(elementkey).append("Exporting Data...(0/3)");
				for(var i=0;i<localStorage.length;i++)
				{
					var name = localStorage.key(i);
					fullStorageData[name] = localStorage.getItem(name);
				}

				KC3Database.con.transaction("r", KC3Database.con.tables, function(){
					$(elementkey).append("
Loading Data to array...(1/4)
");
					KC3Database.con.tables.forEach( //access all tables
						function(table){
							table.toArray(function(tablearray) { //add table data tmptext
									while(locked){}
									locked = true;
									fullDBData[table.name] = tablearray;
									locked = false;
							});
					});//foreach
				}).then(function(){//for transaction
					$(elementkey).append("
Loading Data to zip...(2/4)
");
					zip.file("db.json",JSON.stringify(fullDBData));
					zip.file("storage.json",JSON.stringify(fullStorageData));

					$(elementkey).append("
compressing zip....(3/4)
");
					var objurl= URL.createObjectURL(zip.generate({type:"blob", compression: "DEFLATE"}));

					$(elementkey).append("
downloading zip....(4/4)
");
					console.info("downloading file to "+ConfigManager.ss_directory+'/Backup/');

					chrome.downloads.download({
						url: objurl,
						filename: ConfigManager.ss_directory+'/Backup/'+
						"["+PlayerManager.hq.name+"] "+
						dateFormat("yyyy-mm-dd")+".kc3data",
						conflictAction: "uniquify"
					}, function(downloadId){
					});
					callback();
				});//transaction

			},//savedata

			processDB : function(dbstring,overwrite,elementkey,callback){//load data from DB string

				var dbdata = JSON.parse(dbstring);
                $(elementkey).text("");
				var processTables = function(dbdata_){
					var dothing = function(){
						var tableCount = -1;
						console.log("processing tables...");
						KC3Database.init();
						KC3Database.con.open();
            $(elementkey).append("
-DB Transaction Started-
");
						var alertwhenfinished = function() {
								setTimeout(function()
								{
									if(tableCount==0)  callback();
									else alertwhenfinished();
								}
						,1000)};
						alertwhenfinished();

						$.each(dbdata_,function(index,tabledata) {
							$(elementkey).append("
queued "+index+" 『size : "+tabledata.length+"』
");
						});
						var arrEach = function(tableobj){
							var index = Object.keys(tableobj)[0];
							var tabledata = tableobj[index];
							var table = KC3Database.con[index];
							KC3Database.con.transaction("rw!",table,function(){
								console.log("processing "+index+" 『size : "+tabledata.length+"』");
								$(elementkey+" ."+index).text("processing "+index+" 『size : "+tabledata.length+"』");

								if(tableCount == -1)tableCount=1;
								else tableCount++;

								table.clear();

								tabledata.forEach(function(record)
								{
									var id = record.id;
									delete record.id;
									table.add(record);
								});
								//console.log("processed " + index);
							}).then(function(){
                //console.log("processed " + index);
								$(elementkey+" ."+index).text("processed "+index);
							}).catch($(elementkey+" ."+index).text).finally(function(){tableCount--;delete tableobj[index];arrEach(tableobj);});
						}//arreach
						arrEach(dbdata_);
                        $(elementkey+" .datatransaction").text("=DB transaction all queued=");
					};//dothinh
				  dothing();

				};//processTables
				if(overwrite)
					processTables(dbdata);

				else processTables(dbdata);
			},//processDB

			processStorage: function(importedDataString){
				var data = JSON.parse(importedDataString);
				$.each(data, function(index,access){
					localStorage[index]=access;
				});
				console.info("done processing storage");
			},//processStorage

			loadData : function(file_,overwrite,elementkey,callback){
				var zip;
				var reader = new FileReader();
				reader.onload = (function(e) {
							// read the content of the file with JSZip
							zip = new JSZip(e.target.result);
							$.each(zip.files, function (index, zipEntry) {
								switch (zipEntry.name) {
									case "db.json":
										console.info("db.json detected.");
										setTimeout(function(){
                                            KC3DataBackup.processDB(zipEntry.asText(),overwrite,elementkey,callback);
                                        },0);
										break;
									case "storage.json":
										console.info("storage.json detected.");
										if(overwrite)
												setTimeout(function()
												{
                                                     $(elementkey).append("
-storage processing-
");
                                                    window.KC3DataBackup.processStorage(zipEntry.asText());
                                                     $(elementkey+" .localstorageprocess").text("=storage processed=");
                                                },10);
										break;
									default:
										alert("could be wrong file");

									}//swich: zip name
								});//file acces foreach
				});//reader.onload
				reader.readAsArrayBuffer(file_);
			}//loadData
	};
})();
<|endoftext|>


<commit_before>function init(h,w) {
  $('#title').text(document.title);

  var radar = new pv.Panel()
      .width(w)
      .height(h)
      .canvas('radar')

// arcs
radar.add(pv.Dot)
       .data(radar_arcs)
       .left(w/2)
       .bottom(h/2)
       .radius(function(d){return d.r;})
       .strokeStyle("#ccc")
       .anchor("top")
       .add(pv.Label).text(function(d) { return d.name;});

//quadrant lines -- vertical
radar.add(pv.Line)
        .data([(h/2-radar_arcs[radar_arcs.length-1].r),h-(h/2-radar_arcs[radar_arcs.length-1].r)])
        .lineWidth(1)
        .left(w/2)
        .bottom(function(d) {return d;})
        .strokeStyle("#bbb");

//quadrant lines -- horizontal
radar.add(pv.Line)
        .data([(w/2-radar_arcs[radar_arcs.length-1].r),w-(w/2-radar_arcs[radar_arcs.length-1].r)])
        .lineWidth(1)
        .bottom(h/2)
        .left(function(d) {return d;})
        .strokeStyle("#bbb");

// blips
// var total_index=1;
// for (var i = 0; i < radar_data.length; i++) {
//     radar.add(pv.Dot)
//     .def("active", false)
//     .data(radar_data[i].items)
//     .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
//     .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
//                         //console.log("name:" + d.name + ", x:" + x);
//                         return x;})
//     .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
//                           //console.log("name:" + d.name + ", y:" + y);
//                           return y;})
//     .title(function(d) { return d.name;})
//     .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
//     .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
//     .angle(Math.PI)  // 180 degrees in radians !
//     .strokeStyle(radar_data[i].color)
//     .fillStyle(radar_data[i].color)
//     .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
//     .anchor("center")
//         .add(pv.Label)
//         .text(function(d) {return total_index++;})
//         .textBaseline("middle")
//         .textStyle("white");
// }

// Quadrant Ledgends.
var radar_quadrant_ctr=1;
var quadrantFontSize = 22;
var headingFontSize = 20;
var stageHeadingCount = 0;
var lastRadius = 0;
var lastQuadrant='';
var spacer = 6;
var fontSize = 16;
var total_index = 1;

// TODO: Super fragile: re-order the items, by radius, in order to logically group by the rings.
for (var i = 0; i < radar_data.length; i++) {
    // Adjust top by the number of headings.
    if (lastQuadrant != radar_data[i].quadrant) {
        radar.add(pv.Label)
            .left( radar_data[i].left )
            .top( radar_data[i].top )
            .text(  radar_data[i].quadrant )
            .strokeStyle( radar_data[i].color )
            .fillStyle( radar_data[i].color )
            .font(quadrantFontSize + "px sans-serif");

        lastQuadrant = radar_data[i].quadrant;

    }

    var itemsByStage = _.groupBy(radar_data[i].items, function(item) {return Math.floor(item.pc.r / 100)});
    var offsetIndex = 0;
    for (var stageIdx in _(itemsByStage).keys()) {

        if (stageIdx > 0) {
            var x = itemsByStage[stageIdx-1];
            var l = x? x.length : 0;
            offsetIndex = offsetIndex + l + 1;
        }

        radar.add(pv.Label)
            .left( radar_data[i].left + headingFontSize )
            .top( radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize) )
            .text( radar_arcs[stageIdx].name)
            .strokeStyle( '#cccccc' )
            .fillStyle( '#cccccc')
            .font(headingFontSize + "px Courier New");

    radar.add(pv.Label)
        .left( radar_data[i].left )
        .top( radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize) )
        .strokeStyle( radar_data[i].color )
        .fillStyle( radar_data[i].color )
        .add( pv.Dot )
            .def("i", radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + spacer  + (offsetIndex * fontSize) )
            .data(itemsByStage[stageIdx])
            .top( function() { return ( this.i() + (this.index * fontSize) );} )
            .shape( function(d) {return (d.movement === 't' ? "triangle" : "circle");})
            .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
            .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
            .size(fontSize)
            .angle(45)
            .anchor("right")
                .add(pv.Label)
                .text(function(d) {return radar_quadrant_ctr++ + ". " + d.name;} );

    radar.add(pv.Dot)
      .def("active", false)
      .data(itemsByStage[stageIdx])
      .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
      .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
                          //console.log("name:" + d.name + ", x:" + x);
                          return x;})
      .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
                            //console.log("name:" + d.name + ", y:" + y);
                            return y;})
      .title(function(d) { return d.name;})
      .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
      .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
      .angle(Math.PI)  // 180 degrees in radians !
      .strokeStyle(radar_data[i].color)
      .fillStyle(radar_data[i].color)
      .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
      .anchor("center")
          .add(pv.Label)
          .text(function(d) {return total_index++;})
          .textBaseline("middle")
          .textStyle("white");

    }
}

  radar.anchor('radar');
  radar.render();

};
<commit_msg>Whitespace only<commit_after>function init(h,w) {
  $('#title').text(document.title);

  var radar = new pv.Panel()
      .width(w)
      .height(h)
      .canvas('radar')

// arcs
radar.add(pv.Dot)
       .data(radar_arcs)
       .left(w/2)
       .bottom(h/2)
       .radius(function(d){return d.r;})
       .strokeStyle("#ccc")
       .anchor("top")
       .add(pv.Label).text(function(d) { return d.name;});

// Quadrant lines -- vertical.
radar.add(pv.Line)
        .data([(h/2-radar_arcs[radar_arcs.length-1].r),h-(h/2-radar_arcs[radar_arcs.length-1].r)])
        .lineWidth(1)
        .left(w/2)
        .bottom(function(d) {return d;})
        .strokeStyle("#bbb");

// Quadrant lines -- horizontal.
radar.add(pv.Line)
        .data([(w/2-radar_arcs[radar_arcs.length-1].r),w-(w/2-radar_arcs[radar_arcs.length-1].r)])
        .lineWidth(1)
        .bottom(h/2)
        .left(function(d) {return d;})
        .strokeStyle("#bbb");

// blips
// var total_index=1;
// for (var i = 0; i < radar_data.length; i++) {
//     radar.add(pv.Dot)
//     .def("active", false)
//     .data(radar_data[i].items)
//     .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
//     .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
//                         //console.log("name:" + d.name + ", x:" + x);
//                         return x;})
//     .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
//                           //console.log("name:" + d.name + ", y:" + y);
//                           return y;})
//     .title(function(d) { return d.name;})
//     .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
//     .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
//     .angle(Math.PI)  // 180 degrees in radians !
//     .strokeStyle(radar_data[i].color)
//     .fillStyle(radar_data[i].color)
//     .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
//     .anchor("center")
//         .add(pv.Label)
//         .text(function(d) {return total_index++;})
//         .textBaseline("middle")
//         .textStyle("white");
// }

// Quadrant Ledgends.
var radar_quadrant_ctr=1;
var quadrantFontSize = 22;
var headingFontSize = 20;
var stageHeadingCount = 0;
var lastRadius = 0;
var lastQuadrant='';
var spacer = 6;
var fontSize = 16;
var total_index = 1;

// TODO: Super fragile: re-order the items, by radius, in order to logically group by the rings.
for (var i = 0; i < radar_data.length; i++) {
    // Adjust top by the number of headings.
    if (lastQuadrant != radar_data[i].quadrant) {
        radar.add(pv.Label)
            .left(radar_data[i].left)
            .top(radar_data[i].top)
            .text(radar_data[i].quadrant)
            .strokeStyle(radar_data[i].color)
            .fillStyle(radar_data[i].color)
            .font(quadrantFontSize + "px sans-serif");

        lastQuadrant = radar_data[i].quadrant;
    }

    var itemsByStage = _.groupBy(radar_data[i].items, function(item) {return Math.floor(item.pc.r / 100)});
    var offsetIndex = 0;
    for (var stageIdx in _(itemsByStage).keys()) {

        if (stageIdx > 0) {
            var x = itemsByStage[stageIdx-1];
            var l = x? x.length : 0;
            offsetIndex = offsetIndex + l + 1;
        }

        radar.add(pv.Label)
            .left(radar_data[i].left + headingFontSize)
            .top(radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize))
            .text( radar_arcs[stageIdx].name)
            .strokeStyle('#cccccc')
            .fillStyle('#cccccc')
            .font(headingFontSize + "px Courier New");

    radar.add(pv.Label)
        .left(radar_data[i].left)
        .top(radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize))
        .strokeStyle(radar_data[i].color)
        .fillStyle(radar_data[i].color)
        .add(pv.Dot)
            .def("i", radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + spacer  + (offsetIndex * fontSize))
            .data(itemsByStage[stageIdx])
            .top(function() { return ( this.i() + (this.index * fontSize) );})
            .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
            .cursor(function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
            .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
            .size(fontSize)
            .angle(45)
            .anchor("right")
                .add(pv.Label)
                .text(function(d) {return radar_quadrant_ctr++ + ". " + d.name;} );

    radar.add(pv.Dot)
      .def("active", false)
      .data(itemsByStage[stageIdx])
      .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
      .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
                          //console.log("name:" + d.name + ", x:" + x);
                          return x;})
      .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
                            //console.log("name:" + d.name + ", y:" + y);
                            return y;})
      .title(function(d) { return d.name;})
      .cursor(function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
      .event("click", function(d) { if ( d.url !== undefined ){self.location =  d.url}})
      .angle(Math.PI)  // 180 degrees in radians !
      .strokeStyle(radar_data[i].color)
      .fillStyle(radar_data[i].color)
      .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
      .anchor("center")
          .add(pv.Label)
          .text(function(d) {return total_index++;})
          .textBaseline("middle")
          .textStyle("white");
    }
}

  radar.anchor('radar');
  radar.render();
};
<|endoftext|>


<commit_before>import JSONAPIAdapter from "ember-data/adapters/json-api";
import DataAdapterMixin from "ember-simple-auth/mixins/data-adapter-mixin";
import { isNone } from "@ember/utils";
import config from "ember-get-config";

export default JSONAPIAdapter.extend(DataAdapterMixin, {
  coalesceFindRequests: true,
  host: config.APP.goods.host,

  modelWhitelist: [
    "basket",
    "basket-item",
    "brand",
    "category",
    "country",
    "order",
    "order-line",
    "order-payment-method",
    "payment",
    "payment-method",
    "price",
    "product-category",
    "product-field",
    "product-image",
    "product",
    "promotion",
    "shop-member",
    "shop-payment-method",
    "shop-role",
    "state",
    "sku-field",
    "sku-image",
    "sku",
    "user"
  ],

  pathForType(type) {
    if (this.modelWhitelist.includes(type)) {
      return this._super(...arguments);
    }
    return "content/" + this._super(...arguments);
  },

  authorize(xhr) {
    let { access_token } = this.get("session.data.authenticated");
    if (isNone(access_token)) {
      access_token = config.APP.goods.apiKey;
    }
    xhr.setRequestHeader("Authorization", `Bearer ${access_token}`);
    xhr.setRequestHeader("Space-ID", config.APP.goods.spaceId);
  }
});
<commit_msg>Add support for legacy access_token<commit_after>import JSONAPIAdapter from "ember-data/adapters/json-api";
import DataAdapterMixin from "ember-simple-auth/mixins/data-adapter-mixin";
import { isNone } from "@ember/utils";
import config from "ember-get-config";

export default JSONAPIAdapter.extend(DataAdapterMixin, {
  coalesceFindRequests: true,
  host: config.APP.goods.host,

  modelWhitelist: [
    "basket",
    "basket-item",
    "brand",
    "category",
    "country",
    "order",
    "order-line",
    "order-payment-method",
    "payment",
    "payment-method",
    "price",
    "product-category",
    "product-field",
    "product-image",
    "product",
    "promotion",
    "shop-member",
    "shop-payment-method",
    "shop-role",
    "state",
    "sku-field",
    "sku-image",
    "sku",
    "user"
  ],

  pathForType(type) {
    if (this.modelWhitelist.includes(type)) {
      return this._super(...arguments);
    }
    return "content/" + this._super(...arguments);
  },

  authorize(xhr) {
    //Support legacy access_token
    if (!isNone(config.APP.goods.access_token)) {
      xhr.setRequestHeader(
        "Authorization",
        `Bearer ${config.APP.goods.access_token}`
      );
      return;
    }

    let { access_token } = this.get("session.data.authenticated");

    if (isNone(access_token)) {
      access_token = config.APP.goods.apiKey;
    }
    xhr.setRequestHeader("Authorization", `Bearer ${access_token}`);
    xhr.setRequestHeader("Space-ID", config.APP.goods.spaceId);
  }
});
<|endoftext|>


<commit_before>(function() {
	'use strict';

	function definition(path, Failure, handlerModule, isObject, merge) {
		var settings = { suffix: '.js' };

		demand
			.on('postConfigure:' + path, function(options) {
				if(isObject(options)) {
					merge(settings, options);
				}
			});

		function resolve() {
			var self  = this,
				dfd   = self.dfd,
				probe = settings[self.path] && settings[self.path].probe,
				result;

			handlerModule.process(self);

			function resolve(module) {
				provide(function() { return module; });
			}

			function reject() {
				dfd.reject(new Failure('error probing', self.path));
			}

			if(probe) {
				if((result = probe(resolve, reject))) {
					resolve(result);
				}
			} else {
				reject();
			}
		}

		function HandlerLegacy() {}

		HandlerLegacy.prototype = {
			onPreRequest: function(dependency, suffix) {
				var dependencies = settings[dependency.path] && settings[dependency.path].dependencies;

				suffix = (typeof suffix !== 'undefined') ? suffix : settings.suffix;

				handlerModule.onPreRequest(dependency, suffix || false);

				if(dependencies) {
					dependency.enqueue = demand.apply(null, dependencies);
				}
			},
			onPreProcess: function(dependency) {
				var dependencies = settings[dependency.path] && settings[dependency.path].dependencies;

				if(dependencies && typeof dependency.enqueue === 'boolean') {
					dependency.enqueue = demand.apply(null, dependencies);
				}
			},
			process: function(dependency) {
				var boundResolve = resolve.bind(dependency);

				if(dependency.enqueue === true) {
					boundResolve();
				} else {
					dependency.enqueue
						.then(
							boundResolve,
							function() {
								dependency.dfd.reject(new Failure('error resolving', dependency.path, arguments));
							}
						)
				}
			}
		};

		return new (HandlerLegacy.extends(handlerModule));
	}

	provide([ 'path', '/demand/failure', '/demand/handler/module', '/demand/validator/isObject', '/demand/function/merge' ], definition);
}());
<commit_msg>make legacy modules always resove with `true` if no probe is defined<commit_after>(function() {
	'use strict';

	function definition(path, Failure, handlerModule, isObject, merge) {
		var settings = { suffix: '.js' };

		demand
			.on('postConfigure:' + path, function(options) {
				if(isObject(options)) {
					merge(settings, options);
				}
			});

		function resolve() {
			var self  = this,
				dfd   = self.dfd,
				probe = settings[self.path] && settings[self.path].probe,
				result;

			handlerModule.process(self);

			function resolve(module) {
				provide(function() { return module; });
			}

			function reject() {
				dfd.reject(new Failure('error probing', self.path));
			}

			if(probe) {
				if((result = probe(resolve, reject))) {
					resolve(result);
				}
			} else {
				resolve(true);
			}
		}

		function HandlerLegacy() {}

		HandlerLegacy.prototype = {
			onPreRequest: function(dependency, suffix) {
				var dependencies = settings[dependency.path] && settings[dependency.path].dependencies;

				suffix = (typeof suffix !== 'undefined') ? suffix : settings.suffix;

				handlerModule.onPreRequest(dependency, suffix || false);

				if(dependencies) {
					dependency.enqueue = demand.apply(null, dependencies);
				}
			},
			onPreProcess: function(dependency) {
				var dependencies = settings[dependency.path] && settings[dependency.path].dependencies;

				if(dependencies && typeof dependency.enqueue === 'boolean') {
					dependency.enqueue = demand.apply(null, dependencies);
				}
			},
			process: function(dependency) {
				var boundResolve = resolve.bind(dependency);

				if(dependency.enqueue === true) {
					boundResolve();
				} else {
					dependency.enqueue
						.then(
							boundResolve,
							function() {
								dependency.dfd.reject(new Failure('error resolving', dependency.path, arguments));
							}
						)
				}
			}
		};

		return new (HandlerLegacy.extends(handlerModule));
	}

	provide([ 'path', '/demand/failure', '/demand/handler/module', '/demand/validator/isObject', '/demand/function/merge' ], definition);
}());
<|endoftext|>


<commit_before>/* globals Pikaday */
import Mixin from '@ember/object/mixin';

import { assign } from '@ember/polyfills';
import { isPresent } from '@ember/utils';
import { run } from '@ember/runloop';
import { getProperties, computed } from '@ember/object';
import moment from 'moment';

export default Mixin.create({
  _options: computed('options', 'i18n', {
    get() {
      let options = this._defaultOptions();

      if (isPresent(this.get('i18n'))) {
        if (isPresent(this.get('i18n').t)) {
          options.i18n = {
            previousMonth: this.get('i18n')
              .t('previousMonth')
              .toString(),
            nextMonth: this.get('i18n')
              .t('nextMonth')
              .toString(),
            months: this.get('i18n')
              .t('months')
              .toString()
              .split(','),
            weekdays: this.get('i18n')
              .t('weekdays')
              .toString()
              .split(','),
            weekdaysShort: this.get('i18n')
              .t('weekdaysShort')
              .toString()
              .split(',')
          };
        } else {
          options.i18n = this.get('i18n');
        }
      }
      if (isPresent(this.get('position'))) {
        options.position = this.get('position');
      }
      if (isPresent(this.get('reposition'))) {
        options.reposition = this.get('reposition');
      }

      assign(options, this.get('options') || {});
      return options;
    }
  }),

  _defaultOptions() {
    const firstDay = this.get('firstDay');

    return {
      field: this.get('field'),
      container: this.get('pikadayContainer'),
      bound: this.get('pikadayContainer') ? false : true,
      onOpen: run.bind(this, this.onPikadayOpen),
      onClose: run.bind(this, this.onPikadayClose),
      onSelect: run.bind(this, this.onPikadaySelect),
      onDraw: run.bind(this, this.onPikadayRedraw),
      firstDay: typeof firstDay !== 'undefined' ? parseInt(firstDay, 10) : 1,
      format: this.get('format') || 'DD.MM.YYYY',
      yearRange: this.determineYearRange(),
      minDate: this.get('minDate') || null,
      maxDate: this.get('maxDate') || null,
      defaultDate: this.get('defaultDate') || null,
      setDefaultDate: !!this.get('defaultDate'),
      theme: this.get('theme') || null
    };
  },

  /**
   * When updating attrs, we need to reset some things in case they've changed.
   * @public
   * @memberOf {Mixins.Pikaday}
   * @return {undefined}
   */
  didUpdateAttrs() {
    this.set(
      'cancelToken',
      run.later(() => {
        // Do not set or update anything when the component is destroying.
        if (this.get('isDestroying') || this.get('isDestroyed')) {
          return;
        }

        this.setMinDate();
        this.setMaxDate();
        this.setPikadayDate();

        if (this.get('options')) {
          this._updateOptions();
        }
      })
    );
  },

  didRender() {
    this._super();
    this.autoHideOnDisabled();
  },

  setupPikaday() {
    let pikaday = new Pikaday(this.get('_options'));

    if (this.get('defaultDate')) {
      this.set('value', this.get('defaultDate'));
    }

    this.set('pikaday', pikaday);
    this.setPikadayDate();
  },

  willDestroyElement() {
    this._super();
    this.get('pikaday').destroy();
    run.cancel(this.get('cancelToken'));
  },

  setPikadayDate: function() {
    const format = 'YYYY-MM-DD';
    const value = this.get('value');

    if (!value) {
      this.get('pikaday').setDate(value, true);
    } else {
      const date = this.get('useUTC')
        ? moment(moment.utc(value).format(format), format).toDate()
        : value;

      this.get('pikaday').setDate(date, true);
    }
  },

  setMinDate: function() {
    const { pikaday, minDate, value } = getProperties(this, [
      'pikaday',
      'minDate',
      'value'
    ]);

    if (minDate) {
      const _minDate = new Date(minDate.getTime());
      pikaday.setMinDate(_minDate);

      // If the current date is lower than minDate we set date to minDate
      run.schedule('sync', () => {
        if (
          value &&
          moment(value, this.get('format')).isBefore(minDate, 'day')
        ) {
          pikaday.setDate(minDate);
        }
      });
    } else {
      pikaday.setMinDate(null);
    }
  },

  setMaxDate: function() {
    const { pikaday, maxDate, value } = getProperties(this, [
      'pikaday',
      'maxDate',
      'value'
    ]);

    if (maxDate) {
      const _maxDate = new Date(maxDate.getTime());
      pikaday.setMaxDate(_maxDate);

      // If the current date is greater than maxDate we set date to maxDate
      run.schedule('sync', () => {
        if (value > maxDate) {
          pikaday.setDate(maxDate);
        }
      });
    } else {
      pikaday.setMaxDate(null);
    }
  },

  onOpen() {},
  onClose() {},
  onSelection() {},
  onDraw() {},

  onPikadaySelect: function() {
    this.userSelectedDate();
  },

  onPikadayRedraw: function() {
    this.get('onDraw')();
  },

  userSelectedDate: function() {
    var selectedDate = this.get('pikaday').getDate();

    if (this.get('useUTC')) {
      selectedDate = moment
        .utc([
          selectedDate.getFullYear(),
          selectedDate.getMonth(),
          selectedDate.getDate()
        ])
        .toDate();
    }

    this.get('onSelection')(selectedDate);
  },

  determineYearRange: function() {
    var yearRange = this.get('yearRange');

    if (yearRange) {
      if (yearRange.indexOf(',') > -1) {
        var yearArray = yearRange.split(',');

        if (yearArray[1] === 'currentYear') {
          yearArray[1] = new Date().getFullYear();
        }

        return yearArray;
      } else {
        return yearRange;
      }
    } else {
      return 10;
    }
  },

  autoHideOnDisabled() {
    if (this.get('disabled') && this.get('pikaday')) {
      this.get('pikaday').hide();
    }
  },

  _updateOptions() {
    this.get('pikaday').config(this.get('_options'));
  }
});
<commit_msg>fix: remove use of deprecated `sync` queue<commit_after>/* globals Pikaday */
import Mixin from '@ember/object/mixin';

import { assign } from '@ember/polyfills';
import { isPresent } from '@ember/utils';
import { run, next } from '@ember/runloop';
import { getProperties, computed } from '@ember/object';
import moment from 'moment';

export default Mixin.create({
  _options: computed('options', 'i18n', {
    get() {
      let options = this._defaultOptions();

      if (isPresent(this.get('i18n'))) {
        if (isPresent(this.get('i18n').t)) {
          options.i18n = {
            previousMonth: this.get('i18n')
              .t('previousMonth')
              .toString(),
            nextMonth: this.get('i18n')
              .t('nextMonth')
              .toString(),
            months: this.get('i18n')
              .t('months')
              .toString()
              .split(','),
            weekdays: this.get('i18n')
              .t('weekdays')
              .toString()
              .split(','),
            weekdaysShort: this.get('i18n')
              .t('weekdaysShort')
              .toString()
              .split(',')
          };
        } else {
          options.i18n = this.get('i18n');
        }
      }
      if (isPresent(this.get('position'))) {
        options.position = this.get('position');
      }
      if (isPresent(this.get('reposition'))) {
        options.reposition = this.get('reposition');
      }

      assign(options, this.get('options') || {});
      return options;
    }
  }),

  _defaultOptions() {
    const firstDay = this.get('firstDay');

    return {
      field: this.get('field'),
      container: this.get('pikadayContainer'),
      bound: this.get('pikadayContainer') ? false : true,
      onOpen: run.bind(this, this.onPikadayOpen),
      onClose: run.bind(this, this.onPikadayClose),
      onSelect: run.bind(this, this.onPikadaySelect),
      onDraw: run.bind(this, this.onPikadayRedraw),
      firstDay: typeof firstDay !== 'undefined' ? parseInt(firstDay, 10) : 1,
      format: this.get('format') || 'DD.MM.YYYY',
      yearRange: this.determineYearRange(),
      minDate: this.get('minDate') || null,
      maxDate: this.get('maxDate') || null,
      defaultDate: this.get('defaultDate') || null,
      setDefaultDate: !!this.get('defaultDate'),
      theme: this.get('theme') || null
    };
  },

  /**
   * When updating attrs, we need to reset some things in case they've changed.
   * @public
   * @memberOf {Mixins.Pikaday}
   * @return {undefined}
   */
  didUpdateAttrs() {
    this.set(
      'cancelToken',
      run.later(() => {
        // Do not set or update anything when the component is destroying.
        if (this.get('isDestroying') || this.get('isDestroyed')) {
          return;
        }

        this.setMinDate();
        this.setMaxDate();
        this.setPikadayDate();

        if (this.get('options')) {
          this._updateOptions();
        }
      })
    );
  },

  didRender() {
    this._super();
    this.autoHideOnDisabled();
  },

  setupPikaday() {
    let pikaday = new Pikaday(this.get('_options'));

    if (this.get('defaultDate')) {
      this.set('value', this.get('defaultDate'));
    }

    this.set('pikaday', pikaday);
    this.setPikadayDate();
  },

  willDestroyElement() {
    this._super();
    this.get('pikaday').destroy();
    run.cancel(this.get('cancelToken'));
  },

  setPikadayDate: function() {
    const format = 'YYYY-MM-DD';
    const value = this.get('value');

    if (!value) {
      this.get('pikaday').setDate(value, true);
    } else {
      const date = this.get('useUTC')
        ? moment(moment.utc(value).format(format), format).toDate()
        : value;

      this.get('pikaday').setDate(date, true);
    }
  },

  setMinDate: function() {
    const { pikaday, minDate, value } = getProperties(this, [
      'pikaday',
      'minDate',
      'value'
    ]);

    if (minDate) {
      const _minDate = new Date(minDate.getTime());
      pikaday.setMinDate(_minDate);

      // If the current date is lower than minDate we set date to minDate
      next(() => {
        if (
          value &&
          moment(value, this.get('format')).isBefore(minDate, 'day')
        ) {
          pikaday.setDate(minDate);
        }
      });
    } else {
      pikaday.setMinDate(null);
    }
  },

  setMaxDate: function() {
    const { pikaday, maxDate, value } = getProperties(this, [
      'pikaday',
      'maxDate',
      'value'
    ]);

    if (maxDate) {
      const _maxDate = new Date(maxDate.getTime());
      pikaday.setMaxDate(_maxDate);

      // If the current date is greater than maxDate we set date to maxDate
      next(() => {
        if (value > maxDate) {
          pikaday.setDate(maxDate);
        }
      });
    } else {
      pikaday.setMaxDate(null);
    }
  },

  onOpen() {},
  onClose() {},
  onSelection() {},
  onDraw() {},

  onPikadaySelect: function() {
    this.userSelectedDate();
  },

  onPikadayRedraw: function() {
    this.get('onDraw')();
  },

  userSelectedDate: function() {
    var selectedDate = this.get('pikaday').getDate();

    if (this.get('useUTC')) {
      selectedDate = moment
        .utc([
          selectedDate.getFullYear(),
          selectedDate.getMonth(),
          selectedDate.getDate()
        ])
        .toDate();
    }

    this.get('onSelection')(selectedDate);
  },

  determineYearRange: function() {
    var yearRange = this.get('yearRange');

    if (yearRange) {
      if (yearRange.indexOf(',') > -1) {
        var yearArray = yearRange.split(',');

        if (yearArray[1] === 'currentYear') {
          yearArray[1] = new Date().getFullYear();
        }

        return yearArray;
      } else {
        return yearRange;
      }
    } else {
      return 10;
    }
  },

  autoHideOnDisabled() {
    if (this.get('disabled') && this.get('pikaday')) {
      this.get('pikaday').hide();
    }
  },

  _updateOptions() {
    this.get('pikaday').config(this.get('_options'));
  }
});
<|endoftext|>


<commit_before>/*
 (c) 2013, Vladimir Agafonkin
 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
 https://github.com/mourner/rbush
*/

(function () { 'use strict';

function rbush(maxEntries, format) {
    // jshint newcap: false, validthis: true, evil: true

    if (!(this instanceof rbush)) {
        // allow constructing RBush trees without "new"
        return new rbush(maxEntries, format);
    }

    if (!maxEntries) {
        // maxEntries is required because it's the most important performance decision when using RBush
        // and depens on the type of data and search queries you perform
        throw new Error("Provide a maxEntries argument to rbush constructor");
    }

    this._maxEntries = Math.max(4, maxEntries);
    this._minFill = Math.max(2, Math.floor(this._maxEntries * 0.4));

    // data format (minX, minY, maxX, maxY accessors),
    // uses eval-type function compilation instead of accepting functions to simplify customization;
    // performance is not affected since this happens only once

    format = format || ['[0]', '[1]', '[2]', '[3]'];

    this._sortMinX = this._createSort(format[0]);
    this._sortMinY = this._createSort(format[1]);
    this._sortMaxX = this._createSort(format[2]);
    this._sortMaxY = this._createSort(format[3]);

    this._sortNodeMinX = this._createSort('.bbox[0]');
    this._sortNodeMinY = this._createSort('.bbox[1]');
    this._sortNodeMaxX = this._createSort('.bbox[2]');
    this._sortNodeMaxY = this._createSort('.bbox[3]');

    this._toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
}

rbush.prototype = {

    search: function (bbox) {
        var result = [];

        // recursively search for items in a given bbox, collecting matches in the result array
        this._search(bbox, this.data, result);

        return result;
    },

    load: function (data) {
        // recursively build the tree with the given data from stratch using OMT algorithm
        this.data = this._build(data.slice(), 0);

        // recursively calculate all bboxes
        this._calcBBoxes(this.data, true);

        return this;
    },

    insert: function (item) {
        if (!this.data) {
            this.data = {
                children: [item],
                leaf: true,
                bbox: this._toBBox(item)
            };
        } else {
            // an index of what tree levels overflowed during this single insert
            this._overflowLevels = {};
            this._insert(item);
        }

        return this;
    },

    toJSON: function () {
        // TODO cleanup nodes from area, enlargement, sqDist properties
        return this.data;
    },

    fromJSON: function (data) {
        this.data = data;
        return this;
    },

    _search: function (bbox, node, result) {

        if (!this._intersects(bbox, node.bbox)) { return; }

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (!node.leaf) {
                this._search(bbox, child, result);
            } else if (this._intersects(bbox, this._toBBox(child))) {
                result.push(child);
            }
        }
    },

    _build: function (items, level) {

        var node = {},
            N = items.length,
            M = this._maxEntries;

        if (N <= M) {
            node.children = items;
            node.leaf = true;
            return node;
        }

        node.children = [];

        if (!level) {
            // target number of root entries to maximize storage utilization
            M = Math.ceil(N / Math.pow(M, Math.ceil(Math.log(N) / Math.log(M)) - 1));

            items.sort(this._sortMinX);
        }

        var N1 = Math.ceil(N / M) * Math.ceil(Math.sqrt(M)),
            N2 = Math.ceil(N / M),
            sortFn = level % 2 === 1 ? this._sortMinX : this._sortMinY,
            i, j, slice, sliceLen, childNode;

        // split the items into M mostly square tiles
        for (i = 0; i < N; i += N1) {
            slice = items.slice(i, i + N1).sort(sortFn);

            for (j = 0, sliceLen = slice.length; j < sliceLen; j += N2) {
                // pack each entry recursively
                childNode = this._build(slice.slice(j, j + N2), level + 1);
                node.children.push(childNode);
            }
        }

        return node;
    },

    _chooseSubtree: function (bbox, node, level, path) {

        path.push(node);

        if (node.leaf || path.length - 1 === level) { return node; }

        var i, child, targetNode, area, enlargement, overlap, checkOverlap, minArea, minEnlargement, minOverlap,
            len = node.children.length;

        minArea = minEnlargement = minOverlap = Infinity;

        // calculate area and enlargement for node entries preliminarily for faster sorting
        for (i = 0; i < len; i++) {
            child = node.children[i];

            child.area = this._area(child.bbox);
            child.enlargement = this._enlargedArea(bbox, child.bbox) - child.area;
        }

        if (node.children[0].leaf) {
            // if node children are leaves, narrow our search to 32 rectangles with the least area enlargement
            node.children.sort(this._sortEnlargement);
            len = Math.min(32, len);
            checkOverlap = true;
        }

        for (i = 0; i < len; i++) {
            child = node.children[i];
            area = child.area;
            enlargement = child.enlargement;

            if (checkOverlap) {
                overlap = this._overlapArea(bbox, child, node.children, len);
            }

            // choose entry with the least overlap enlargement
            if (checkOverlap && overlap < minOverlap) {
                minOverlap = overlap;
                minEnlargement = enlargement < minEnlargement ? enlargement : minEnlargement;
                minArea = area < minArea ? area : minArea;
                targetNode = child;

            } else if (!checkOverlap || overlap === minOverlap) {

                // otherwise choose entry with the least area enlargement
                if (enlargement < minEnlargement) {
                    minEnlargement = enlargement;
                    minArea = area < minArea ? area : minArea;
                    targetNode = child;

                } else if (enlargement === minEnlargement) {
                    // otherwise choose one with the smallest area
                    if (area < minArea) {
                        minArea = area;
                        targetNode = child;
                    }
                }
            }
        }

        return this._chooseSubtree(bbox, targetNode || child, level, path);
    },

    _overlapArea: function (bbox, node, nodes, len) {
        var newBox = this._extend(node.bbox.slice(), bbox);

        for (var i = 0, sum = 0, bbox2; i < len; i++) {
            if (node !== nodes[i]) {
                bbox2 = nodes[i].bbox;
                if (this._intersects(newBox, bbox2)) {
                    sum += this._intersectionArea(newBox, bbox2);
                }
            }
        }

        return sum;
    },

    _insert: function (item, level, isNode, root) {
        var bbox = isNode ? item.bbox : this._toBBox(item),
            insertPath = [];

        // recursively find the best node for accommodating the item, saving all nodes along the path too
        var node = this._chooseSubtree(bbox, root || this.data, level, insertPath),
            splitOccured;

        if (typeof level === 'undefined') {
            level = insertPath.length - 1;
        }

        // put the item into the node
        node.children.push(item);

        this._extend(node.bbox, bbox);

        // deal with node overflow if it happened
        do {
            splitOccured = false;
            if (insertPath[level].children.length > this._maxEntries) {
                splitOccured = this._treatOverflow(insertPath, level);
                level--;
            }
        } while (level >= 0 && splitOccured);

        // adjust bboxes along the insertion path
        this._adjustParentBBoxes(node, insertPath, level);
    },

    _treatOverflow: function (insertPath, level) {
        var firstOverflow = !this._overflowLevels[level];
        this._overflowLevels[level] = true;

        // reinsert a part of node entries if not root and overflowing for the first time on this tree level
        if (level > 0 && firstOverflow) {
            this._reinsert(insertPath[level], level);
            return false;
        } else {
            // otherwise split the node
            this._split(insertPath, level);
            return true;
        }
    },

    _reinsert: function (node, level) {
        var x = (node.bbox[0] + node.bbox[1]) / 2,
            y = (node.bbox[2] + node.bbox[3]) / 2,
            len = node.children.length,
            reinsertLen = Math.round(len * 0.3),
            child, i, dx, dy, bbox;

        // calculate distances from node bbox center to children bbox centers
        for (i = 0; i < len; i++) {
            child = node.children[i];
            bbox = node.leaf ? this._toBBox(child) : child.bbox;
            dx = (bbox[0] + bbox[1]) / 2 - x;
            dy = (bbox[2] + bbox[3]) / 2 - y;
            child.sqDist = dx * dx + dy * dy;
        }

        // remove and reinsert 30% entries that are closest to the node bbox center
        node.children.sort(this._sortDist);

        var reinserted = node.children.splice(0, reinsertLen);

        this._calcBBoxes(node);
        // TODO adjust along path?

        var root = this.data;

        for (i = 0; i < reinsertLen; i++) {
            this._insert(reinserted[i], level, !node.leaf, root);
            // TODO side effects of not reinserting to other branch of splitted root?
        }
    },

    _split: function (insertPath, level) {
        var node = insertPath[level],
            M = node.children.length,
            m = Math.ceil(M * 0.4);

        this._chooseSplitAxis(node, m, M);

        var k = this._chooseSplitIndex(node, m, M);

        var newNode = {};
        newNode.children = node.children.splice(k);

        if (node.leaf) {
            newNode.leaf = true;
        }

        this._calcBBoxes(node);
        this._calcBBoxes(newNode);

        if (level) {
            insertPath[level - 1].children.push(newNode);
        } else {
            // split root node
            this.data = {};
            this.data.children = [node, newNode];
            this._calcBBoxes(this.data);
        }
    },

    _chooseSplitIndex: function (node, m, M) {

        var overlap, area,
            minOverlap = Infinity,
            minArea = Infinity,
            index, i, bbox1, bbox2;

        for (i = m; i <= M - m; i++) {
            bbox1 = this._distBBox(node, 0, i);
            bbox2 = this._distBBox(node, i, M);

            overlap = this._intersectionArea(bbox1, bbox2);
            area = this._area(bbox1) + this._area(bbox2);

            // choose distribution with minimum overlap
            if (overlap < minOverlap) {
                minOverlap = overlap;
                index = i;

                minArea = area < minArea ? area : minArea;

            } else if (overlap === minOverlap) {
                // otherwise choose distribution with minimum area

                if (area < minArea) {
                    minArea = area;
                    index = i;
                }
            }
        }

        return index;
    },

    _chooseSplitAxis: function (node, m, M) {

        var sortMinX = node.leaf ? this._sortMinX : this._sortNodeMinX,
            sortMaxX = node.leaf ? this._sortMaxX : this._sortNodeMaxX,
            sortMinY = node.leaf ? this._sortMinY : this._sortNodeMinY,
            sortMaxY = node.leaf ? this._sortMaxY : this._sortNodeMaxY,

            xMargin = this._allDistMargin(node, m, M, sortMinX) + this._allDistMargin(node, m, M, sortMaxX),
            yMargin = this._allDistMargin(node, m, M, sortMinY) + this._allDistMargin(node, m, M, sortMaxY);

        // if total distributions margin value is minimal for x, sort by maxX,
        // otherwise it's already sorted by maxY

        if (xMargin < yMargin) {
            node.children.sort(sortMaxX);
        }
    },

    _allDistMargin: function (node, m, M, sort) {

        node.children.sort(sort);

        for (var i = m, margin = 0; i <= M - m; i++) {
            margin += this._margin(this._distBBox(node, 0, i)) +
                      this._margin(this._distBBox(node, i, M));
        }

        return margin;
    },

    _distBBox: function (node, k, p) {
        var bbox = [Infinity, Infinity, -Infinity, -Infinity];

        for (var i = k, child; i < p; i++) {
            child = node.children[i];
            this._extend(bbox, node.leaf ? this._toBBox(child) : child.bbox);
        }

        return bbox;
    },

    _calcBBoxes: function (node, recursive) {

        node.bbox = [Infinity, Infinity, -Infinity, -Infinity];

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (node.leaf) {
                this._extend(node.bbox, this._toBBox(child));
            } else {
                if (recursive) {
                    this._calcBBoxes(child, recursive);
                }
                this._extend(node.bbox, child.bbox);
            }
        }
    },

    _adjustParentBBoxes: function (node, path, level) {
        // adjust bboxes along the given tree path
        for (var i = level; i >= 0; i--) {
            this._extend(path[i].bbox, node.bbox);
        }
    },

    _sortEnlargement: function (a, b) {
        return a.enlargement > b.enlargement ? 1 : -1;
    },

    _sortDist: function (a, b) {
        return a.sqDist < b.sqDist ? 1 : -1;
    },

    _intersects: function (bbox, bbox2) {
        return bbox2[0] <= bbox[2] &&
               bbox2[1] <= bbox[3] &&
               bbox2[2] >= bbox[0] &&
               bbox2[3] >= bbox[1];
    },

    _extend: function (bbox, bbox2) {
        bbox[0] = Math.min(bbox[0], bbox2[0]);
        bbox[1] = Math.min(bbox[1], bbox2[1]);
        bbox[2] = Math.max(bbox[2], bbox2[2]);
        bbox[3] = Math.max(bbox[3], bbox2[3]);
        return bbox;
    },

    _area: function (bbox) {
        return (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]);
    },

    _margin: function (bbox) {
        return (bbox[2] - bbox[0]) + (bbox[3] - bbox[1]);
    },

    _enlargedArea: function (bbox, bbox2) {
        return (Math.max(bbox2[2], bbox[2]) - Math.min(bbox2[0], bbox[0])) *
               (Math.max(bbox2[3], bbox[3]) - Math.min(bbox2[1], bbox[1]));
    },

    _intersectionArea: function (bbox, bbox2) {
        var minX = Math.max(bbox[0], bbox2[0]),
            maxX = Math.min(bbox[2], bbox2[2]),
            minY = Math.max(bbox[1], bbox2[1]),
            maxY = Math.min(bbox[3], bbox2[3]);

        return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
    },

    _createSort: function (accessor) {
        return new Function('a', 'b', 'return a' + accessor + ' > b' + accessor + ' ? 1 : -1;');
    }
};

if (typeof module !== 'undefined') {
    module.exports = rbush;
} else {
    window.rbush = rbush;
}

})();
<commit_msg>fix bbox adjusting on single insertion<commit_after>/*
 (c) 2013, Vladimir Agafonkin
 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
 https://github.com/mourner/rbush
*/

(function () { 'use strict';

function rbush(maxEntries, format) {
    // jshint newcap: false, validthis: true, evil: true

    if (!(this instanceof rbush)) {
        // allow constructing RBush trees without "new"
        return new rbush(maxEntries, format);
    }

    if (!maxEntries) {
        // maxEntries is required because it's the most important performance decision when using RBush
        // and depens on the type of data and search queries you perform
        throw new Error("Provide a maxEntries argument to rbush constructor");
    }

    this._maxEntries = Math.max(4, maxEntries);
    this._minFill = Math.max(2, Math.floor(this._maxEntries * 0.4));

    // data format (minX, minY, maxX, maxY accessors),
    // uses eval-type function compilation instead of accepting functions to simplify customization;
    // performance is not affected since this happens only once

    format = format || ['[0]', '[1]', '[2]', '[3]'];

    this._sortMinX = this._createSort(format[0]);
    this._sortMinY = this._createSort(format[1]);
    this._sortMaxX = this._createSort(format[2]);
    this._sortMaxY = this._createSort(format[3]);

    this._sortNodeMinX = this._createSort('.bbox[0]');
    this._sortNodeMinY = this._createSort('.bbox[1]');
    this._sortNodeMaxX = this._createSort('.bbox[2]');
    this._sortNodeMaxY = this._createSort('.bbox[3]');

    this._toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
}

rbush.prototype = {

    search: function (bbox) {
        var result = [];

        // recursively search for items in a given bbox, collecting matches in the result array
        this._search(bbox, this.data, result);

        return result;
    },

    load: function (data) {
        // recursively build the tree with the given data from stratch using OMT algorithm
        this.data = this._build(data.slice(), 0);

        // recursively calculate all bboxes
        this._calcBBoxes(this.data, true);

        return this;
    },

    insert: function (item) {
        if (!this.data) {
            this.data = {
                children: [item],
                leaf: true,
                bbox: this._toBBox(item)
            };
        } else {
            // an index of what tree levels overflowed during this single insert
            this._overflowLevels = {};
            this._insert(item);
        }

        return this;
    },

    toJSON: function () {
        // TODO cleanup nodes from area, enlargement, sqDist properties
        return this.data;
    },

    fromJSON: function (data) {
        this.data = data;
        return this;
    },

    _search: function (bbox, node, result) {

        if (!this._intersects(bbox, node.bbox)) { return; }

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (!node.leaf) {
                this._search(bbox, child, result);
            } else if (this._intersects(bbox, this._toBBox(child))) {
                result.push(child);
            }
        }
    },

    _build: function (items, level) {

        var node = {},
            N = items.length,
            M = this._maxEntries;

        if (N <= M) {
            node.children = items;
            node.leaf = true;
            return node;
        }

        node.children = [];

        if (!level) {
            // target number of root entries to maximize storage utilization
            M = Math.ceil(N / Math.pow(M, Math.ceil(Math.log(N) / Math.log(M)) - 1));

            items.sort(this._sortMinX);
        }

        var N1 = Math.ceil(N / M) * Math.ceil(Math.sqrt(M)),
            N2 = Math.ceil(N / M),
            sortFn = level % 2 === 1 ? this._sortMinX : this._sortMinY,
            i, j, slice, sliceLen, childNode;

        // split the items into M mostly square tiles
        for (i = 0; i < N; i += N1) {
            slice = items.slice(i, i + N1).sort(sortFn);

            for (j = 0, sliceLen = slice.length; j < sliceLen; j += N2) {
                // pack each entry recursively
                childNode = this._build(slice.slice(j, j + N2), level + 1);
                node.children.push(childNode);
            }
        }

        return node;
    },

    _chooseSubtree: function (bbox, node, level, path) {

        path.push(node);

        if (node.leaf || path.length - 1 === level) { return node; }

        var i, child, targetNode, area, enlargement, overlap, checkOverlap, minArea, minEnlargement, minOverlap,
            len = node.children.length;

        minArea = minEnlargement = minOverlap = Infinity;

        // calculate area and enlargement for node entries preliminarily for faster sorting
        for (i = 0; i < len; i++) {
            child = node.children[i];

            child.area = this._area(child.bbox);
            child.enlargement = this._enlargedArea(bbox, child.bbox) - child.area;
        }

        if (node.children[0].leaf) {
            // if node children are leaves, narrow our search to 32 rectangles with the least area enlargement
            node.children.sort(this._sortEnlargement);
            len = Math.min(32, len);
            checkOverlap = true;
        }

        for (i = 0; i < len; i++) {
            child = node.children[i];
            area = child.area;
            enlargement = child.enlargement;

            if (checkOverlap) {
                overlap = this._overlapArea(bbox, child, node.children, len);
            }

            // choose entry with the least overlap enlargement
            if (checkOverlap && overlap < minOverlap) {
                minOverlap = overlap;
                minEnlargement = enlargement < minEnlargement ? enlargement : minEnlargement;
                minArea = area < minArea ? area : minArea;
                targetNode = child;

            } else if (!checkOverlap || overlap === minOverlap) {

                // otherwise choose entry with the least area enlargement
                if (enlargement < minEnlargement) {
                    minEnlargement = enlargement;
                    minArea = area < minArea ? area : minArea;
                    targetNode = child;

                } else if (enlargement === minEnlargement) {
                    // otherwise choose one with the smallest area
                    if (area < minArea) {
                        minArea = area;
                        targetNode = child;
                    }
                }
            }
        }

        return this._chooseSubtree(bbox, targetNode || child, level, path);
    },

    _overlapArea: function (bbox, node, nodes, len) {
        var newBox = this._extend(node.bbox.slice(), bbox);

        for (var i = 0, sum = 0, bbox2; i < len; i++) {
            if (node !== nodes[i]) {
                bbox2 = nodes[i].bbox;
                if (this._intersects(newBox, bbox2)) {
                    sum += this._intersectionArea(newBox, bbox2);
                }
            }
        }

        return sum;
    },

    _insert: function (item, level, isNode, root) {
        var bbox = isNode ? item.bbox : this._toBBox(item),
            insertPath = [];

        // recursively find the best node for accommodating the item, saving all nodes along the path too
        var node = this._chooseSubtree(bbox, root || this.data, level, insertPath),
            splitOccured, reinsertOccured;

        if (typeof level === 'undefined') {
            level = insertPath.length - 1;
        }

        // put the item into the node
        node.children.push(item);
        this._extend(node.bbox, bbox);

        // deal with node overflow if it happened
        do {
            splitOccured = false;
            if (insertPath[level].children.length > this._maxEntries) {
                splitOccured = this._treatOverflow(insertPath, level);
                level--;
                reinsertOccured = !splitOccured;
            }
        } while (level >= 0 && splitOccured);

        // adjust bboxes along the insertion path
        if (!reinsertOccured) {
            this._adjustParentBBoxes(bbox, insertPath, level);
        }
    },

    _treatOverflow: function (insertPath, level) {
        var firstOverflow = !this._overflowLevels[level];
        this._overflowLevels[level] = true;

        // reinsert a part of node entries if not root and overflowing for the first time on this tree level
        if (level > 0 && firstOverflow) {
            this._reinsert(insertPath, level);
            return false;
        } else {
            // otherwise split the node
            this._split(insertPath, level);
            return true;
        }
    },

    _reinsert: function (insertPath, level) {
        var node = insertPath[level],
            x = (node.bbox[0] + node.bbox[1]) / 2,
            y = (node.bbox[2] + node.bbox[3]) / 2,
            len = node.children.length,
            reinsertLen = Math.round(len * 0.3),
            child, i, dx, dy, bbox;

        // calculate distances from node bbox center to children bbox centers
        for (i = 0; i < len; i++) {
            child = node.children[i];
            bbox = node.leaf ? this._toBBox(child) : child.bbox;
            dx = (bbox[0] + bbox[1]) / 2 - x;
            dy = (bbox[2] + bbox[3]) / 2 - y;
            child.sqDist = dx * dx + dy * dy;
        }

        // remove and reinsert 30% entries that are closest to the node bbox center
        node.children.sort(this._sortDist);

        var reinserted = node.children.splice(0, reinsertLen);

        // adjust bboxes along insertion path
        for (i = insertPath.length - 1; i >= 0; i--) {
            this._calcBBoxes(insertPath[i]);
        }

        var root = this.data;

        for (i = 0; i < reinsertLen; i++) {
            this._insert(reinserted[i], level, !node.leaf, root);
            // TODO side effects of not reinserting to other branch of splitted root?
        }
    },

    _split: function (insertPath, level) {
        var node = insertPath[level],
            M = node.children.length,
            m = Math.ceil(M * 0.4);

        this._chooseSplitAxis(node, m, M);

        var k = this._chooseSplitIndex(node, m, M);

        var newNode = {};
        newNode.children = node.children.splice(k);

        if (node.leaf) {
            newNode.leaf = true;
        }

        this._calcBBoxes(node);
        this._calcBBoxes(newNode);

        if (level) {
            insertPath[level - 1].children.push(newNode);
        } else {
            // split root node
            this.data = {};
            this.data.children = [node, newNode];
            this._calcBBoxes(this.data);
        }
    },

    _chooseSplitIndex: function (node, m, M) {

        var overlap, area,
            minOverlap = Infinity,
            minArea = Infinity,
            index, i, bbox1, bbox2;

        for (i = m; i <= M - m; i++) {
            bbox1 = this._distBBox(node, 0, i);
            bbox2 = this._distBBox(node, i, M);

            overlap = this._intersectionArea(bbox1, bbox2);
            area = this._area(bbox1) + this._area(bbox2);

            // choose distribution with minimum overlap
            if (overlap < minOverlap) {
                minOverlap = overlap;
                index = i;

                minArea = area < minArea ? area : minArea;

            } else if (overlap === minOverlap) {
                // otherwise choose distribution with minimum area

                if (area < minArea) {
                    minArea = area;
                    index = i;
                }
            }
        }

        return index;
    },

    _chooseSplitAxis: function (node, m, M) {

        var sortMinX = node.leaf ? this._sortMinX : this._sortNodeMinX,
            sortMaxX = node.leaf ? this._sortMaxX : this._sortNodeMaxX,
            sortMinY = node.leaf ? this._sortMinY : this._sortNodeMinY,
            sortMaxY = node.leaf ? this._sortMaxY : this._sortNodeMaxY,

            xMargin = this._allDistMargin(node, m, M, sortMinX) + this._allDistMargin(node, m, M, sortMaxX),
            yMargin = this._allDistMargin(node, m, M, sortMinY) + this._allDistMargin(node, m, M, sortMaxY);

        // if total distributions margin value is minimal for x, sort by maxX,
        // otherwise it's already sorted by maxY

        if (xMargin < yMargin) {
            node.children.sort(sortMaxX);
        }
    },

    _allDistMargin: function (node, m, M, sort) {

        node.children.sort(sort);

        for (var i = m, margin = 0; i <= M - m; i++) {
            margin += this._margin(this._distBBox(node, 0, i)) +
                      this._margin(this._distBBox(node, i, M));
        }

        return margin;
    },

    _distBBox: function (node, k, p) {
        var bbox = [Infinity, Infinity, -Infinity, -Infinity];

        for (var i = k, child; i < p; i++) {
            child = node.children[i];
            this._extend(bbox, node.leaf ? this._toBBox(child) : child.bbox);
        }

        return bbox;
    },

    _calcBBoxes: function (node, recursive) {

        node.bbox = [Infinity, Infinity, -Infinity, -Infinity];

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (node.leaf) {
                this._extend(node.bbox, this._toBBox(child));
            } else {
                if (recursive) {
                    this._calcBBoxes(child, recursive);
                }
                this._extend(node.bbox, child.bbox);
            }
        }
    },

    _adjustParentBBoxes: function (bbox, path, level) {
        // adjust bboxes along the given tree path
        for (var i = level; i >= 0; i--) {
            this._extend(path[i].bbox, bbox);
        }
    },

    _sortEnlargement: function (a, b) {
        return a.enlargement > b.enlargement ? 1 : -1;
    },

    _sortDist: function (a, b) {
        return a.sqDist < b.sqDist ? 1 : -1;
    },

    _intersects: function (bbox, bbox2) {
        return bbox2[0] <= bbox[2] &&
               bbox2[1] <= bbox[3] &&
               bbox2[2] >= bbox[0] &&
               bbox2[3] >= bbox[1];
    },

    _extend: function (bbox, bbox2) {
        bbox[0] = Math.min(bbox[0], bbox2[0]);
        bbox[1] = Math.min(bbox[1], bbox2[1]);
        bbox[2] = Math.max(bbox[2], bbox2[2]);
        bbox[3] = Math.max(bbox[3], bbox2[3]);
        return bbox;
    },

    _area: function (bbox) {
        return (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]);
    },

    _margin: function (bbox) {
        return (bbox[2] - bbox[0]) + (bbox[3] - bbox[1]);
    },

    _enlargedArea: function (bbox, bbox2) {
        return (Math.max(bbox2[2], bbox[2]) - Math.min(bbox2[0], bbox[0])) *
               (Math.max(bbox2[3], bbox[3]) - Math.min(bbox2[1], bbox[1]));
    },

    _intersectionArea: function (bbox, bbox2) {
        var minX = Math.max(bbox[0], bbox2[0]),
            maxX = Math.min(bbox[2], bbox2[2]),
            minY = Math.max(bbox[1], bbox2[1]),
            maxY = Math.min(bbox[3], bbox2[3]);

        return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
    },

    _createSort: function (accessor) {
        return new Function('a', 'b', 'return a' + accessor + ' > b' + accessor + ' ? 1 : -1;');
    }
};

if (typeof module !== 'undefined') {
    module.exports = rbush;
} else {
    window.rbush = rbush;
}

})();
<|endoftext|>