<commit_before>'use strict';

module.exports =
    ['$scope', 'Home', '$mdSidenav', '$mdBottomSheet', 'HomeScrollRequest', 'ToolbarService', 'ElyModal', 'SearchService', 'SearchHome',
        'HomeAddRemovePinwallElementService', 'BlogRecommendationFilters', '$mdMedia', 'WebStorageFilter',
        function ($scope, Home, $mdSidenav, $mdBottomSheet, HomeScrollRequest, ToolbarService, ElyModal, SearchService, SearchHome,
                  HomeAddRemovePinwallElementService, BlogRecommendationFilters, $mdMedia, WebStorageFilter) {
            var ctrl = this, filters = BlogRecommendationFilters.getFilterParams();
            ctrl.home = {pinwall: []};
            ctrl.noPinwall = false;
            ctrl.loadRunning = true;
            ctrl.showSearch = false;
            ctrl.filterOrder = WebStorageFilter.getFilterOrder();
            ctrl.$mdMedia = $mdMedia;

            ctrl.addRemovePinwallElementService = HomeAddRemovePinwallElementService;

            HomeScrollRequest.reset();

            ctrl.openCreatePage = function () {
                $mdBottomSheet.show({
                    templateUrl: 'app/modules/navigation/createPage/template.html',
                    controller: 'CreatePageNavCtrl',
                    controllerAs: 'ctrl',
                    locals: {},
                    clickOutsideToClose: true,
                    parent: '#viewport'
                });
            };

            //toolbar search ----
            SearchService.register(ctrl, SearchHome.query, SearchHome.query);

            ctrl.requestStarted = function () {
                ctrl.loadRunning = true;
            };

            ctrl.requestFinished = function (resp) {
                ctrl.loadRunning = false;
                ctrl.showSearch = true;
                ctrl.searchResult = resp;
            };

            ctrl.abortSearch = function () {
                ctrl.loadRunning = false;
                ctrl.showSearch = false;
            };
            //---------------------
            //Filter---------------
            BlogRecommendationFilters.register('Home', this);

            ctrl.filterChanged = function (newFilters) {
                filters = newFilters;
                ctrl.reset();
            };

            ctrl.orderChanged = function () {
                WebStorageFilter.setFilterOrder(ctrl.filterOrder);
                ctrl.reset();
            };

            ctrl.reset = function () {
                HomeScrollRequest.reset();
                ctrl.home = {pinwall: []};
                ctrl.loadRunning = true;
                ctrl.nextPinwallInfo();
            };

            //---------------------

            ctrl.nextPinwallInfo = function () {
                var payload = angular.extend({}, filters, {order: ctrl.filterOrder});
                HomeScrollRequest.nextRequest(ctrl.home.pinwall, payload).then(function (pinwall) {
                    ctrl.home = pinwall;
                    ctrl.loadRunning = false;
                    if (pinwall.pinwall.length === 0) {
                        ctrl.noPinwall = true;
                    }
                });
            };
            ctrl.nextPinwallInfo();

            ctrl.reloadPinwall = function () {
                HomeScrollRequest.reset();
                ctrl.home = {pinwall: []};
                ctrl.loadRunning = true;
                ctrl.nextPinwallInfo();
            };

            $scope.isSideNavOpen = false;

            ctrl.openSideNavRight = function () {
                $mdSidenav('rightFilterRecommendationNav').open();
            };

            $scope.$watch('isSideNavOpen', function (isOpen) {
                if (isOpen) {
                    ToolbarService.disable();
                } else {
                    ToolbarService.enable();
                }
            });
        }];
<commit_msg>Only submit order when order changed.<commit_after>'use strict';

module.exports =
    ['$scope', 'Home', '$mdSidenav', '$mdBottomSheet', 'HomeScrollRequest', 'ToolbarService', 'ElyModal', 'SearchService', 'SearchHome',
        'HomeAddRemovePinwallElementService', 'BlogRecommendationFilters', '$mdMedia', 'WebStorageFilter',
        function ($scope, Home, $mdSidenav, $mdBottomSheet, HomeScrollRequest, ToolbarService, ElyModal, SearchService, SearchHome,
                  HomeAddRemovePinwallElementService, BlogRecommendationFilters, $mdMedia, WebStorageFilter) {
            var ctrl = this, filters = BlogRecommendationFilters.getFilterParams();
            ctrl.home = {pinwall: []};
            ctrl.noPinwall = false;
            ctrl.loadRunning = true;
            ctrl.showSearch = false;
            ctrl.filterOrder = WebStorageFilter.getFilterOrder();
            ctrl.actualFilterOrder = angular.copy(ctrl.filterOrder);
            ctrl.$mdMedia = $mdMedia;

            ctrl.addRemovePinwallElementService = HomeAddRemovePinwallElementService;

            HomeScrollRequest.reset();

            ctrl.openCreatePage = function () {
                $mdBottomSheet.show({
                    templateUrl: 'app/modules/navigation/createPage/template.html',
                    controller: 'CreatePageNavCtrl',
                    controllerAs: 'ctrl',
                    locals: {},
                    clickOutsideToClose: true,
                    parent: '#viewport'
                });
            };

            //toolbar search ----
            SearchService.register(ctrl, SearchHome.query, SearchHome.query);

            ctrl.requestStarted = function () {
                ctrl.loadRunning = true;
            };

            ctrl.requestFinished = function (resp) {
                ctrl.loadRunning = false;
                ctrl.showSearch = true;
                ctrl.searchResult = resp;
            };

            ctrl.abortSearch = function () {
                ctrl.loadRunning = false;
                ctrl.showSearch = false;
            };
            //---------------------
            //Filter---------------
            BlogRecommendationFilters.register('Home', this);

            ctrl.filterChanged = function (newFilters) {
                filters = newFilters;
                ctrl.reset();
            };

            ctrl.orderChanged = function () {
                if (ctrl.filterOrder !== ctrl.actualFilterOrder) {
                    ctrl.actualFilterOrder = angular.copy(ctrl.filterOrder);
                    WebStorageFilter.setFilterOrder(ctrl.filterOrder);
                    ctrl.reset();
                }
            };

            ctrl.reset = function () {
                HomeScrollRequest.reset();
                ctrl.home = {pinwall: []};
                ctrl.loadRunning = true;
                ctrl.nextPinwallInfo();
            };

            //---------------------

            ctrl.nextPinwallInfo = function () {
                var payload = angular.extend({}, filters, {order: ctrl.filterOrder});
                HomeScrollRequest.nextRequest(ctrl.home.pinwall, payload).then(function (pinwall) {
                    ctrl.home = pinwall;
                    ctrl.loadRunning = false;
                    if (pinwall.pinwall.length === 0) {
                        ctrl.noPinwall = true;
                    }
                });
            };
            ctrl.nextPinwallInfo();

            ctrl.reloadPinwall = function () {
                HomeScrollRequest.reset();
                ctrl.home = {pinwall: []};
                ctrl.loadRunning = true;
                ctrl.nextPinwallInfo();
            };

            $scope.isSideNavOpen = false;

            ctrl.openSideNavRight = function () {
                $mdSidenav('rightFilterRecommendationNav').open();
            };

            $scope.$watch('isSideNavOpen', function (isOpen) {
                if (isOpen) {
                    ToolbarService.disable();
                } else {
                    ToolbarService.enable();
                }
            });
        }];
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const compareLocations = require("./compareLocations");
let debugId = 1000;
const removeAndDo = require("./removeAndDo");

const byId = (a, b) => {
	if(a.id < b.id) return -1;
	if(b.id < a.id) return 1;
	return 0;
};

class Chunk {

	constructor(name, module, loc) {
		this.id = null;
		this.ids = null;
		this.debugId = debugId++;
		this.name = name;
		this.modules = [];
		this.entrypoints = [];
		this.chunks = [];
		this.parents = [];
		this.blocks = [];
		this.origins = [];
		this.files = [];
		this.rendered = false;
		this.addChunk = this.createAdder("chunks");
		this.addParent = this.createAdder("parents");
		if(module) {
			this.origins.push({
				module,
				loc,
				name
			});
		}
	}

	createAdder(collection) {
		const createAdderCallback = (chunk) => {
			if(chunk === this) {
				return false;
			}
			if(this[collection].indexOf(chunk) >= 0) {
				return false;
			}
			this[collection].push(chunk);
			return true;
		};
		return createAdderCallback;
	}

	get entry() {
		throw new Error("Chunk.entry was removed. Use hasRuntime()");
	}

	set entry(data) {
		throw new Error("Chunk.entry was removed. Use hasRuntime()");
	}

	get initial() {
		throw new Error("Chunk.initial was removed. Use isInitial()");
	}

	set initial(data) {
		throw new Error("Chunk.initial was removed. Use isInitial()");
	}

	hasRuntime() {
		if(this.entrypoints.length === 0) return false;
		return this.entrypoints[0].chunks[0] === this;
	}

	isInitial() {
		return this.entrypoints.length > 0;
	}

	hasEntryModule() {
		return !!this.entryModule;
	}

	addModule(module) {
		if(this.modules.indexOf(module) >= 0) {
			return false;
		}
		this.modules.push(module);
		return true;
	}

	removeModule(module) {
		removeAndDo(this.modules, module, "removeChunk", this);
	}

	removeChunk(chunk) {
		removeAndDo(this.chunks, chunk, "removeParent", this);
	}

	removeParent(chunk) {
		removeAndDo(this.parents, chunk, "removeChunk", this);
	}

	addBlock(block) {
		if(this.blocks.indexOf(block) >= 0) {
			return false;
		}
		this.blocks.push(block);
		return true;
	}

	addOrigin(module, loc) {
		this.origins.push({
			module,
			loc,
			name: this.name
		});
	}

	remove(reason) {
		// cleanup modules
		this.modules.slice().forEach(module => {
			module.removeChunk(this);
		});

		// cleanup parents
		this.parents.forEach(parent => {
			// remove this chunk from its parents
			const idx = parent.chunks.indexOf(this);
			if(idx >= 0) {
				parent.chunks.splice(idx, 1);
			}

			// cleanup "sub chunks"
			this.chunks.forEach(chunk => {
				/**
				 * remove this chunk as "intermediary" and connect
				 * it "sub chunks" and parents directly
				 */
				// add parent to each "sub chunk"
				chunk.addParent(parent);
				// add "sub chunk" to parent
				parent.addChunk(chunk);

				// remove this as parent of every "sub chunk"
				const idx = chunk.parents.indexOf(this);
				if(idx >= 0) {
					chunk.parents.splice(idx, 1);
				}
			});
		});

		// cleanup blocks
		this.blocks.forEach(block => {
			const idx = block.chunks.indexOf(this);
			if(idx >= 0) {
				block.chunks.splice(idx, 1);
				if(block.chunks.length === 0) {
					block.chunks = null;
					block.chunkReason = reason;
				}
			}
		});
	}

	moveModule(module, other) {
		module.removeChunk(this);
		module.addChunk(other);
		other.addModule(module);
		module.rewriteChunkInReasons(this, [other]);
	}

	integrate(other, reason) {
		if(!this.canBeIntegrated(other)) {
			return false;
		}

		const otherModules = other.modules.slice();
		otherModules.forEach(m => {
			m.removeChunk(other);
			m.addChunk(this);
			this.addModule(m);
			m.rewriteChunkInReasons(other, [this]);
		}, this);
		other.modules.length = 0;

		const moveChunks = (chunks, kind, onChunk) => {
			chunks.forEach(c => {
				const idx = c[kind].indexOf(other);
				if(idx >= 0) {
					c[kind].splice(idx, 1);
				}
				onChunk(c);
			});
		};
		moveChunks(other.parents, "chunks", c => {
			if(c !== this && this.addParent(c)) {
				c.addChunk(this);
			}
		});
		other.parents.length = 0;
		moveChunks(other.chunks, "parents", c => {
			if(c !== this && this.addChunk(c)) {
				c.addParent(this);
			}
		});
		other.chunks.length = 0;
		other.blocks.forEach(b => {
			b.chunks = (b.chunks || [this]).map(c => {
				return c === other ? this : c;
			}, this);
			b.chunkReason = reason;
			this.addBlock(b);
		}, this);
		other.blocks.length = 0;
		other.origins.forEach(origin => {
			this.origins.push(origin);
		}, this);
		this.origins.forEach(origin => {
			if(!origin.reasons) {
				origin.reasons = [reason];
			} else if(origin.reasons[0] !== reason) {
				origin.reasons.unshift(reason);
			}
		});
		this.chunks = this.chunks.filter(c => {
			return c !== other && c !== this;
		});
		this.parents = this.parents.filter(c => {
			return c !== other && c !== this;
		});
		return true;
	}

	split(newChunk) {
		this.blocks.forEach(b => {
			newChunk.blocks.push(b);
			b.chunks.push(newChunk);
		});
		this.chunks.forEach(c => {
			newChunk.chunks.push(c);
			c.parents.push(newChunk);
		});
		this.parents.forEach(p => {
			p.chunks.push(newChunk);
			newChunk.parents.push(p);
		});
		this.entrypoints.forEach(e => {
			e.insertChunk(newChunk, this);
		});
	}

	isEmpty() {
		return this.modules.length === 0;
	}

	updateHash(hash) {
		hash.update(`${this.id} `);
		hash.update(this.ids ? this.ids.join(",") : "");
		hash.update(`${this.name || ""} `);
		this.modules.forEach(m => m.updateHash(hash));
	}

	size(options) {
		const CHUNK_OVERHEAD = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
		const ENTRY_CHUNK_MULTIPLICATOR = options.entryChunkMultiplicator || 10;

		const modulesSize = this.modules.reduce((a, b) => {
			return a + b.size();
		}, 0);
		return modulesSize * (this.isInitial() ? ENTRY_CHUNK_MULTIPLICATOR : 1) + CHUNK_OVERHEAD;
	}

	canBeIntegrated(other) {
		if(other.isInitial()) {
			return false;
		}
		if(this.isInitial()) {
			if(other.parents.length !== 1 || other.parents[0] !== this) {
				return false;
			}
		}
		return true;
	}

	integratedSize(other, options) {
		// Chunk if it's possible to integrate this chunk
		if(!this.canBeIntegrated(other)) {
			return false;
		}

		const CHUNK_OVERHEAD = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
		const ENTRY_CHUNK_MULTIPLICATOR = options.entryChunkMultiplicator || 10;

		const mergedModules = this.modules.slice();
		other.modules.forEach(m => {
			if(this.modules.indexOf(m) < 0) {
				mergedModules.push(m);
			}
		}, this);

		const modulesSize = mergedModules.reduce((a, m) => {
			return a + m.size();
		}, 0);
		return modulesSize * (this.isInitial() || other.isInitial() ? ENTRY_CHUNK_MULTIPLICATOR : 1) + CHUNK_OVERHEAD;
	}

	getChunkMaps(includeEntries, realHash) {
		const chunksProcessed = [];
		const chunkHashMap = {};
		const chunkNameMap = {};
		(function addChunk(c) {
			if(chunksProcessed.indexOf(c) >= 0) return;
			chunksProcessed.push(c);
			if(!c.hasRuntime() || includeEntries) {
				chunkHashMap[c.id] = realHash ? c.hash : c.renderedHash;
				if(c.name)
					chunkNameMap[c.id] = c.name;
			}
			c.chunks.forEach(addChunk);
		}(this));
		return {
			hash: chunkHashMap,
			name: chunkNameMap
		};
	}

	sortItems() {
		this.modules.sort(byId);
		this.origins.sort((a, b) => {
			const aIdent = a.module.identifier();
			const bIdent = b.module.identifier();
			if(aIdent < bIdent) return -1;
			if(aIdent > bIdent) return 1;
			return compareLocations(a.loc, b.loc);
		});
		this.origins.forEach(origin => {
			if(origin.reasons)
				origin.reasons.sort();
		});
		this.parents.sort(byId);
		this.chunks.sort(byId);
	}

	toString() {
		return `Chunk[${this.modules.join()}]`;
	}

	checkConstraints() {
		const chunk = this;
		chunk.chunks.forEach((child, idx) => {
			if(chunk.chunks.indexOf(child) !== idx)
				throw new Error(`checkConstraints: duplicate child in chunk ${chunk.debugId} ${child.debugId}`);
			if(child.parents.indexOf(chunk) < 0)
				throw new Error(`checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`);
		});
		chunk.parents.forEach((parent, idx) => {
			if(chunk.parents.indexOf(parent) !== idx)
				throw new Error(`checkConstraints: duplicate parent in chunk ${chunk.debugId} ${parent.debugId}`);
			if(parent.chunks.indexOf(chunk) < 0)
				throw new Error(`checkConstraints: parent missing child ${parent.debugId} <- ${chunk.debugId}`);
		});
	}
}

module.exports = Chunk;
<commit_msg>transfer add logic for module, block, parent, chunk to prototype<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const compareLocations = require("./compareLocations");
let debugId = 1000;
const removeAndDo = require("./removeAndDo");

const byId = (a, b) => {
	if(a.id < b.id) return -1;
	if(b.id < a.id) return 1;
	return 0;
};

class Chunk {

	constructor(name, module, loc) {
		this.id = null;
		this.ids = null;
		this.debugId = debugId++;
		this.name = name;
		this.modules = [];
		this.entrypoints = [];
		this.chunks = [];
		this.parents = [];
		this.blocks = [];
		this.origins = [];
		this.files = [];
		this.rendered = false;
		if(module) {
			this.origins.push({
				module,
				loc,
				name
			});
		}
	}

	get entry() {
		throw new Error("Chunk.entry was removed. Use hasRuntime()");
	}

	set entry(data) {
		throw new Error("Chunk.entry was removed. Use hasRuntime()");
	}

	get initial() {
		throw new Error("Chunk.initial was removed. Use isInitial()");
	}

	set initial(data) {
		throw new Error("Chunk.initial was removed. Use isInitial()");
	}

	hasRuntime() {
		if(this.entrypoints.length === 0) return false;
		return this.entrypoints[0].chunks[0] === this;
	}

	isInitial() {
		return this.entrypoints.length > 0;
	}

	hasEntryModule() {
		return !!this.entryModule;
	}

	addToCollection(collection, item) {
		if(item === this) {
			return false;
		}

		if(collection.indexOf(item) > -1) {
			return false;
		}

		collection.push(item);
		return true;
	}

	addChunk(chunk) {
		return this.addToCollection(this.chunks, chunk);
	}

	addParent(parent) {
		return this.addToCollection(this.parents, parent);
	}

	addModule(module) {
		return this.addToCollection(this.modules, module);
	}

	addBlock(block) {
		return this.addToCollection(this.blocks, block);
	}

	removeModule(module) {
		removeAndDo(this.modules, module, "removeChunk", this);
	}

	removeChunk(chunk) {
		removeAndDo(this.chunks, chunk, "removeParent", this);
	}

	removeParent(chunk) {
		removeAndDo(this.parents, chunk, "removeChunk", this);
	}

	addOrigin(module, loc) {
		this.origins.push({
			module,
			loc,
			name: this.name
		});
	}

	remove(reason) {
		// cleanup modules
		this.modules.slice().forEach(module => {
			module.removeChunk(this);
		});

		// cleanup parents
		this.parents.forEach(parent => {
			// remove this chunk from its parents
			const idx = parent.chunks.indexOf(this);
			if(idx >= 0) {
				parent.chunks.splice(idx, 1);
			}

			// cleanup "sub chunks"
			this.chunks.forEach(chunk => {
				/**
				 * remove this chunk as "intermediary" and connect
				 * it "sub chunks" and parents directly
				 */
				// add parent to each "sub chunk"
				chunk.addParent(parent);
				// add "sub chunk" to parent
				parent.addChunk(chunk);

				// remove this as parent of every "sub chunk"
				const idx = chunk.parents.indexOf(this);
				if(idx >= 0) {
					chunk.parents.splice(idx, 1);
				}
			});
		});

		// cleanup blocks
		this.blocks.forEach(block => {
			const idx = block.chunks.indexOf(this);
			if(idx >= 0) {
				block.chunks.splice(idx, 1);
				if(block.chunks.length === 0) {
					block.chunks = null;
					block.chunkReason = reason;
				}
			}
		});
	}

	moveModule(module, other) {
		module.removeChunk(this);
		module.addChunk(other);
		other.addModule(module);
		module.rewriteChunkInReasons(this, [other]);
	}

	integrate(other, reason) {
		if(!this.canBeIntegrated(other)) {
			return false;
		}

		const otherModules = other.modules.slice();
		otherModules.forEach(m => {
			m.removeChunk(other);
			m.addChunk(this);
			this.addModule(m);
			m.rewriteChunkInReasons(other, [this]);
		}, this);
		other.modules.length = 0;

		const moveChunks = (chunks, kind, onChunk) => {
			chunks.forEach(c => {
				const idx = c[kind].indexOf(other);
				if(idx >= 0) {
					c[kind].splice(idx, 1);
				}
				onChunk(c);
			});
		};
		moveChunks(other.parents, "chunks", c => {
			if(c !== this && this.addParent(c)) {
				c.addChunk(this);
			}
		});
		other.parents.length = 0;
		moveChunks(other.chunks, "parents", c => {
			if(c !== this && this.addChunk(c)) {
				c.addParent(this);
			}
		});
		other.chunks.length = 0;
		other.blocks.forEach(b => {
			b.chunks = (b.chunks || [this]).map(c => {
				return c === other ? this : c;
			}, this);
			b.chunkReason = reason;
			this.addBlock(b);
		}, this);
		other.blocks.length = 0;
		other.origins.forEach(origin => {
			this.origins.push(origin);
		}, this);
		this.origins.forEach(origin => {
			if(!origin.reasons) {
				origin.reasons = [reason];
			} else if(origin.reasons[0] !== reason) {
				origin.reasons.unshift(reason);
			}
		});
		this.chunks = this.chunks.filter(c => {
			return c !== other && c !== this;
		});
		this.parents = this.parents.filter(c => {
			return c !== other && c !== this;
		});
		return true;
	}

	split(newChunk) {
		this.blocks.forEach(b => {
			newChunk.blocks.push(b);
			b.chunks.push(newChunk);
		});
		this.chunks.forEach(c => {
			newChunk.chunks.push(c);
			c.parents.push(newChunk);
		});
		this.parents.forEach(p => {
			p.chunks.push(newChunk);
			newChunk.parents.push(p);
		});
		this.entrypoints.forEach(e => {
			e.insertChunk(newChunk, this);
		});
	}

	isEmpty() {
		return this.modules.length === 0;
	}

	updateHash(hash) {
		hash.update(`${this.id} `);
		hash.update(this.ids ? this.ids.join(",") : "");
		hash.update(`${this.name || ""} `);
		this.modules.forEach(m => m.updateHash(hash));
	}

	size(options) {
		const CHUNK_OVERHEAD = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
		const ENTRY_CHUNK_MULTIPLICATOR = options.entryChunkMultiplicator || 10;

		const modulesSize = this.modules.reduce((a, b) => {
			return a + b.size();
		}, 0);
		return modulesSize * (this.isInitial() ? ENTRY_CHUNK_MULTIPLICATOR : 1) + CHUNK_OVERHEAD;
	}

	canBeIntegrated(other) {
		if(other.isInitial()) {
			return false;
		}
		if(this.isInitial()) {
			if(other.parents.length !== 1 || other.parents[0] !== this) {
				return false;
			}
		}
		return true;
	}

	integratedSize(other, options) {
		// Chunk if it's possible to integrate this chunk
		if(!this.canBeIntegrated(other)) {
			return false;
		}

		const CHUNK_OVERHEAD = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
		const ENTRY_CHUNK_MULTIPLICATOR = options.entryChunkMultiplicator || 10;

		const mergedModules = this.modules.slice();
		other.modules.forEach(m => {
			if(this.modules.indexOf(m) < 0) {
				mergedModules.push(m);
			}
		}, this);

		const modulesSize = mergedModules.reduce((a, m) => {
			return a + m.size();
		}, 0);
		return modulesSize * (this.isInitial() || other.isInitial() ? ENTRY_CHUNK_MULTIPLICATOR : 1) + CHUNK_OVERHEAD;
	}

	getChunkMaps(includeEntries, realHash) {
		const chunksProcessed = [];
		const chunkHashMap = {};
		const chunkNameMap = {};
		(function addChunk(c) {
			if(chunksProcessed.indexOf(c) >= 0) return;
			chunksProcessed.push(c);
			if(!c.hasRuntime() || includeEntries) {
				chunkHashMap[c.id] = realHash ? c.hash : c.renderedHash;
				if(c.name)
					chunkNameMap[c.id] = c.name;
			}
			c.chunks.forEach(addChunk);
		}(this));
		return {
			hash: chunkHashMap,
			name: chunkNameMap
		};
	}

	sortItems() {
		this.modules.sort(byId);
		this.origins.sort((a, b) => {
			const aIdent = a.module.identifier();
			const bIdent = b.module.identifier();
			if(aIdent < bIdent) return -1;
			if(aIdent > bIdent) return 1;
			return compareLocations(a.loc, b.loc);
		});
		this.origins.forEach(origin => {
			if(origin.reasons)
				origin.reasons.sort();
		});
		this.parents.sort(byId);
		this.chunks.sort(byId);
	}

	toString() {
		return `Chunk[${this.modules.join()}]`;
	}

	checkConstraints() {
		const chunk = this;
		chunk.chunks.forEach((child, idx) => {
			if(chunk.chunks.indexOf(child) !== idx)
				throw new Error(`checkConstraints: duplicate child in chunk ${chunk.debugId} ${child.debugId}`);
			if(child.parents.indexOf(chunk) < 0)
				throw new Error(`checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`);
		});
		chunk.parents.forEach((parent, idx) => {
			if(chunk.parents.indexOf(parent) !== idx)
				throw new Error(`checkConstraints: duplicate parent in chunk ${chunk.debugId} ${parent.debugId}`);
			if(parent.chunks.indexOf(chunk) < 0)
				throw new Error(`checkConstraints: parent missing child ${parent.debugId} <- ${chunk.debugId}`);
		});
	}
}

module.exports = Chunk;
<|endoftext|>


<commit_before>"use strict";

var expect = chai.expect;
var _actualSinon = sinon;
var instanceId = respoke.makeGUID();
var connectionId = respoke.makeGUID();

var client = respoke.createClient({
    instanceId: instanceId
});

describe("A respoke.Endpoint", function () {
    var endpoint;
    var endpointId;

    beforeEach(function () {
        sinon = sinon.sandbox.create();
        endpointId = respoke.makeGUID();
        endpoint = client.getEndpoint({
            connectionId: connectionId,
            id: endpointId,
            gloveColor: "white"
        });
    });

    afterEach(function () {
        sinon.restore();
        sinon = _actualSinon;

    });

    describe("it's object structure", function () {
        it("extends respoke.EventEmitter.", function () {
            expect(typeof endpoint.listen).to.equal('function');
            expect(typeof endpoint.ignore).to.equal('function');
            expect(typeof endpoint.fire).to.equal('function');
        });

        it("extends respoke.Presentable.", function () {
            expect(typeof endpoint.getPresence).to.equal('function');
            expect(typeof endpoint.setPresence).to.equal('function');
        });

        it("has the correct class name.", function () {
            expect(endpoint.className).to.equal('respoke.Endpoint');
        });

        it("contains some important methods.", function () {
            expect(typeof endpoint.sendMessage).to.equal('function');
            expect(typeof endpoint.resolvePresence).to.equal('function');
            expect(typeof endpoint.startAudioCall).to.equal('function');
            expect(typeof endpoint.startVideoCall).to.equal('function');
            expect(typeof endpoint.startCall).to.equal('function');
            expect(typeof endpoint.startDirectConnection).to.equal('function');
            expect(typeof endpoint.startScreenShare).to.equal('function');
        });

        it("can set and get presence and fires the correct event.", function () {
            var newPresence = 'xa';

            sinon.spy(endpoint, "fire");
            try {
                endpoint.setPresence({
                    presence: newPresence,
                    connectionId: connectionId
                });

                expect(endpoint.getPresence()).to.equal(newPresence);
                expect(endpoint.fire.calledWith('presence')).to.equal(true);
            } finally {
                endpoint.fire.restore();
            }
        });

        it("saves unexpected developer-specified parameters.", function () {
            expect(endpoint.gloveColor).to.equal('white');
        });

        it("doesn't expose the signaling channel", function () {
            expect(endpoint.signalingChannel).to.not.exist;
            expect(endpoint.getSignalingChannel).to.not.exist;
        });
    });

    describe("when not connected", function () {
        describe("sendMessage()", function () {
            it("throws an error", function (done) {
                endpoint.sendMessage({
                    message: "Ain't nobody got time fo dat."
                }).then(function success() {
                    done(new Error("Shouldn't be able to send a message when not connected!"));
                }).catch(function failure(err) {
                    expect(err.message).to.contain("not connected");
                    done();
                });
            });
        });

        describe("startAudioCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startAudioCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startVideoCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startVideoCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startDirectConnection()", function () {
            it("throws an error", function success(done) {
                endpoint.startDirectConnection().then(function failure() {
                    done(new Error("User presence succeeded with no connection!"));
                }, function (err) {
                    expect(err.message).to.contain("not connected");
                    done();
                });
            });
        });

        describe("resolvePresence()", function () {
            describe("when only one connection", function () {
                ['chat', 'available', 'away', 'dnd', 'xa', 'unavailable'].forEach(function (presString) {
                    describe("when presence is set to '" + presString + "'", function () {
                        it("endpoint.presence equals '" + presString + "'", function () {
                            endpoint.connections = [{presence: presString}];
                            endpoint.resolvePresence();
                            expect(endpoint.presence).to.equal(presString);
                        });
                    });
                });
            });

            describe("when there are two connections", function () {
                var presenceStrings = ['chat', 'available', 'away', 'dnd', 'xa', 'unavailable'];
                for (var i = 0; i < presenceStrings.length; i += 1) {
                    var presString1 = presenceStrings[i];
                    for (var j = i+1; j < presenceStrings.length; j += 1) {
                        var presString2 = presenceStrings[j];

                        if (presString1 === presString2) {
                            return;
                       }

                        describe("when presence is set to '" + presString1 + "' and '" + presString2 + "'", function (){
                            it("endpoint.presence equals the one that appears first in the array", function () {
                                var presenceToFind;
                                if (presenceStrings.indexOf(presString1) > presenceStrings.indexOf(presString2)) {
                                    presenceToFind = presString2;
                                } else {
                                    presenceToFind = presString1;
                                }

                                endpoint.connections = [{presence: presString1}, {presence: presString2}];
                                endpoint.resolvePresence();
                                expect(endpoint.presence).to.equal(presenceToFind);
                            });
                        });
                    }
                }

                describe("with custom resolve endpoint presence", function () {

                    var customPresence1 = {'myRealPresence': 'not ready'};
                    var customPresence2 = {'myRealPresence': 'not ready'};

                    describe("that returns valid presence", function () {
                        it("endpoint.presence equals expected presence", function () {
                            var tempInstanceId = respoke.makeGUID();
                            var tempConnectionId = respoke.makeGUID();
                            var tempEndpointId = respoke.makeGUID();
                            var expectedPresence = {'myRealPresence': 'ready'};
                            var tempClient = respoke.createClient({
                                instanceId: tempInstanceId,
                                resolveEndpointPresence: function (presenceList) {
                                    expect(presenceList.length).to.equal(3);
                                    expect(presenceList.indexOf(customPresence1)).to.not.equal(-1);
                                    expect(presenceList.indexOf(customPresence2)).to.not.equal(-1);
                                    expect(presenceList.indexOf(expectedPresence)).to.not.equal(-1);
                                    return expectedPresence;
                                }
                            });
                            var ep = tempClient.getEndpoint({
                                connectionId: tempConnectionId,
                                id: tempEndpointId
                            });
                            ep.connections = [{presence: customPresence1}, {presence: expectedPresence}, {presence: customPresence2}];
                            ep.resolvePresence();
                            expect(ep.presence).to.equal(expectedPresence);
                        });
                    });
                    describe("that returns custom presence", function () {
                        it("endpoint.presence equals expected presence", function () {
                            var tempInstanceId = respoke.makeGUID();
                            var tempConnectionId = respoke.makeGUID();
                            var tempEndpointId = respoke.makeGUID();
                            var expectedPresence = 'always and forever';
                            var tempClient = respoke.createClient({
                                instanceId: tempInstanceId,
                                resolveEndpointPresence: function (presenceList) {
                                    return expectedPresence;
                                }
                            });
                            var ep = tempClient.getEndpoint({
                                connectionId: tempConnectionId,
                                id: tempEndpointId
                            });
                            ep.connections = [{presence: customPresence1}, {presence: 'available'}, {presence: customPresence2}];
                            ep.resolvePresence();
                            expect(ep.presence).to.equal(expectedPresence);
                        });
                    });
                });
            });
        });

        describe("getConnection()", function () {
            describe("when there is one connection", function () {
                beforeEach(function () {
                    endpoint.connections = [{
                        id: respoke.makeGUID()
                    }];
                });

                describe("and no connectionId is specified", function () {
                    it("returns the connection", function () {
                        var connection = endpoint.getConnection();
                        expect(connection.id).to.equal(endpoint.connections[0].id);
                    });
                });

                describe("and the connectionId is specified", function () {
                    it("returns the connection", function () {
                        var connection = endpoint.getConnection({
                            connectionId: endpoint.connections[0].id
                        });
                        expect(connection.id).to.equal(endpoint.connections[0].id);
                    });
                });

                describe("and a wrong connectionId is specified", function () {
                    it("returns null", function () {
                        var connection = endpoint.getConnection({
                            connectionId: respoke.makeGUID()
                        });
                        expect(connection).to.equal(null);
                    });
                });
            });
        });
    });

    describe("startScreenShare", function () {

        it("calls startCall", function () {
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(endpoint.startCall.calledOnce).to.equal(true);
        });

        it("sets target = 'screenshare' on params passed to startCall", function () {
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('target', 'screenshare');
        });

        it("sets caller = true on params passed to startCall when params.caller not a boolean", function () {
            // test against a bunch of non-bool things
            ['beef', 1, [], {}, undefined, null].forEach(function (val) {
                sinon.stub(endpoint, 'startCall');

                endpoint.startScreenShare({ caller: val });

                expect(endpoint.startCall.calledOnce).to.equal(true);
                var startCallArgs = endpoint.startCall.firstCall.args[0];
                expect(startCallArgs).to.include.property('caller', true);
                endpoint.startCall.restore();
            });
        });

        it("sets params.sendOnly = true when params.caller = true", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare({ caller: true });

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('sendOnly', true);
        });

        it("sets constraints to result of getScreenShareConstraints when params.caller = true", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(respoke.getScreenShareConstraints.calledOnce).to.equal(true);
            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('constraints');
            expect(startCallArgs.constraints).to.deep.equal({ foo: 'bar' });
        });

        it("sets params.receiveOnly = true when !params.caller", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare({ caller: false });

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('receiveOnly', true);
        });
    });
});
<commit_msg>fixing jshint<commit_after>"use strict";
/* global sinon: true */

var expect = chai.expect;
var _actualSinon = sinon;
var instanceId = respoke.makeGUID();
var connectionId = respoke.makeGUID();

var client = respoke.createClient({
    instanceId: instanceId
});

describe("A respoke.Endpoint", function () {
    var endpoint;
    var endpointId;

    beforeEach(function () {
        sinon = sinon.sandbox.create();
        endpointId = respoke.makeGUID();
        endpoint = client.getEndpoint({
            connectionId: connectionId,
            id: endpointId,
            gloveColor: "white"
        });
    });

    afterEach(function () {
        sinon.restore();
        sinon = _actualSinon;

    });

    describe("it's object structure", function () {
        it("extends respoke.EventEmitter.", function () {
            expect(typeof endpoint.listen).to.equal('function');
            expect(typeof endpoint.ignore).to.equal('function');
            expect(typeof endpoint.fire).to.equal('function');
        });

        it("extends respoke.Presentable.", function () {
            expect(typeof endpoint.getPresence).to.equal('function');
            expect(typeof endpoint.setPresence).to.equal('function');
        });

        it("has the correct class name.", function () {
            expect(endpoint.className).to.equal('respoke.Endpoint');
        });

        it("contains some important methods.", function () {
            expect(typeof endpoint.sendMessage).to.equal('function');
            expect(typeof endpoint.resolvePresence).to.equal('function');
            expect(typeof endpoint.startAudioCall).to.equal('function');
            expect(typeof endpoint.startVideoCall).to.equal('function');
            expect(typeof endpoint.startCall).to.equal('function');
            expect(typeof endpoint.startDirectConnection).to.equal('function');
            expect(typeof endpoint.startScreenShare).to.equal('function');
        });

        it("can set and get presence and fires the correct event.", function () {
            var newPresence = 'xa';

            sinon.spy(endpoint, "fire");
            try {
                endpoint.setPresence({
                    presence: newPresence,
                    connectionId: connectionId
                });

                expect(endpoint.getPresence()).to.equal(newPresence);
                expect(endpoint.fire.calledWith('presence')).to.equal(true);
            } finally {
                endpoint.fire.restore();
            }
        });

        it("saves unexpected developer-specified parameters.", function () {
            expect(endpoint.gloveColor).to.equal('white');
        });

        it("doesn't expose the signaling channel", function () {
            expect(endpoint.signalingChannel).to.not.exist;
            expect(endpoint.getSignalingChannel).to.not.exist;
        });
    });

    describe("when not connected", function () {
        describe("sendMessage()", function () {
            it("throws an error", function (done) {
                endpoint.sendMessage({
                    message: "Ain't nobody got time fo dat."
                }).then(function success() {
                    done(new Error("Shouldn't be able to send a message when not connected!"));
                }).catch(function failure(err) {
                    expect(err.message).to.contain("not connected");
                    done();
                });
            });
        });

        describe("startAudioCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startAudioCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startVideoCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startVideoCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startCall()", function () {
            it("throws an error", function () {
                var call;
                try {
                    call = endpoint.startCall();
                } catch (err) {
                    expect(err.message).to.contain("not connected");
                }
                expect(call).to.be.undefined;
            });
        });

        describe("startDirectConnection()", function () {
            it("throws an error", function success(done) {
                endpoint.startDirectConnection().then(function failure() {
                    done(new Error("User presence succeeded with no connection!"));
                }, function (err) {
                    expect(err.message).to.contain("not connected");
                    done();
                });
            });
        });

        describe("resolvePresence()", function () {
            describe("when only one connection", function () {
                ['chat', 'available', 'away', 'dnd', 'xa', 'unavailable'].forEach(function (presString) {
                    describe("when presence is set to '" + presString + "'", function () {
                        it("endpoint.presence equals '" + presString + "'", function () {
                            endpoint.connections = [{presence: presString}];
                            endpoint.resolvePresence();
                            expect(endpoint.presence).to.equal(presString);
                        });
                    });
                });
            });

            describe("when there are two connections", function () {
                var presenceStrings = ['chat', 'available', 'away', 'dnd', 'xa', 'unavailable'];
                for (var i = 0; i < presenceStrings.length; i += 1) {
                    var presString1 = presenceStrings[i];
                    for (var j = i+1; j < presenceStrings.length; j += 1) {
                        var presString2 = presenceStrings[j];

                        if (presString1 === presString2) {
                            return;
                       }

                        describe("when presence is set to '" + presString1 + "' and '" + presString2 + "'", function (){
                            it("endpoint.presence equals the one that appears first in the array", function () {
                                var presenceToFind;
                                if (presenceStrings.indexOf(presString1) > presenceStrings.indexOf(presString2)) {
                                    presenceToFind = presString2;
                                } else {
                                    presenceToFind = presString1;
                                }

                                endpoint.connections = [{presence: presString1}, {presence: presString2}];
                                endpoint.resolvePresence();
                                expect(endpoint.presence).to.equal(presenceToFind);
                            });
                        });
                    }
                }

                describe("with custom resolve endpoint presence", function () {

                    var customPresence1 = {'myRealPresence': 'not ready'};
                    var customPresence2 = {'myRealPresence': 'not ready'};

                    describe("that returns valid presence", function () {
                        it("endpoint.presence equals expected presence", function () {
                            var tempInstanceId = respoke.makeGUID();
                            var tempConnectionId = respoke.makeGUID();
                            var tempEndpointId = respoke.makeGUID();
                            var expectedPresence = {'myRealPresence': 'ready'};
                            var tempClient = respoke.createClient({
                                instanceId: tempInstanceId,
                                resolveEndpointPresence: function (presenceList) {
                                    expect(presenceList.length).to.equal(3);
                                    expect(presenceList.indexOf(customPresence1)).to.not.equal(-1);
                                    expect(presenceList.indexOf(customPresence2)).to.not.equal(-1);
                                    expect(presenceList.indexOf(expectedPresence)).to.not.equal(-1);
                                    return expectedPresence;
                                }
                            });
                            var ep = tempClient.getEndpoint({
                                connectionId: tempConnectionId,
                                id: tempEndpointId
                            });
                            ep.connections = [{presence: customPresence1}, {presence: expectedPresence}, {presence: customPresence2}];
                            ep.resolvePresence();
                            expect(ep.presence).to.equal(expectedPresence);
                        });
                    });
                    describe("that returns custom presence", function () {
                        it("endpoint.presence equals expected presence", function () {
                            var tempInstanceId = respoke.makeGUID();
                            var tempConnectionId = respoke.makeGUID();
                            var tempEndpointId = respoke.makeGUID();
                            var expectedPresence = 'always and forever';
                            var tempClient = respoke.createClient({
                                instanceId: tempInstanceId,
                                resolveEndpointPresence: function (presenceList) {
                                    return expectedPresence;
                                }
                            });
                            var ep = tempClient.getEndpoint({
                                connectionId: tempConnectionId,
                                id: tempEndpointId
                            });
                            ep.connections = [{presence: customPresence1}, {presence: 'available'}, {presence: customPresence2}];
                            ep.resolvePresence();
                            expect(ep.presence).to.equal(expectedPresence);
                        });
                    });
                });
            });
        });

        describe("getConnection()", function () {
            describe("when there is one connection", function () {
                beforeEach(function () {
                    endpoint.connections = [{
                        id: respoke.makeGUID()
                    }];
                });

                describe("and no connectionId is specified", function () {
                    it("returns the connection", function () {
                        var connection = endpoint.getConnection();
                        expect(connection.id).to.equal(endpoint.connections[0].id);
                    });
                });

                describe("and the connectionId is specified", function () {
                    it("returns the connection", function () {
                        var connection = endpoint.getConnection({
                            connectionId: endpoint.connections[0].id
                        });
                        expect(connection.id).to.equal(endpoint.connections[0].id);
                    });
                });

                describe("and a wrong connectionId is specified", function () {
                    it("returns null", function () {
                        var connection = endpoint.getConnection({
                            connectionId: respoke.makeGUID()
                        });
                        expect(connection).to.equal(null);
                    });
                });
            });
        });
    });

    describe("startScreenShare", function () {

        it("calls startCall", function () {
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(endpoint.startCall.calledOnce).to.equal(true);
        });

        it("sets target = 'screenshare' on params passed to startCall", function () {
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('target', 'screenshare');
        });

        it("sets caller = true on params passed to startCall when params.caller not a boolean", function () {
            // test against a bunch of non-bool things
            ['beef', 1, [], {}, undefined, null].forEach(function (val) {
                sinon.stub(endpoint, 'startCall');

                endpoint.startScreenShare({ caller: val });

                expect(endpoint.startCall.calledOnce).to.equal(true);
                var startCallArgs = endpoint.startCall.firstCall.args[0];
                expect(startCallArgs).to.include.property('caller', true);
                endpoint.startCall.restore();
            });
        });

        it("sets params.sendOnly = true when params.caller = true", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare({ caller: true });

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('sendOnly', true);
        });

        it("sets constraints to result of getScreenShareConstraints when params.caller = true", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare();

            expect(respoke.getScreenShareConstraints.calledOnce).to.equal(true);
            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('constraints');
            expect(startCallArgs.constraints).to.deep.equal({ foo: 'bar' });
        });

        it("sets params.receiveOnly = true when !params.caller", function () {
            sinon.stub(respoke, 'getScreenShareConstraints').returns({ foo: 'bar' });
            sinon.stub(endpoint, 'startCall');

            endpoint.startScreenShare({ caller: false });

            expect(endpoint.startCall.calledOnce).to.equal(true);
            var startCallArgs = endpoint.startCall.firstCall.args[0];
            expect(startCallArgs).to.include.property('receiveOnly', true);
        });
    });
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

// Listen for escape key being pressed and call `onEscape`
export default class EscapeListener extends React.Component {
  constructor(props) {
    super(props);
    this.onKeyUp = this.onKeyUp.bind(this);
    this.onClick = this.onClick.bind(this);
  }

  onKeyUp(e) {
    const {onEscape} = this.props;
    if (e.which === 27) onEscape();
  }

  onClick(e) {
    const {escapeOnUnhandledClick, onEscape} = this.props;
    if (escapeOnUnhandledClick) onEscape();
  }

  render() {
    const {className, children, style} = this.props;
    const classNameString = _.compact([className, 'EscapeListener']).join(' ');
    return (

{children}

    );
  }
}
EscapeListener.propTypes = {
  onEscape: PropTypes.func.isRequired,
  children: PropTypes.node.isRequired,
  escapeOnUnhandledClick: PropTypes.bool,
  className: PropTypes.string,
  style: PropTypes.object
};

<commit_msg>Smaller change to EscapeListener<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

// Listen for escape key being pressed and call `onEscape`
export default class EscapeListener extends React.Component {
  constructor(props) {
    super(props);
    this.onKeyUp = this.onKeyUp.bind(this);
    this.onClick = this.onClick.bind(this);
  }

  onKeyUp(e) {
    const {onEscape} = this.props;
    if (e.which === 27) onEscape();
  }

  onClick(e) {
    const {escapeOnUnhandledClick, onEscape} = this.props;
    if (escapeOnUnhandledClick) onEscape();
  }

  render() {
    const {className, children, style, escapeOnUnhandledClick} = this.props;
    const classNameString = _.compact([className, 'EscapeListener']).join(' ');
    return (

{children}

    );
  }
}
EscapeListener.propTypes = {
  onEscape: PropTypes.func.isRequired,
  children: PropTypes.node.isRequired,
  escapeOnUnhandledClick: PropTypes.bool,
  className: PropTypes.string,
  style: PropTypes.object
};

<|endoftext|>


<commit_before>"use strict";

var cp = require('child_process');
var path = require('path');

var Commits = require('./commits');
var Cache = require('./cache');
var utils = require('./utils');

var spawn = cp.spawn;
var basename = path.basename;
var debug = require('debug')('pushstack');

var Repo = module.exports = function Repo(dir) {
    this.name = basename(dir);
    this.path = dir;
    this.cache = new Cache();

    this.memoize();
};

Repo.prototype.parse = function parse(text, ref) {
    text = text.toString();
    return text.split('\n').map(function(line) {
        var o = {
            'mode': line.slice(0, 6),
            'type': line.slice(7, 11),
            'hash': line.slice(12, 52),
            'path': line.slice(53)
        };
        o.path += (o.type == 'tree') ? '/' : '';
        o.name = basename(o.path);
        //TODO: Doesn't belong here
        o.url = utils.url('', this.name, o.type, ref, o.path);
        return o;
    }, this);
};

Repo.prototype.dirStat = function dirStat(ref ,path, fileList, cb) {
    var commits = [],
        expected = fileList.length;

    fileList.forEach(function(entry, index) {
        this.stats(ref, entry, 1, function(err, commit) {
            if(err) throw err;
            commits[index] = commit;
            if(commits.length == expected) {
                cb(null, commits);
            }
        });
    }, this);
    return commits;
};

Repo.prototype.memoize = function memoize() {
    debug('cache: building');
    this.branches(utils.noop);
    this.tags(utils.noop);
};

Repo.prototype.flush = function flush() {
    debug('cache: flush');
    this.cache.del('branches');
    this.cache.del('tags');
};

// https://github.com/creationix/node-git/blob/master/lib/git-fs.js
Repo.prototype.gitExec = function gitExec(commands, cb) {
    commands.unshift('--git-dir=' + this.path);
    var child = spawn("git", commands);
    var stdout = [], stderr = [];
    child.stdout.addListener('data', function (text) {
        stdout[stdout.length] = text;
    });
    child.stderr.addListener('data', function (text) {
        stderr[stderr.length] = text;
    });
    child.addListener('exit', function (code) {
        if (code > 0) {
            var err = new Error("git " + commands.join(" ") + "\n" + utils.bufferConcat(stderr, 'utf8'));
            cb(err);
            return;
        }
        cb(null, utils.bufferConcat(stdout));
    });
    child.stdin.end();
};

Repo.prototype.stats = function stats(ref, entry) {
    var cb = utils.noop,
        maxcount = 0,
        skip = 0,
        len = arguments.length,
        args = ['log', ref, '--date=relative'];

    if(typeof entry === 'string') {
        entry = { path: entry };
    }
    if(len === 3) {
        cb = arguments[2];
    }
    if(len === 4) {
        maxcount = arguments[2];
        cb = arguments[3];
    }
    if(len === 5) {
        maxcount = arguments[2];
        skip = arguments[3];
        cb = arguments[4];
    }
    if(maxcount >= 1) {
        args.push('--max-count=' + maxcount);
    }
    if(skip > 0) {
        args.push('--skip=' + skip);
    }

    args.push('--', entry.path);

    this.gitExec(args, function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            entry.commits = new Commits(stdout);
            entry.tip = entry.commits.tip();
            return cb(null, entry);
        }
    }.bind(this));
};

Repo.prototype.tip = function tip(ref, cb) {
    debug('tip for ref "%s"', ref);
    this.gitExec(['log', ref, '-n1', '--date=relative', '--', '.'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            var c = new Commits(stdout);
            return cb(null, c.tip());
        }
    }.bind(this));
};

Repo.prototype.tree = function tree(ref, path, cb) {
    var directories, files;

    debug('tree for path "%s"', path);
    this.gitExec(['ls-tree', ref, path], function(err, stdout) {
        if(err) { cb(err); }

        var entries = this.parse(stdout, ref);
        directories = entries.filter(function(entry) {
            return entry.type == 'tree';
        });
        files = entries.filter(function(entry) {
            return entry.type == 'blob';
        });
        directories.sort();
        files.sort();
        entries = directories.concat(files);

        this.dirStat(ref, path, entries, function(err, tree) {
            if(err) { return cb(err); }
            cb(null, tree);
        });
    }.bind(this));
};

Repo.prototype.blob = function blob(ref, path, cb) {
    debug('blob for path "%s"', path);
    this.gitExec(['show', ref + ':' + path], cb);
};

Repo.prototype.tags = function tags(cb) {
    var out;

    if(this.cache.has('tags')) {
        debug('tags: fetching from cache');
        return cb(null, this.cache.get('tags'));
    }

    this.gitExec(['tag', '-l'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            out = stdout.toString().split('\n').filter(utils.not(''));
            debug('tags: storing in cache, [%s]', out.join());
            this.cache.store('tags', out);
            return cb(null, out);
        }
    }.bind(this));
};

Repo.prototype.branches = function branches(cb) {
    var lines;

    if(this.cache.has('branches')) {
        debug('branches: fetching from cache');
        return cb(null, this.cache.get('branches'));
    }

    this.gitExec(['branch'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            lines = stdout.toString().split('\n');
            lines.pop();
            lines = lines.map(function(line) {
                return line.replace(/^\*\s/, '').trim();
            });
            debug('branches: storing in cache, [%s]', lines.join());
            this.cache.store('branches', lines);
            return cb(null, lines);
        }
    }.bind(this));
};
<commit_msg>Moved url creation into stats<commit_after>"use strict";

var cp = require('child_process');
var path = require('path');

var Commits = require('./commits');
var Cache = require('./cache');
var utils = require('./utils');

var spawn = cp.spawn;
var basename = path.basename;
var debug = require('debug')('pushstack');

var Repo = module.exports = function Repo(dir) {
    this.name = basename(dir);
    this.path = dir;
    this.cache = new Cache();

    this.memoize();
};

Repo.prototype.parse = function parse(text, ref) {
    text = text.toString();
    return text.split('\n').map(function(line) {
        var o = {
            'mode': line.slice(0, 6),
            'type': line.slice(7, 11),
            'hash': line.slice(12, 52),
            'path': line.slice(53)
        };
        o.path += (o.type == 'tree') ? '/' : '';
        o.name = basename(o.path);
        return o;
    }, this);
};

Repo.prototype.dirStat = function dirStat(ref ,path, fileList, cb) {
    var commits = [],
        expected = fileList.length;

    fileList.forEach(function(entry, index) {
        this.stats(ref, entry, 1, function(err, commit) {
            if(err) throw err;
            commits[index] = commit;
            if(commits.length == expected) {
                cb(null, commits);
            }
        });
    }, this);
    return commits;
};

Repo.prototype.memoize = function memoize() {
    debug('cache: building');
    this.branches(utils.noop);
    this.tags(utils.noop);
};

Repo.prototype.flush = function flush() {
    debug('cache: flush');
    this.cache.del('branches');
    this.cache.del('tags');
};

// https://github.com/creationix/node-git/blob/master/lib/git-fs.js
Repo.prototype.gitExec = function gitExec(commands, cb) {
    commands.unshift('--git-dir=' + this.path);
    var child = spawn("git", commands);
    var stdout = [], stderr = [];
    child.stdout.addListener('data', function (text) {
        stdout[stdout.length] = text;
    });
    child.stderr.addListener('data', function (text) {
        stderr[stderr.length] = text;
    });
    child.addListener('exit', function (code) {
        if (code > 0) {
            var err = new Error("git " + commands.join(" ") + "\n" + utils.bufferConcat(stderr, 'utf8'));
            cb(err);
            return;
        }
        cb(null, utils.bufferConcat(stdout));
    });
    child.stdin.end();
};

Repo.prototype.stats = function stats(ref, entry) {
    var cb = utils.noop,
        maxcount = 0,
        skip = 0,
        len = arguments.length,
        args = ['log', ref, '--date=relative'];

    if(typeof entry === 'string') {
        entry = { path: entry };
    }
    if(len === 3) {
        cb = arguments[2];
    }
    if(len === 4) {
        maxcount = arguments[2];
        cb = arguments[3];
    }
    if(len === 5) {
        maxcount = arguments[2];
        skip = arguments[3];
        cb = arguments[4];
    }
    if(maxcount >= 1) {
        args.push('--max-count=' + maxcount);
    }
    if(skip > 0) {
        args.push('--skip=' + skip);
    }

    args.push('--', entry.path);

    this.gitExec(args, function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            entry.commits = new Commits(stdout);
            entry.tip = entry.commits.tip();
            entry.url = utils.url('', this.name, entry.type, ref, entry.path);
            return cb(null, entry);
        }
    }.bind(this));
};

Repo.prototype.tip = function tip(ref, cb) {
    debug('tip for ref "%s"', ref);
    this.gitExec(['log', ref, '-n1', '--date=relative', '--', '.'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            var c = new Commits(stdout);
            return cb(null, c.tip());
        }
    }.bind(this));
};

Repo.prototype.tree = function tree(ref, path, cb) {
    var directories, files;

    debug('tree for path "%s"', path);
    this.gitExec(['ls-tree', ref, path], function(err, stdout) {
        if(err) { cb(err); }

        var entries = this.parse(stdout, ref);
        directories = entries.filter(function(entry) {
            return entry.type == 'tree';
        });
        files = entries.filter(function(entry) {
            return entry.type == 'blob';
        });
        directories.sort();
        files.sort();
        entries = directories.concat(files);

        this.dirStat(ref, path, entries, function(err, tree) {
            if(err) { return cb(err); }
            cb(null, tree);
        });
    }.bind(this));
};

Repo.prototype.blob = function blob(ref, path, cb) {
    debug('blob for path "%s"', path);
    this.gitExec(['show', ref + ':' + path], cb);
};

Repo.prototype.tags = function tags(cb) {
    var out;

    if(this.cache.has('tags')) {
        debug('tags: fetching from cache');
        return cb(null, this.cache.get('tags'));
    }

    this.gitExec(['tag', '-l'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            out = stdout.toString().split('\n').filter(utils.not(''));
            debug('tags: storing in cache, [%s]', out.join());
            this.cache.store('tags', out);
            return cb(null, out);
        }
    }.bind(this));
};

Repo.prototype.branches = function branches(cb) {
    var lines;

    if(this.cache.has('branches')) {
        debug('branches: fetching from cache');
        return cb(null, this.cache.get('branches'));
    }

    this.gitExec(['branch'], function(err, stdout) {
        if(err) {
            return cb(err);
        } else {
            lines = stdout.toString().split('\n');
            lines.pop();
            lines = lines.map(function(line) {
                return line.replace(/^\*\s/, '').trim();
            });
            debug('branches: storing in cache, [%s]', lines.join());
            this.cache.store('branches', lines);
            return cb(null, lines);
        }
    }.bind(this));
};
<|endoftext|>


<commit_before>/**
 * THIS FILE IS GENERATED AUTOMATICALLY.
 * DO NOT EDIT.
 *
 * You are probably looking on adding startup/initialization code.
 * Use "quasar new boot <name>" and add it there.
 * One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
 * boot: ['file', ...] // do not add ".js" extension to it.
 *
 * Boot files are your "main.js"
 **/
import Vue from 'vue'
import './import-quasar.js'

<% if (ctx.mode.ssr) { %>
import <%= framework.importStrategy === 'all' ? 'Quasar' : '{ Quasar }' %> from 'quasar'
<% if (ctx.mode.pwa) { %>
import { isRunningOnPWA } from './ssr-pwa'
<% } %>
<% } %>

import App from 'app/<%= sourceFiles.rootComponent %>'

<% if (store) { %>
import createStore from 'app/<%= sourceFiles.store %>'
<% } %>
import createRouter from 'app/<%= sourceFiles.router %>'

<% if (ctx.mode.capacitor && capacitor.hideSplashscreen !== false) { %>
import { Plugins } from '@capacitor/core'
const { SplashScreen } = Plugins
<% } %>

<% if (__vueDevtools !== false) { %>
import vueDevtools from '@vue/devtools'
<% } %>

export default async function (<%= ctx.mode.ssr ? 'ssrContext' : '' %>) {
  // create store and router instances
  <% if (store) { %>
  const store = typeof createStore === 'function'
    ? await createStore({Vue<%= ctx.mode.ssr ? ', ssrContext' : '' %>})
    : createStore
  <% } %>
  const router = typeof createRouter === 'function'
    ? await createRouter({Vue<%= ctx.mode.ssr ? ', ssrContext' : '' %><%= store ? ', store' : '' %>})
    : createRouter
  <% if (store) { %>
  // make router instance available in store
  store.$router = router
  <% } %>

  // Create the app instantiation Object.
  // Here we inject the router, store to all child components,
  // making them available everywhere as `this.$router` and `this.$store`.
  const app = {
    router,
    <%= store ? 'store,' : '' %>
    render: h => h(App)<% if (__needsAppMountHook === true) { %>,
    mounted () {
      <% if (ctx.mode.capacitor && capacitor.hideSplashscreen !== false) { %>
      SplashScreen.hide()
      <% } %>

      <% if (__vueDevtools !== false) { %>
      vueDevtools.connect('<%= __vueDevtools.host %>', <%= __vueDevtools.port %>)
      <% } %>
    }<% } %>
  }

  <% if (ctx.mode.ssr) { %>
    <% if (ctx.mode.pwa) { %>
  if (isRunningOnPWA === true) {
    app.el = '#q-app'
  }
  else {
    Quasar.ssrUpdate({ app, ssr: ssrContext })
  }
    <% } else { %>
  Quasar.ssrUpdate({ app, ssr: ssrContext })
    <% } %>
  <% } else { %>
  app.el = '#q-app'
  <% } %>

  // expose the app, the router and the store.
  // note we are not mounting the app here, since bootstrapping will be
  // different depending on whether we are in a browser or on the server.
  return {
    app,
    <%= store ? 'store,' : '' %>
    router
  }
}
<commit_msg>fix: using vueDevtools doesn't show tab vuex store (#8462)<commit_after>/**
 * THIS FILE IS GENERATED AUTOMATICALLY.
 * DO NOT EDIT.
 *
 * You are probably looking on adding startup/initialization code.
 * Use "quasar new boot <name>" and add it there.
 * One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
 * boot: ['file', ...] // do not add ".js" extension to it.
 *
 * Boot files are your "main.js"
 **/

<% if (__vueDevtools !== false) { %>
import vueDevtools from '@vue/devtools'
<% } %>

import Vue from 'vue'
import './import-quasar.js'

<% if (ctx.mode.ssr) { %>
import <%= framework.importStrategy === 'all' ? 'Quasar' : '{ Quasar }' %> from 'quasar'
<% if (ctx.mode.pwa) { %>
import { isRunningOnPWA } from './ssr-pwa'
<% } %>
<% } %>

import App from 'app/<%= sourceFiles.rootComponent %>'

<% if (store) { %>
import createStore from 'app/<%= sourceFiles.store %>'
<% } %>
import createRouter from 'app/<%= sourceFiles.router %>'

<% if (ctx.mode.capacitor && capacitor.hideSplashscreen !== false) { %>
import { Plugins } from '@capacitor/core'
const { SplashScreen } = Plugins
<% } %>

export default async function (<%= ctx.mode.ssr ? 'ssrContext' : '' %>) {
  // create store and router instances
  <% if (store) { %>
  const store = typeof createStore === 'function'
    ? await createStore({Vue<%= ctx.mode.ssr ? ', ssrContext' : '' %>})
    : createStore
  <% } %>
  const router = typeof createRouter === 'function'
    ? await createRouter({Vue<%= ctx.mode.ssr ? ', ssrContext' : '' %><%= store ? ', store' : '' %>})
    : createRouter
  <% if (store) { %>
  // make router instance available in store
  store.$router = router
  <% } %>

  // Create the app instantiation Object.
  // Here we inject the router, store to all child components,
  // making them available everywhere as `this.$router` and `this.$store`.
  const app = {
    router,
    <%= store ? 'store,' : '' %>
    render: h => h(App)<% if (__needsAppMountHook === true) { %>,
    mounted () {
      <% if (ctx.mode.capacitor && capacitor.hideSplashscreen !== false) { %>
      SplashScreen.hide()
      <% } %>

      <% if (__vueDevtools !== false) { %>
      vueDevtools.connect('<%= __vueDevtools.host %>', <%= __vueDevtools.port %>)
      <% } %>
    }<% } %>
  }

  <% if (ctx.mode.ssr) { %>
    <% if (ctx.mode.pwa) { %>
  if (isRunningOnPWA === true) {
    app.el = '#q-app'
  }
  else {
    Quasar.ssrUpdate({ app, ssr: ssrContext })
  }
    <% } else { %>
  Quasar.ssrUpdate({ app, ssr: ssrContext })
    <% } %>
  <% } else { %>
  app.el = '#q-app'
  <% } %>

  // expose the app, the router and the store.
  // note we are not mounting the app here, since bootstrapping will be
  // different depending on whether we are in a browser or on the server.
  return {
    app,
    <%= store ? 'store,' : '' %>
    router
  }
}
<|endoftext|>


<commit_before>PuzzleState = Backbone.Model.extend({

    initialize: function(attributes, options) {
        this.tiles = [1,2,3,4,5,6,7,8,0];
        this.depth = 0;
        this.expansionOrder = 0;
        this.heuristicValue = null;
        if (options != null) {
            this.parent = options.parent;
            if (this.parent != null) {
                this.copyFrom(this.parent);
                this.depth = this.parent.depth + 1;
            }
        }
    },

    copyFrom: function(src) {

        if (src.hasOwnProperty('tiles') && $.isArray(src.tiles) && src.tiles.length == 9) {
            this.tiles = src.tiles.slice();
            this.trigger('change');
            return this;
        }

        throw "Invalid source state";
    },

    generateSuccessors: function() {
        var successors = [];
        for (var x = 0; x < 3; x++) {
            for (var y = 0; y < 3; y++) {
                if (this.tiles[x + y * 3] == 0) {
                    var zero = [x, y];
                    if (x > 0) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x - 1, y]);
                        successors.push(newState);
                    }
                    if (x < 2) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x + 1, y]);
                        successors.push(newState);
                    }
                    if (y > 0) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x, y - 1]);
                        successors.push(newState);
                    }
                    if (y < 2) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x, y + 1]);
                        successors.push(newState);
                    }

                    return successors;
                }
            }
        }

        throw "Failed to generate successors.";
    },

    getDepth: function() {
        return this.depth;
    },

    getExpansionOrder: function() {
        return this.expansionOrder;
    },

    getHeuristicValue: function() {
        return this.heuristicValue;
    },

    /**
     *  Returns an identifier that represents the path followed to reach the
     *  given state.
     *
     *  @param  state  the state whose identifier should be constructed
     *
     *  @return a string that can be used to identifier the state
     */
    getLongIdentifier: function() {
        var s = this.toString();
        var p = this.getParent();
        while (p != null) {
            s = p.toString() + ':' + s;
            p = p.getParent();
        }
        return s;
    },

    getParent: function() {
        return this.parent;
    },

    getTile: function(x, y) {

        if (x < 0 || x > 2 || y < 0 || y > 2) {
            throw "Tile position is out of bounds.";
        }

        return this.tiles[x + y * 3];
    },

    isEqualTo: function(other) {
        if (typeof other == typeof this) {
            return other.toString() === this.toString();
        }
        return false;
    },

    setExpansionOrder: function(value) {
        this.expansionOrder = value;
    },

    setHeuristicValue: function(value) {
        this.heuristicValue = value;
    },

    setTile: function(x, y, tile) {

        if (x < 0 || x > 2 || y < 0 || y > 2) {
            throw "Tile position is out of bounds.";
        }

        if (tile < 0 || tile > 8) {
            throw "Tile value is out of bounds.";
        }

        // If the current tile value is the same as the one that will be set
        // we can return early.
        var current = this.tiles[x + y * 3];
        if (current == tile) {
            return;
        }

        // Find where the tile value has been used previously and replace that
        // tile's value with the previous value of the current tile
        for (var dx = 0; dx < 3; dx++) {
            for (var dy = 0; dy < 3; dy++) {
                if (this.tiles[dx + dy * 3] == tile) {
                    this.tiles[dx + dy * 3] = current;
                    this.tiles[x + y * 3] = tile;
                    this.trigger('change');
                    return this;
                }
            }
        }

        // An error occurred while trying to re-assign the previous value of
        // this tile to the available location.
        throw ("Failed to set tile at (" + x + "," + y + ") to " + tile);
    },

    setTiles: function(tiles) {
        if (tiles.length != 9) {
            throw "Tile array must have a length of 9.";
        }

        // Validate input
        var valuesUsed = [];
        for (var i = 0; i < 9; i++) {
            var newTile = tiles[i];
            if (Util.isInteger(newTile) && newTile >= 0 && newTile <= 8) {
                if (valuesUsed.indexOf(tiles[i]) == -1) {
                    valuesUsed.push(tiles[i]);
                    continue;
                }
            }

            throw "Tile array must use all the values 0 through 8 exactly once each.";
        }

        for (var i = 0; i < 9; i++) {
            this.tiles[i] = tiles[i];
        }

        this.trigger('change');
    },

    swapTiles: function(a, b) {

        if (a[0] < 0 || a[0] > 2 || a[1] < 0 || a[1] > 2) {
            throw "Tile position for first tile is out of bounds.";
        }

        if (b[0] < 0 || b[0] > 2 || b[1] < 0 || b[1] > 2) {
            throw "Tile position for first tile is out of bounds.";
        }

        var tmp = this.tiles[a[0] + a[1] * 3];
        this.tiles[a[0] + a[1] * 3] = this.tiles[b[0] + b[1] * 3];
        this.tiles[b[0] + b[1] * 3] = tmp;

        this.trigger('change');
        return this;
    },

    toString: function() {
        return this.tiles.toString();
    },

    valueOf: function() {
        return this.tiles.valueOf();
    }

});

PuzzleState.calculateEuclideanDistance = function(a, b) {
    var distance = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            // Find the matching tile in puzzle state 'b'
            var found = false;
            for (var dy = 0; dy < 3; dy++) {
                for (var dx = 0; dx < 3; dx++) {
                    if (a.getTile(x, y) == b.getTile(dx, dy)) {
                        // Then add the distance between the tiles' positions
                        var h = Math.abs(dx - x);
                        var v = Math.abs(dy - y);
                        distance += Math.sqrt(v*v + h*h);
                        found = true;
                        break;
                    }
                }
                if (found) {
                    break;
                }
            }
        }
    }
    return distance;
};

PuzzleState.calculateManhattanDistance = function(a, b) {
    var distance = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            if (a.getTile(x, y) != 0) {
                // Find the matching tile in puzzle state 'b'
                var found = false;
                for (var dy = 0; dy < 3; dy++) {
                    for (var dx = 0; dx < 3; dx++) {
                        if (a.getTile(x, y) == b.getTile(dx, dy)) {
                            distance += Math.abs(dx - x);
                            distance += Math.abs(dy - y);
                            found = true;
                            break;
                        }
                    }
                    if (found) {
                        break;
                    }
                }
            }
        }
    }
    return distance;
};

PuzzleState.calculateTilesOutOfPlace = function(a, b) {
    var tilesOutOfPlace = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            var tile = a.getTile(x, y);
            if (tile != 0) {
                if (tile != b.getTile(x, y)) {
                    tilesOutOfPlace++;
                }
            }
        }
    }
    return tilesOutOfPlace;
};
<commit_msg>Fix rounding discrepancies in euclidean distance heuristic.<commit_after>PuzzleState = Backbone.Model.extend({

    initialize: function(attributes, options) {
        this.tiles = [1,2,3,4,5,6,7,8,0];
        this.depth = 0;
        this.expansionOrder = 0;
        this.heuristicValue = null;
        if (options != null) {
            this.parent = options.parent;
            if (this.parent != null) {
                this.copyFrom(this.parent);
                this.depth = this.parent.depth + 1;
            }
        }
    },

    copyFrom: function(src) {

        if (src.hasOwnProperty('tiles') && $.isArray(src.tiles) && src.tiles.length == 9) {
            this.tiles = src.tiles.slice();
            this.trigger('change');
            return this;
        }

        throw "Invalid source state";
    },

    generateSuccessors: function() {
        var successors = [];
        for (var x = 0; x < 3; x++) {
            for (var y = 0; y < 3; y++) {
                if (this.tiles[x + y * 3] == 0) {
                    var zero = [x, y];
                    if (x > 0) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x - 1, y]);
                        successors.push(newState);
                    }
                    if (x < 2) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x + 1, y]);
                        successors.push(newState);
                    }
                    if (y > 0) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x, y - 1]);
                        successors.push(newState);
                    }
                    if (y < 2) {
                        var newState = new PuzzleState({}, {parent: this});
                        newState.swapTiles(zero, [x, y + 1]);
                        successors.push(newState);
                    }

                    return successors;
                }
            }
        }

        throw "Failed to generate successors.";
    },

    getDepth: function() {
        return this.depth;
    },

    getExpansionOrder: function() {
        return this.expansionOrder;
    },

    getHeuristicValue: function() {
        return this.heuristicValue;
    },

    /**
     *  Returns an identifier that represents the path followed to reach the
     *  given state.
     *
     *  @param  state  the state whose identifier should be constructed
     *
     *  @return a string that can be used to identifier the state
     */
    getLongIdentifier: function() {
        var s = this.toString();
        var p = this.getParent();
        while (p != null) {
            s = p.toString() + ':' + s;
            p = p.getParent();
        }
        return s;
    },

    getParent: function() {
        return this.parent;
    },

    getTile: function(x, y) {

        if (x < 0 || x > 2 || y < 0 || y > 2) {
            throw "Tile position is out of bounds.";
        }

        return this.tiles[x + y * 3];
    },

    isEqualTo: function(other) {
        if (typeof other == typeof this) {
            return other.toString() === this.toString();
        }
        return false;
    },

    setExpansionOrder: function(value) {
        this.expansionOrder = value;
    },

    setHeuristicValue: function(value) {
        this.heuristicValue = value;
    },

    setTile: function(x, y, tile) {

        if (x < 0 || x > 2 || y < 0 || y > 2) {
            throw "Tile position is out of bounds.";
        }

        if (tile < 0 || tile > 8) {
            throw "Tile value is out of bounds.";
        }

        // If the current tile value is the same as the one that will be set
        // we can return early.
        var current = this.tiles[x + y * 3];
        if (current == tile) {
            return;
        }

        // Find where the tile value has been used previously and replace that
        // tile's value with the previous value of the current tile
        for (var dx = 0; dx < 3; dx++) {
            for (var dy = 0; dy < 3; dy++) {
                if (this.tiles[dx + dy * 3] == tile) {
                    this.tiles[dx + dy * 3] = current;
                    this.tiles[x + y * 3] = tile;
                    this.trigger('change');
                    return this;
                }
            }
        }

        // An error occurred while trying to re-assign the previous value of
        // this tile to the available location.
        throw ("Failed to set tile at (" + x + "," + y + ") to " + tile);
    },

    setTiles: function(tiles) {
        if (tiles.length != 9) {
            throw "Tile array must have a length of 9.";
        }

        // Validate input
        var valuesUsed = [];
        for (var i = 0; i < 9; i++) {
            var newTile = tiles[i];
            if (Util.isInteger(newTile) && newTile >= 0 && newTile <= 8) {
                if (valuesUsed.indexOf(tiles[i]) == -1) {
                    valuesUsed.push(tiles[i]);
                    continue;
                }
            }

            throw "Tile array must use all the values 0 through 8 exactly once each.";
        }

        for (var i = 0; i < 9; i++) {
            this.tiles[i] = tiles[i];
        }

        this.trigger('change');
    },

    swapTiles: function(a, b) {

        if (a[0] < 0 || a[0] > 2 || a[1] < 0 || a[1] > 2) {
            throw "Tile position for first tile is out of bounds.";
        }

        if (b[0] < 0 || b[0] > 2 || b[1] < 0 || b[1] > 2) {
            throw "Tile position for first tile is out of bounds.";
        }

        var tmp = this.tiles[a[0] + a[1] * 3];
        this.tiles[a[0] + a[1] * 3] = this.tiles[b[0] + b[1] * 3];
        this.tiles[b[0] + b[1] * 3] = tmp;

        this.trigger('change');
        return this;
    },

    toString: function() {
        return this.tiles.toString();
    },

    valueOf: function() {
        return this.tiles.valueOf();
    }

});

PuzzleState.calculateEuclideanDistance = function(a, b) {
    var distance = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            // Find the matching tile in puzzle state 'b'
            var found = false;
            for (var dy = 0; dy < 3; dy++) {
                for (var dx = 0; dx < 3; dx++) {
                    if (a.getTile(x, y) == b.getTile(dx, dy)) {
                        // Then add the distance between the tiles' positions
                        var h = Math.abs(dx - x);
                        var v = Math.abs(dy - y);
                        distance += Math.floor(Math.sqrt(v*v + h*h));
                        found = true;
                        break;
                    }
                }
                if (found) {
                    break;
                }
            }
        }
    }
    return distance;
};

PuzzleState.calculateManhattanDistance = function(a, b) {
    var distance = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            if (a.getTile(x, y) != 0) {
                // Find the matching tile in puzzle state 'b'
                var found = false;
                for (var dy = 0; dy < 3; dy++) {
                    for (var dx = 0; dx < 3; dx++) {
                        if (a.getTile(x, y) == b.getTile(dx, dy)) {
                            distance += Math.abs(dx - x);
                            distance += Math.abs(dy - y);
                            found = true;
                            break;
                        }
                    }
                    if (found) {
                        break;
                    }
                }
            }
        }
    }
    return distance;
};

PuzzleState.calculateTilesOutOfPlace = function(a, b) {
    var tilesOutOfPlace = 0;
    // For each tile in puzzle state 'a'
    for (var y = 0; y < 3; y++) {
        for (var x = 0; x < 3; x++) {
            var tile = a.getTile(x, y);
            if (tile != 0) {
                if (tile != b.getTile(x, y)) {
                    tilesOutOfPlace++;
                }
            }
        }
    }
    return tilesOutOfPlace;
};
<|endoftext|>