<commit_before>window.addEventListener('load', function(evt) {
	// make ui
	var namespace = 'vongrid.map';

	var map = window.localStorage[namespace];
	if (map) {
		map = JSON.parse(map);
		console.log('Loading map from localStorage');
	}

	var timeTilAutoSave = 300; // timer runs per frame, 60fps
	var saveTimer = 10;
	var dirtyMap = false;

	var saveBtn = document.getElementById('save-btn');
	saveBtn.onmouseup = function(evt) {
		saveMap();
		return false;
	};

	var loadBtn = document.getElementById('load-btn');
	loadBtn.addEventListener('click', function() {
		fileInput.click();
	}, false);

	var fileInput = document.createElement('input');
	fileInput.type = 'file';
	fileInput.addEventListener('change', function(evt) {
		var file = fileInput.files[0];
		if (!file) {
			return;
		}

		var reader = new FileReader();
		reader.onload = function(e) {
			var json = null;
			try {
				json = JSON.parse(e.target.result);
			}
			catch(err) {
				console.warn('File is not json format');
				return;
			}
			loadMap(json);
		};

		reader.readAsText(file);

		return false;
	});

	// setup the thing

	var scene = new hg.Scene({
		element: document.getElementById('view'),
		cameraPosition: {x:0, y:300, z:120}
	}, {
		noZoom: false
	});

	// listen to the orbit controls to disable the raycaster while user adjusts the view
	scene.controls.addEventListener('wheel', onControlWheel);

	var grid = new hg.HexGrid({
		rings: 1,
		cellSize: 10,
		cellDepth: 5,
		cellScale: 0.95
	});

	var board = new hg.Board(grid);
	var mouse = new hg.MouseCaster(board.group, scene.camera, document.getElementById('view'));
	// disable orbit controls if user hovers over a cell so they can adjust the height with the mouse wheel
	mouse.signal.add(onMouse, this);

	var plane = new EditorPlane(board.group, grid, mouse);
	plane.addHoverMeshToGroup(scene.container);

	plane.mapChanged.add(onMapChange, this);

	scene.add(board.group);
	scene.focusOn(board.group);

	if (map) {
		loadMap(map);
	}
	else {
		var mapCells = [];
		var cell, mat;
		for (var c in grid.cells) {
			cell = grid.cells[c];
			mapCells.push({
				x: cell.x,
				y: cell.y,
				z: cell.z,
				depth: cell.w.depth,
				matCacheId: 0,
				customData: cell.w.userData.mapData
			});
		}
		var mapMats = [];
		for (var i = 0; i < grid._matCache.length; i++) {
			mat = grid._matCache[i];
			/*mapMats.push({
				cache_id: i,
				type: mat.type,
				// color, ambient, emissive, reflectivity, refractionRatio, wrapAround,
				imgURL: // get this value from the ui
			});*/
		}
		map = {
			cells: mapCells,
			materials: mapMats
		};
	}

	update();
	function update() {
		if (wheelTimer < 10) {
			wheelTimer++;
			if (wheelTimer === 10) {
				mouse.active = true;
			}
		}
		if (dirtyMap) {
			saveTimer--;
			if (saveTimer === 0) {
				dirtyMap = false;
				try {
					window.localStorage[namespace] = JSON.stringify(map);
					console.log('Auto-saved new map data');
				}
				catch (err) {
					console.warn('Problem auto-saving map');
				}
			}
		}
		mouse.update();
		plane.update();
		scene.render();
		requestAnimationFrame(update);
	}

	var wheelTimer = 10;
	function onControlWheel() {
		mouse.active = false;
		wheelTimer = 0;
	}

	function onMouse(type, obj) {
		switch (type) {
			case hg.MouseCaster.OVER:
				if (obj) {
					scene.controls.noZoom = true;
				}
				break;
			case hg.MouseCaster.OUT:
				if (obj) {
					scene.controls.noZoom = false;
				}
				break;
			case hg.MouseCaster.WHEEL:
				if (mouse.wheel < 1) {
					// prevent wheel from going negative since cells can't extrude inside-out (well, shouldn't)
					mouse.wheel = 1;
				}
				break;
		}
	}

	function onMapChange(tile) {
		dirtyMap = true;
		saveTimer = timeTilAutoSave;
	}

	// taken from https://github.com/mrdoob/three.js/blob/master/editor/js/Menubar.File.js
	var link = document.createElement('a');
	link.style.display = 'none';
	document.body.appendChild(link); // Firefox workaround

	function exportString(output, filename) {
		var blob = new Blob([output], {type: 'text/plain'});
		var objectURL = URL.createObjectURL(blob);

		link.href = objectURL;
		link.download = filename || 'data.json';
		link.target = '_blank';

		var evt = document.createEvent('MouseEvents');
		evt.initMouseEvent(
			'click', true, false, window, 0, 0, 0, 0, 0,
			false, false, false, false, 0, null
		);
		link.dispatchEvent(evt);
	}

	function loadMap(json) {
		board.group.remove(grid.group);
		grid.load(json);
		board.setGrid(grid);
		scene.add(board.group);
		console.log('Map load complete');
	}

	function saveMap() {
		var output = null;

		map.cells = grid.toJSON();

		try {
			output = JSON.stringify(map, null, '\t');
			output = output.replace(/[\n\t]+([\d\.e\-\[\]]+)/g, '$1');
		} catch (e) {
			output = JSON.stringify(map);
		}

		exportString(output, 'hex-map.json');
	}
});<commit_msg>fixed autosave<commit_after>window.addEventListener('load', function(evt) {
	// make ui
	var namespace = 'vongrid.map';

	var map = window.localStorage[namespace];
	if (map) {
		map = JSON.parse(map);
		console.log('Loading map from localStorage');
	}

	var timeTilAutoSave = 200; // timer runs per frame, 60fps
	var saveTimer = 10;
	var dirtyMap = false;

	var saveBtn = document.getElementById('save-btn');
	saveBtn.onmouseup = function(evt) {
		saveMap();
		return false;
	};

	var loadBtn = document.getElementById('load-btn');
	loadBtn.addEventListener('click', function() {
		fileInput.click();
	}, false);

	var fileInput = document.createElement('input');
	fileInput.type = 'file';
	fileInput.addEventListener('change', function(evt) {
		var file = fileInput.files[0];
		if (!file) {
			return;
		}

		var reader = new FileReader();
		reader.onload = function(e) {
			var json = null;
			try {
				json = JSON.parse(e.target.result);
			}
			catch(err) {
				console.warn('File is not json format');
				return;
			}
			loadMap(json);
		};

		reader.readAsText(file);

		return false;
	});

	// setup the thing
	var canvas = document.getElementById('view');
	var scene = new hg.Scene({
		element: canvas,
		cameraPosition: {x:0, y:300, z:120}
	}, {
		noZoom: false
	});

	// listen to the orbit controls to disable the raycaster while user adjusts the view
	scene.controls.addEventListener('wheel', onControlWheel);

	var grid = new hg.HexGrid({
		rings: 1,
		cellSize: 10,
		cellDepth: 5,
		cellScale: 0.95
	});

	var board = new hg.Board(grid);
	var mouse = new hg.MouseCaster(board.group, scene.camera, canvas);
	// disable orbit controls if user hovers over a cell so they can adjust the height with the mouse wheel
	mouse.signal.add(onMouse, this);

	var plane = new EditorPlane(board.group, grid, mouse);
	plane.addHoverMeshToGroup(scene.container);

	plane.mapChanged.add(onMapChange, this);

	scene.add(board.group);
	scene.focusOn(board.group);

	if (map) {
		loadMap(map);
	}
	else {
		var mapCells = [];
		var cell, mat;
		for (var c in grid.cells) {
			cell = grid.cells[c];
			mapCells.push({
				x: cell.x,
				y: cell.y,
				z: cell.z,
				depth: cell.w.depth,
				matCacheId: 0,
				customData: cell.w.userData.mapData
			});
		}
		var mapMats = [];
		for (var i = 0; i < grid._matCache.length; i++) {
			mat = grid._matCache[i];
			/*mapMats.push({
				cache_id: i,
				type: mat.type,
				// color, ambient, emissive, reflectivity, refractionRatio, wrapAround,
				imgURL: // get this value from the ui
			});*/
		}
		map = {
			cells: mapCells,
			materials: mapMats
		};
		console.log('Created a new map');
	}

	update();
	function update() {
		if (wheelTimer < 10) {
			wheelTimer++;
			if (wheelTimer === 10) {
				mouse.active = true;
			}
		}
		if (dirtyMap) {
			saveTimer--;
			if (saveTimer === 0) {
				dirtyMap = false;
				try {
					window.localStorage[namespace] = JSON.stringify(map);
					console.log('Auto-saved new map data');
				}
				catch (err) {
					console.warn('Problem auto-saving map');
				}
			}
		}
		mouse.update();
		plane.update();
		scene.render();
		requestAnimationFrame(update);
	}

	var wheelTimer = 10;
	function onControlWheel() {
		mouse.active = false;
		wheelTimer = 0;
	}

	function onMouse(type, obj) {
		switch (type) {
			case hg.MouseCaster.OVER:
				if (obj) {
					scene.controls.noZoom = true;
				}
				break;
			case hg.MouseCaster.OUT:
				if (obj) {
					scene.controls.noZoom = false;
				}
				break;
			case hg.MouseCaster.WHEEL:
				if (mouse.wheel < 1) {
					// prevent wheel from going negative since cells can't extrude inside-out (well, shouldn't)
					mouse.wheel = 1;
				}
				break;
		}
	}

	function onMapChange(tile) {
		dirtyMap = true;
		saveTimer = timeTilAutoSave;
		map.cells = grid.toJSON();
	}

	// taken from https://github.com/mrdoob/three.js/blob/master/editor/js/Menubar.File.js
	var link = document.createElement('a');
	link.style.display = 'none';
	document.body.appendChild(link); // Firefox workaround

	function exportString(output, filename) {
		var blob = new Blob([output], {type: 'text/plain'});
		var objectURL = URL.createObjectURL(blob);

		link.href = objectURL;
		link.download = filename || 'data.json';
		link.target = '_blank';

		var evt = document.createEvent('MouseEvents');
		evt.initMouseEvent(
			'click', true, false, window, 0, 0, 0, 0, 0,
			false, false, false, false, 0, null
		);
		link.dispatchEvent(evt);
	}

	function loadMap(json) {
		console.log(json);
		board.group.remove(grid.group);
		grid.load(json);
		board.setGrid(grid);
		scene.add(board.group);
		console.log('Map load complete');
	}

	function saveMap() {
		var output = null;

		map.cells = grid.toJSON();

		try {
			output = JSON.stringify(map, null, '\t');
			output = output.replace(/[\n\t]+([\d\.e\-\[\]]+)/g, '$1');
		} catch (e) {
			output = JSON.stringify(map);
		}

		exportString(output, 'hex-map.json');
	}
});
{'fraction_non_alphanumeric': 0.1534445695567612, 'fraction_numerical': 0.008393899068481933, 'mean_word_length': 3.1877411058722673, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7415096', 'n_tokens_mistral': 4044, 'n_tokens_neox': 3414, 'n_words': 813}