<commit_before>"use strict"; // jshint unused:false

define([
	'bugfix', 'distance', 'flight', 'log', 'map', 'math', 'waypoints',
	'nav/LNAV', 'nav/progress', 'nav/VNAV', './elements', 'redefine', './position'
], function (bugfix, distance, flight, log, map, math, waypoints, lnav, progress, vnav, E) {

	// Checks if UI has been properly placed
	var timer = setInterval(function () {
		if ($(E.modal)[0] && $(E.btn.fmcBtn)) {
			clearInterval(timer);
			loadFMC();
		}
	}, 4);

	// FMC actions init function
	function loadFMC () {
		var modal = E.modal,
			container = E.container,
			btn = E.btn,
			input = E.input,
			textarea = E.textarea;

		// Adds one input field on start
		waypoints.addWaypoint();

		/* ---- UI actions binding ---- */

		// -----------------------------------------
		// ------------- General Modal -------------
		// -----------------------------------------

		// Modal actions: open/close
		$(modal).on('click', btn.close, function () {
			$(modal).removeClass('opened');
		}).parent().on('click', btn.fmcBtn, function () {
			if ($(modal).hasClass('opened')) $(modal).removeClass('opened');
			else $(modal).addClass('opened');
		});

		// Modal tab contents: toggle
		$(container.tabBar).on('click', 'a', function (event) {
			event.preventDefault();
			var c = 'is-active';
			var $this = $(this);
			var $that = $(container.tabBar).find('.' + c);
			var interactive = $this.attr('interactive');

			// Interactive actions button
			$(btn.interactive).removeClass(c);
			if (interactive) $(interactive).addClass(c);

			$(container.modalContent).find($that.attr('to')).removeClass(c);
			$(container.modalContent).find($this.attr('to')).addClass(c);
			$that.removeClass(c);
			$this.addClass(c);
		});

		// ---------------------------------------
		// -------------- ROUTE TAB --------------
		// ---------------------------------------

		// Save/retrieve waypoints data
		$(modal).on('click', btn.saveWptData, function () {
			waypoints.saveData();
		}).on('click', btn.retrieveWpt, function () {
			waypoints.loadFromSave();
		});

		// Waypoint list actions: activate/add/remove/move up or down
		// FIXME potential item index confusion/mess up
		$(modal).on('click', btn.addWpt, function () {
			waypoints.addWaypoint();
		}).on('click', btn.activateWpt, function () {
			var index = $(this).parents().eq(1).index() - 1;
			waypoints.activateWaypoint(index);
			lnav.update();
		}).on('click', btn.removeWpt, function () {
			var index = $(this).parents().eq(1).index() - 1;
			waypoints.removeWaypoint(index);
		}).on('click', btn.moveWptUp, function () {
			var row = $(this).parents().eq(1);
			waypoints.shiftWaypoint(row, row.index() - 1, 'up');
		}).on('click', btn.moveWptDown, function () {
			var row = $(this).parents().eq(1);
			waypoints.shiftWaypoint(row, row.index() - 1, 'down');
		});

		// Arrival airport input
		$(container.depArr).on('change', input.arr, function () {
			var wpt = $(this).val().trim();
			if (wpt) {
				var coords = waypoints.getCoords(wpt);
				if (coords) flight.arrival = [wpt, coords[0], coords[1]];
				else flight.arrival = [];
			} else flight.arrival = [];
			lnav.update();
		});

		// Waypoint list input actions: update `route` array
		$(container.wptList).on('change', input.wpt, function () {
			var index = $(this).parents().eq(2).index() - 1;

			if (!$(this).parent().hasClass('is-invalid')) {
				var wpt = $(this).val();
				var coords = waypoints.getCoords(wpt);
				if (!coords) {
					var altRes = waypoints.route[index][3];
					$(this).parents().eq(2).find(input.lat).val('').change().parent().removeClass('is-dirty');
					$(this).parents().eq(2).find(input.lon).val('').change().parent().removeClass('is-dirty');
					waypoints.route[index] = [wpt, undefined, undefined, altRes, false];
				} else {
					bugfix.input($(this).parents().eq(2).find(input.lat).val(coords[0]).change());
					bugfix.input($(this).parents().eq(2).find(input.lon).val(coords[1]).change());
					waypoints.route[index] = [wpt, coords[0], coords[1], undefined, true];
				}
			}

			progress.printNextWaypointInfo(index);
		}).on('change', input.lat, function () {
			var index = $(this).parents().eq(2).index() - 1;

			// If lat input is invalid
			if ($(this).parent().hasClass('is-invalid') || !$(this).val() || $(this).val() === '') {
				waypoints.route[index][1] = undefined;
			} else {
				waypoints.route[index][1] = waypoints.formatCoords($(this).val());
				waypoints.route[index][4] = false;
			}

			// Prints next waypoint info regardless
			progress.printNextWaypointInfo(index);

		}).on('change', input.lon, function () {
			var index = $(this).parents().eq(2).index() - 1;

			// If lon input is invalid
			if ($(this).parent().hasClass('is-invalid') || !$(this).val() || $(this).val() === '') {
				waypoints.route[index][2] = undefined;
			} else {
				waypoints.route[index][2] = waypoints.formatCoords($(this).val());
				waypoints.route[index][4] = false;
			}

			// Prints next waypoint info regardless
			progress.printNextWaypointInfo(index);

		}).on('change', input.alt, function () {
			var index = $(this).parents().eq(2).index() - 1;

			if (!$(this).parent().hasClass('is-invalid')) waypoints.route[index][3] = Number($(this).val());
		 	else waypoints.route[index][3] = undefined;
		});

		// -----------------------------------------
		// ---------------- ARR TAB ----------------
		// -----------------------------------------

		// TOD Distance and Field Elevation inputs
		$(container.arrPage).on('change', input.todDist, function () {
			if (!$(this).parent().hasClass('is-invalid')) flight.todDist = Number($(this).val());
			else flight.todDist = 0;
		}).on('change', input.fieldElev, function () {
			if (!$(this).parent().hasClass('is-invalid')) flight.fieldElev = Number($(this).val());
			else flight.fieldElev = undefined;
		});

		// Automatic TOD calculation button
		$(container.autoTOD).on('click', btn.autoTOD, function () {
			if ($(this).parent().hasClass('is-checked'))
				flight.todCalc = false;
			else flight.todCalc = true;

			// Instantly updates VNAV info
			vnav.update();
		});

		// ----------------------------------------
		// --------------- VNAV TAB ---------------
		// ----------------------------------------

		$(btn.vnavToggle).prop('disabled', true).parent().addClass('is-disabled');

		// VNAV, Speed toggle and cruising altitude input
		$(container.vnavPage).on('click', btn.vnavToggle, function () {
			if (flight.cruiseAlt) {
				if ($(this).parent().hasClass('is-checked')) {
					flight.VNAV = false;
					clearInterval(vnav.timer);
				} else {
					flight.VNAV = true;
					vnav.timer = setInterval(function () { vnav.update(); }, 5000);
				}
			}
		}).on('click', btn.spdToggle, function () {
			if ($(this).parent().hasClass('is-checked'))
				flight.spdControl = false;
			else {
				flight.spdControl = true;
				vnav.update();
			}
		}).on('change', input.cruiseAlt, function () {
			// If cruise altitude is an error or is empty (0)
			if ($(this).parent().hasClass('is-invalid') || Number($(this).val().trim()) === 0) {
				// Disables VNAV toggle button
				flight.cruiseAlt = undefined;
				$(btn.vnavToggle).prop('disabled', true)
					.parent().removeClass('is-checked').addClass('is-disabled');
				flight.VNAV = false;
				clearInterval(vnav.timer);
				return;
			}

			// Sets cruise alt and enables vnav toggle button
			flight.cruiseAlt = Number($(this).val().trim());
			$(btn.vnavToggle).prop('disabled', false).parent().removeClass('is-disabled');
			vnav.update();
		});

		// VNAV phase
		$(container.vnavPhase).on('click', btn.togglePhase, function () {
			progress.updatePhase();
		}).on('click', btn.lockPhase, function () {
			if ($(this).hasClass('locked')) $(this).removeClass('locked');
			else $(this).addClass('locked');
		});

		// ----------------------------------------
		// --------------- LOAD TAB ---------------
		// ----------------------------------------

		// Loads waypoints separated by spaces or generated route
		$(container.loadPage).on('click', btn.loadWpt, function () {
			waypoints.toRoute($(input.loadWpt).val().trim());
		});

		// Disables editing on the generated route textarea
		$(textarea.generateRte).prop('disabled', true);

		// Generates an FMC route to the textarea
		$(modal).on('click', btn.generateRte, function () {
			bugfix.input($(textarea.generateRte).val(waypoints.toRouteString()).change());
		}).on('click', btn.clearRte, function () {
			$(textarea.generateRte).val('').change().parent().removeClass('is-dirty');
		});

		// -----------------------------------------
		// ---------------- LOG TAB ----------------
		// -----------------------------------------

		$(modal).on('click', btn.removeLogData, function () {
			log.removeData();
		});

		/* ---- All Initializations ---- */

		// Initializes all timers
		progress.timer = setInterval(function () { progress.update(); }, 5000);
		log.mainTimer = setInterval(function () { log.update(); }, 30000);
		log.speedTimer = setInterval(function () { log.speed(); }, 15000);

	}
});
<commit_msg>Added escape button to exit FMC<commit_after>"use strict"; // jshint unused:false

define([
	'bugfix', 'distance', 'flight', 'log', 'map', 'math', 'waypoints',
	'nav/LNAV', 'nav/progress', 'nav/VNAV', './elements', 'redefine', './position'
], function (bugfix, distance, flight, log, map, math, waypoints, lnav, progress, vnav, E) {

	// Checks if UI has been properly placed
	var timer = setInterval(function () {
		if ($(E.modal)[0] && $(E.btn.fmcBtn)) {
			clearInterval(timer);
			loadFMC();
		}
	}, 4);

	// FMC actions init function
	function loadFMC () {
		var modal = E.modal,
			container = E.container,
			btn = E.btn,
			input = E.input,
			textarea = E.textarea;

		// Adds one input field on start
		waypoints.addWaypoint();

		/* ---- UI actions binding ---- */

		// -----------------------------------------
		// ------------- General Modal -------------
		// -----------------------------------------

		// Modal actions: open/close
		$(modal).on('click', btn.close, function () {
			$(modal).removeClass('opened');
		}).parent().on('click', btn.fmcBtn, function () {
			if ($(modal).hasClass('opened')) $(modal).removeClass('opened');
			else $(modal).addClass('opened');
		}).keydown(function (event) { // Sets escape button to close FMC
			if ((event.which === 27 || event.keyCode === 27) && $(this).is(':visible'))
				$(modal).removeClass('opened');
		});

		// Modal tab contents: toggle
		$(container.tabBar).on('click', 'a', function (event) {
			event.preventDefault();
			var c = 'is-active';
			var $this = $(this);
			var $that = $(container.tabBar).find('.' + c);
			var interactive = $this.attr('interactive');

			// Interactive actions button
			$(btn.interactive).removeClass(c);
			if (interactive) $(interactive).addClass(c);

			$(container.modalContent).find($that.attr('to')).removeClass(c);
			$(container.modalContent).find($this.attr('to')).addClass(c);
			$that.removeClass(c);
			$this.addClass(c);
		});

		// ---------------------------------------
		// -------------- ROUTE TAB --------------
		// ---------------------------------------

		// Save/retrieve waypoints data
		$(modal).on('click', btn.saveWptData, function () {
			waypoints.saveData();
		}).on('click', btn.retrieveWpt, function () {
			waypoints.loadFromSave();
		});

		// Waypoint list actions: activate/add/remove/move up or down
		// FIXME potential item index confusion/mess up
		$(modal).on('click', btn.addWpt, function () {
			waypoints.addWaypoint();
		}).on('click', btn.activateWpt, function () {
			var index = $(this).parents().eq(1).index() - 1;
			waypoints.activateWaypoint(index);
			lnav.update();
		}).on('click', btn.removeWpt, function () {
			var index = $(this).parents().eq(1).index() - 1;
			waypoints.removeWaypoint(index);
		}).on('click', btn.moveWptUp, function () {
			var row = $(this).parents().eq(1);
			waypoints.shiftWaypoint(row, row.index() - 1, 'up');
		}).on('click', btn.moveWptDown, function () {
			var row = $(this).parents().eq(1);
			waypoints.shiftWaypoint(row, row.index() - 1, 'down');
		});

		// Arrival airport input
		$(container.depArr).on('change', input.arr, function () {
			var wpt = $(this).val().trim();
			if (wpt) {
				var coords = waypoints.getCoords(wpt);
				if (coords) flight.arrival = [wpt, coords[0], coords[1]];
				else flight.arrival = [];
			} else flight.arrival = [];
			lnav.update();
		});

		// Waypoint list input actions: update `route` array
		$(container.wptList).on('change', input.wpt, function () {
			var index = $(this).parents().eq(2).index() - 1;

			if (!$(this).parent().hasClass('is-invalid')) {
				var wpt = $(this).val();
				var coords = waypoints.getCoords(wpt);
				if (!coords) {
					var altRes = waypoints.route[index][3];
					$(this).parents().eq(2).find(input.lat).val('').change().parent().removeClass('is-dirty');
					$(this).parents().eq(2).find(input.lon).val('').change().parent().removeClass('is-dirty');
					waypoints.route[index] = [wpt, undefined, undefined, altRes, false];
				} else {
					bugfix.input($(this).parents().eq(2).find(input.lat).val(coords[0]).change());
					bugfix.input($(this).parents().eq(2).find(input.lon).val(coords[1]).change());
					waypoints.route[index] = [wpt, coords[0], coords[1], undefined, true];
				}
			}

			progress.printNextWaypointInfo(index);
		}).on('change', input.lat, function () {
			var index = $(this).parents().eq(2).index() - 1;

			// If lat input is invalid
			if ($(this).parent().hasClass('is-invalid') || !$(this).val() || $(this).val() === '') {
				waypoints.route[index][1] = undefined;
			} else {
				waypoints.route[index][1] = waypoints.formatCoords($(this).val());
				waypoints.route[index][4] = false;
			}

			// Prints next waypoint info regardless
			progress.printNextWaypointInfo(index);

		}).on('change', input.lon, function () {
			var index = $(this).parents().eq(2).index() - 1;

			// If lon input is invalid
			if ($(this).parent().hasClass('is-invalid') || !$(this).val() || $(this).val() === '') {
				waypoints.route[index][2] = undefined;
			} else {
				waypoints.route[index][2] = waypoints.formatCoords($(this).val());
				waypoints.route[index][4] = false;
			}

			// Prints next waypoint info regardless
			progress.printNextWaypointInfo(index);

		}).on('change', input.alt, function () {
			var index = $(this).parents().eq(2).index() - 1;

			if (!$(this).parent().hasClass('is-invalid')) waypoints.route[index][3] = Number($(this).val());
		 	else waypoints.route[index][3] = undefined;
		});

		// -----------------------------------------
		// ---------------- ARR TAB ----------------
		// -----------------------------------------

		// TOD Distance and Field Elevation inputs
		$(container.arrPage).on('change', input.todDist, function () {
			if (!$(this).parent().hasClass('is-invalid')) flight.todDist = Number($(this).val());
			else flight.todDist = 0;
		}).on('change', input.fieldElev, function () {
			if (!$(this).parent().hasClass('is-invalid')) flight.fieldElev = Number($(this).val());
			else flight.fieldElev = undefined;
		});

		// Automatic TOD calculation button
		$(container.autoTOD).on('click', btn.autoTOD, function () {
			if ($(this).parent().hasClass('is-checked'))
				flight.todCalc = false;
			else flight.todCalc = true;

			// Instantly updates VNAV info
			vnav.update();
		});

		// ----------------------------------------
		// --------------- VNAV TAB ---------------
		// ----------------------------------------

		$(btn.vnavToggle).prop('disabled', true).parent().addClass('is-disabled');

		// VNAV, Speed toggle and cruising altitude input
		$(container.vnavPage).on('click', btn.vnavToggle, function () {
			if (flight.cruiseAlt) {
				if ($(this).parent().hasClass('is-checked')) {
					flight.VNAV = false;
					clearInterval(vnav.timer);
				} else {
					flight.VNAV = true;
					vnav.timer = setInterval(function () { vnav.update(); }, 5000);
				}
			}
		}).on('click', btn.spdToggle, function () {
			if ($(this).parent().hasClass('is-checked'))
				flight.spdControl = false;
			else {
				flight.spdControl = true;
				vnav.update();
			}
		}).on('change', input.cruiseAlt, function () {
			// If cruise altitude is an error or is empty (0)
			if ($(this).parent().hasClass('is-invalid') || Number($(this).val().trim()) === 0) {
				// Disables VNAV toggle button
				flight.cruiseAlt = undefined;
				$(btn.vnavToggle).prop('disabled', true)
					.parent().removeClass('is-checked').addClass('is-disabled');
				flight.VNAV = false;
				clearInterval(vnav.timer);
				return;
			}

			// Sets cruise alt and enables vnav toggle button
			flight.cruiseAlt = Number($(this).val().trim());
			$(btn.vnavToggle).prop('disabled', false).parent().removeClass('is-disabled');
			vnav.update();
		});

		// VNAV phase
		$(container.vnavPhase).on('click', btn.togglePhase, function () {
			progress.updatePhase();
		}).on('click', btn.lockPhase, function () {
			if ($(this).hasClass('locked')) $(this).removeClass('locked');
			else $(this).addClass('locked');
		});

		// ----------------------------------------
		// --------------- LOAD TAB ---------------
		// ----------------------------------------

		// Loads waypoints separated by spaces or generated route
		$(container.loadPage).on('click', btn.loadWpt, function () {
			waypoints.toRoute($(input.loadWpt).val().trim());
		});

		// Disables editing on the generated route textarea
		$(textarea.generateRte).prop('disabled', true);

		// Generates an FMC route to the textarea
		$(modal).on('click', btn.generateRte, function () {
			bugfix.input($(textarea.generateRte).val(waypoints.toRouteString()).change());
		}).on('click', btn.clearRte, function () {
			$(textarea.generateRte).val('').change().parent().removeClass('is-dirty');
		});

		// -----------------------------------------
		// ---------------- LOG TAB ----------------
		// -----------------------------------------

		$(modal).on('click', btn.removeLogData, function () {
			log.removeData();
		});

		/* ---- All Initializations ---- */

		// Initializes all timers
		progress.timer = setInterval(function () { progress.update(); }, 5000);
		log.mainTimer = setInterval(function () { log.update(); }, 30000);
		log.speedTimer = setInterval(function () { log.speed(); }, 15000);

	}
});
<|endoftext|>


<commit_before>/*
 Preferences Library

 Usage:
   var value = window['piro.sakura.ne.jp'].prefs.getPref('my.extension.pref');
   window['piro.sakura.ne.jp'].prefs.setPref('my.extension.pref', true);
   window['piro.sakura.ne.jp'].prefs.clearPref('my.extension.pref');
   var listener = {
         domains : [
           'browser.tabs',
           'extensions.someextension'
         ],
         observe : function(aSubject, aTopic, aData)
         {
           if (aTopic != 'nsPref:changed') return;
           var value = window['piro.sakura.ne.jp'].prefs.getPref(aData);
         }
       };
   window['piro.sakura.ne.jp'].prefs.addPrefListener(listener);
   window['piro.sakura.ne.jp'].prefs.removePrefListener(listener);

 license: The MIT License, Copyright (c) 2009-2013 YUKI "Piro" Hiroshi
 original:
   http://github.com/piroor/fxaddonlib-prefs
*/

/* To work as a JS Code Module  */
if (typeof window == 'undefined' ||
	(window && typeof window.constructor == 'function')) {
	this.EXPORTED_SYMBOLS = ['prefs'];

	// If namespace.jsm is available, export symbols to the shared namespace.
	// See: http://github.com/piroor/fxaddonlibs/blob/master/namespace.jsm
	try {
		let ns = {};
		Components.utils.import('resource://my-modules/namespace.jsm', ns);
		/* var */ window = ns.getNamespaceFor('piro.sakura.ne.jp');
	}
	catch(e) {
		window = {};
	}
}

(function() {
	const currentRevision = 9;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'prefs' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].prefs.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	const Cc = Components.classes;
	const Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].prefs = {
		revision : currentRevision,

		Prefs : Cc['@mozilla.org/preferences;1']
					.getService(Ci.nsIPrefBranch)
					.QueryInterface(Ci.nsIPrefBranch2),

		DefaultPrefs : Cc['@mozilla.org/preferences-service;1']
					.getService(Ci.nsIPrefService)
					.getDefaultBranch(null),

		getPref : function(aPrefstring, aInterface, aBranch)
		{
			if (!aInterface || aInterface instanceof Ci.nsIPrefBranch)
				[aBranch, aInterface] = [aInterface, aBranch];

			aBranch = aBranch || this.Prefs;

			var type = aBranch.getPrefType(aPrefstring);
			if (type == aBranch.PREF_INVALID)
				return null;

			if (aInterface)
				return aBranch.getComplexValue(aPrefstring, aInterface);

			switch (type)
			{
				case aBranch.PREF_STRING:
					return decodeURIComponent(escape(aBranch.getCharPref(aPrefstring)));

				case aBranch.PREF_INT:
					return aBranch.getIntPref(aPrefstring);

				case aBranch.PREF_BOOL:
					return aBranch.getBoolPref(aPrefstring);

				case aBranch.PREF_INVALID:
				default:
					return null;
			}
		},

		getDefaultPref : function(aPrefstring, aInterface)
		{
			return this.getPref(aPrefstring, this.DefaultPrefs, aInterface);
		},

		setPref : function(aPrefstring, aNewValue, aBranch)
		{
			aBranch = aBranch || this.Prefs;
			switch (typeof aNewValue)
			{
				case 'string':
					return aBranch.setCharPref(aPrefstring, unescape(encodeURIComponent(aNewValue)));

				case 'number':
					return aBranch.setIntPref(aPrefstring, parseInt(aNewValue));

				default:
					return aBranch.setBoolPref(aPrefstring, !!aNewValue);
			}
		},

		setDefaultPref : function(aPrefstring, aNewValue)
		{
			return this.setPref(aPrefstring, aNewValue, this.DefaultPrefs);
		},

		clearPref : function(aPrefstring)
		{
			if (this.Prefs.prefHasUserValue(aPrefstring))
				this.Prefs.clearUserPref(aPrefstring);
		},

		getDescendant : function(aRoot, aBranch)
		{
			aBranch = aBranch || this.Prefs;
			return aBranch.getChildList(aRoot, {}).sort();
		},

		getChildren : function(aRoot, aBranch)
		{
			var foundChildren = {};
			var possibleChildren = [];
			var actualChildren = this.getDescendant(aRoot, aBranch)
					.forEach(function(aPrefstring) {
						var name = aPrefstring.replace(aRoot, '');
						if (name.charAt(0) == '.')
							name = name.substring(1);
						if (name.indexOf('.') < 0) {
							if (!(aPrefstring in foundChildren)) {
								actualChildren.push(aPrefstring);
								foundChildren[aPrefstring] = true;
							}
						}
						else {
							let possibleChildKey = aRoot + name.split('.')[0];
							if (possibleChildKey && !(possibleChildKey in foundChildren)) {
								possibleChildren.push(possibleChildKey);
								foundChildren[possibleChildKey] = true;
							}
						}
					});
			return possibleChildren.concat(actualChildren).sort();
		},

		addPrefListener : function(aObserver)
		{
			var domains = ('domains' in aObserver) ? aObserver.domains : [aObserver.domain] ;
			try {
				for each (var domain in domains)
					this.Prefs.addObserver(domain, aObserver, false);
			}
			catch(e) {
			}
		},

		removePrefListener : function(aObserver)
		{
			var domains = ('domains' in aObserver) ? aObserver.domains : [aObserver.domain] ;
			try {
				for each (var domain in domains)
					this.Prefs.removeObserver(domain, aObserver, false);
			}
			catch(e) {
			}
		}
	};
})();

if (window != this) { // work as a JS Code Module
	this.prefs = window['piro.sakura.ne.jp'].prefs;
}
<commit_msg>Use latest prefs.js<commit_after>/*
 Preferences Library

 Usage:
   var value = window['piro.sakura.ne.jp'].prefs.getPref('my.extension.pref');
   window['piro.sakura.ne.jp'].prefs.setPref('my.extension.pref', true);
   window['piro.sakura.ne.jp'].prefs.clearPref('my.extension.pref');
   var listener = {
         domains : [
           'browser.tabs',
           'extensions.someextension'
         ],
         observe : function(aSubject, aTopic, aData)
         {
           if (aTopic != 'nsPref:changed') return;
           var value = window['piro.sakura.ne.jp'].prefs.getPref(aData);
         }
       };
   window['piro.sakura.ne.jp'].prefs.addPrefListener(listener);
   window['piro.sakura.ne.jp'].prefs.removePrefListener(listener);

   // utility
   var store = window['piro.sakura.ne.jp'].prefs.createStore('extensions.someextension.');
   // property name/key, default value
   store.define('enabled', true);
   // property name, default value, pref key (different to the name)
   store.define('leftMargin', true, 'margin.left');
   var enabled = store.enabled;
   store.destroy(); // free the memory.

 license: The MIT License, Copyright (c) 2009-2013 YUKI "Piro" Hiroshi
 original:
   http://github.com/piroor/fxaddonlib-prefs
*/

/* To work as a JS Code Module  */
if (typeof window == 'undefined' ||
	(window && typeof window.constructor == 'function')) {
	this.EXPORTED_SYMBOLS = ['prefs'];

	// If namespace.jsm is available, export symbols to the shared namespace.
	// See: http://github.com/piroor/fxaddonlibs/blob/master/namespace.jsm
	try {
		let ns = {};
		Components.utils.import('resource://my-modules/namespace.jsm', ns);
		/* var */ window = ns.getNamespaceFor('piro.sakura.ne.jp');
	}
	catch(e) {
		window = {};
	}
}

(function() {
	const currentRevision = 16;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'prefs' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].prefs.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	const Cc = Components.classes;
	const Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].prefs = {
		revision : currentRevision,

		Prefs : Cc['@mozilla.org/preferences;1']
					.getService(Ci.nsIPrefBranch)
					.QueryInterface(Ci.nsIPrefBranch2),

		DefaultPrefs : Cc['@mozilla.org/preferences-service;1']
					.getService(Ci.nsIPrefService)
					.getDefaultBranch(null),

		getPref : function(aPrefstring, aInterface, aBranch)
		{
			if (!aInterface || aInterface instanceof Ci.nsIPrefBranch)
				[aBranch, aInterface] = [aInterface, aBranch];

			aBranch = aBranch || this.Prefs;

			var type = aBranch.getPrefType(aPrefstring);
			if (type == aBranch.PREF_INVALID)
				return null;

			if (aInterface)
				return aBranch.getComplexValue(aPrefstring, aInterface);

			try {
				switch (type)
				{
					case aBranch.PREF_STRING:
						return decodeURIComponent(escape(aBranch.getCharPref(aPrefstring)));

					case aBranch.PREF_INT:
						return aBranch.getIntPref(aPrefstring);

					case aBranch.PREF_BOOL:
						return aBranch.getBoolPref(aPrefstring);

					case aBranch.PREF_INVALID:
					default:
						return null;
				}
			} catch(e) {
				// getXXXPref can raise an error if it is the default branch.
				return null;
			}
		},

		getLocalizedPref : function(aPrefstring)
		{
			try {
				return this.getPref(aPrefstring, Ci.nsIPrefLocalizedString).data;
			} catch(e) {
				return this.getPref(aPrefstring);
			}
		},

		getDefaultPref : function(aPrefstring, aInterface)
		{
			return this.getPref(aPrefstring, this.DefaultPrefs, aInterface);
		},

		setPref : function(aPrefstring, aNewValue)
		{
			var branch = this.Prefs;
			var interface = null;
			if (arguments.length > 2) {
				for (let i = 2; i < arguments.length; i++)
				{
					let arg = arguments[i];
					if (!arg)
						continue;
					if (arg instanceof Ci.nsIPrefBranch)
						branch = arg;
					else
						interface = arg;
				}
			}
			if (interface &&
				aNewValue instanceof Ci.nsISupports) {
				return branch.setComplexValue(aPrefstring, interface, aNewValue);
			}
			switch (typeof aNewValue)
			{
				case 'string':
					return branch.setCharPref(aPrefstring, unescape(encodeURIComponent(aNewValue)));

				case 'number':
					return branch.setIntPref(aPrefstring, parseInt(aNewValue));

				default:
					return branch.setBoolPref(aPrefstring, !!aNewValue);
			}
		},

		setDefaultPref : function(aPrefstring, aNewValue)
		{
			return this.setPref(aPrefstring, aNewValue, this.DefaultPrefs);
		},

		clearPref : function(aPrefstring)
		{
			if (this.Prefs.prefHasUserValue(aPrefstring))
				this.Prefs.clearUserPref(aPrefstring);
		},

		getDescendant : function(aRoot, aBranch)
		{
			aBranch = aBranch || this.Prefs;
			return aBranch.getChildList(aRoot, {}).sort();
		},

		getChildren : function(aRoot, aBranch)
		{
			aRoot = aRoot.replace(/\.$/, '');
			var foundChildren = {};
			var possibleChildren = [];
			this.getDescendant(aRoot, aBranch)
					.forEach(function(aPrefstring) {
						var name = aPrefstring.replace(aRoot + '.', '');
							let possibleChildKey = aRoot + '.' + name.split('.')[0];
							if (possibleChildKey && !(possibleChildKey in foundChildren)) {
								possibleChildren.push(possibleChildKey);
								foundChildren[possibleChildKey] = true;
							}
					});
			return possibleChildren.sort();
		},

		addPrefListener : function(aObserver)
		{
			var domains = ('domains' in aObserver) ? aObserver.domains : [aObserver.domain] ;
			try {
				for (var domain of domains)
					this.Prefs.addObserver(domain, aObserver, false);
			}
			catch(e) {
			}
		},

		removePrefListener : function(aObserver)
		{
			var domains = ('domains' in aObserver) ? aObserver.domains : [aObserver.domain] ;
			try {
				for (var domain of domains)
					this.Prefs.removeObserver(domain, aObserver, false);
			}
			catch(e) {
			}
		},

		createStore : function(aDomain)
		{
			var listener = {
				domain : aDomain,
				observe : function(aSubject, aTopic, aData) {
					if (aTopic != 'nsPref:changed')
						return;
					var name = keyToName[aData];
					store[name] = window['piro.sakura.ne.jp'].prefs.getPref(aData);
				}
			};
			this.addPrefListener(listener);
			var keyToName = {};
			var base = aDomain.replace(/\.$/, '') + '.';
			var store = {
				define : function(aName, aValue, aKey) {
					aKey = base + (aKey || aName);
					window['piro.sakura.ne.jp'].prefs.setDefaultPref(aKey, aValue);
					this[aName] = window['piro.sakura.ne.jp'].prefs.getPref(aKey);
					keyToName[aKey] = aName;
				},
				destroy : function() {
					window['piro.sakura.ne.jp'].prefs.removePrefListener(listener);
					aDomain = undefined;
					base = undefined;
					listener = undefined;
					keyToName = undefined;
					store = undefined;
				}
			};
			return store;
		}
	};
})();

if (window != this) { // work as a JS Code Module
	this.prefs = window['piro.sakura.ne.jp'].prefs;
}
<|endoftext|>


<commit_before>import * as d3 from 'd3';
import _ from 'lodash';
import { d3combobox } from '../lib/d3.combobox.js';
import { t, textDirection } from '../util/locale';
import { modeBrowse } from '../modes/index';
import { svgIcon } from '../svg/index';
import { uiDisclosure } from './disclosure';
import { uiFields } from './fields/index';
import { uiTagReference } from './tag_reference';
import {
    utilGetSetValue,
    utilNoAuto,
    utilRebind
} from '../util';

export function uiPreset(context) {
    var dispatch = d3.dispatch('change'),
        expandedPreference = (context.storage('preset_fields.expanded') !== 'false'),
        state,
        fieldsArr,
        preset,
        tags,
        id;

    // Field Constructor
    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = uiFields[field.type](field, context)
            .on('change', function(t, onInput) {
                dispatch.call('change', field, t, onInput);
            });

        if (field.input.entity) field.input.entity(entity);

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.some(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        field.present = function() {
            return _.some(field.keys, function(key) {
                return tags[key];
            });
        };

        field.remove = function() {
            var t = {};
            field.keys.forEach(function(key) {
                t[key] = undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        selection.call(uiDisclosure()
            .title(t('inspector.all_fields'))
            .expanded(expandedPreference)
            .on('toggled', toggled)
            .content(content)
        );

        function toggled(expanded) {
            expandedPreference = expanded;
            context.storage('preset_fields.expanded', expanded);
        }
    }

    function content(selection) {
        if (!fieldsArr) {
            var entity = context.entity(id),
                geometry = context.geometry(id),
                presets = context.presets();

            fieldsArr = [];

            if (presets.field('name')) {
                fieldsArr.push(UIField(presets.field('name'), entity));
            }

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fieldsArr.push(UIField(field, entity, true));
                }
            });

            if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
                fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
            }

            presets.universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fieldsArr.push(UIField(field, entity));
                }
            });
        }

        var shown = fieldsArr.filter(function(field) { return field.shown(); }),
            notShown = fieldsArr.filter(function(field) { return !field.shown(); });

        var form = selection.selectAll('.preset-form')
            .data([0]);

        form = form.enter()
            .append('div')
            .attr('class', 'preset-form inspector-inner fillL3')
            .merge(form);

        var fields = form.selectAll('.form-field')
            .data(shown, fieldKey);

        fields.exit()
            .remove();

        // Enter
        var enter = fields.enter()
            .append('div')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var label = enter
            .append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        var wrap = label
            .append('div')
            .attr('class', 'form-label-button-wrap');

        wrap.append('button')
            .attr('class', 'remove-icon')
            .attr('tabindex', -1)
            .call(svgIcon('#operation-delete'));

        wrap.append('button')
            .attr('class', 'modified-icon')
            .attr('tabindex', -1)
            .call(
                (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
            );

        // Update
        fields = fields
            .merge(enter);

        fields.selectAll('.form-label-button-wrap .remove-icon')
            .on('click', remove);

        fields.selectAll('.modified-icon')
            .on('click', revert);

        fields
            .order()
            .classed('modified', function(field) { return field.modified(); })
            .classed('present', function(field) { return field.present(); })
            .each(function(field) {
                var referenceKey = field.key;
                if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
                    referenceKey = referenceKey.replace(/:$/, '');
                }
                var reference = uiTagReference(field.reference || { key: referenceKey }, context);

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .selectAll('input')
                    .on('keydown', function() {
                        // if user presses enter, and combobox is not active, accept edits..
                        if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
                            context.enter(modeBrowse(context));
                        }
                    });

                d3.select(this)
                    .call(reference.body)
                    .select('.form-label-button-wrap')
                    .call(reference.button);

                field.input.tags(tags);
            });

        notShown = notShown.map(function(field) {
            return {
                title: field.label(),
                value: field.label(),
                field: field
            };
        });

        var more = selection.selectAll('.more-fields')
            .data((notShown.length > 0) ? [0] : []);

        more.exit()
            .remove();

        more = more.enter()
            .append('div')
            .attr('class', 'more-fields')
            .append('label')
            .text(t('inspector.add_fields'))
            .merge(more);

        var input = more.selectAll('.value')
            .data([0]);

        input.exit()
            .remove();

        input = input.enter()
            .append('input')
            .attr('class', 'value')
            .attr('type', 'text')
            .call(utilNoAuto)
            .merge(input);

        input
            .call(utilGetSetValue, '')
            .attr('placeholder', function() {
                var placeholder = [];
                for (var field in notShown) {
                    placeholder.push(notShown[field].title);
                }
                return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
            })
            .call(d3combobox()
                .container(context.container())
                .data(notShown)
                .minItems(1)
                .on('accept', show)
            );

        function show(field) {
            field = field.field;
            field.show = true;
            content(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.revert());
        }

        function remove(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.remove());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        if (preset && preset.id === _.id) return presets;
        preset = _;
        fieldsArr = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fieldsArr here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        if (id === _) return presets;
        id = _;
        fieldsArr = null;
        return presets;
    };

    return utilRebind(presets, dispatch, 'on');
}
<commit_msg>Don't force name tags<commit_after>import * as d3 from 'd3';
import _ from 'lodash';
import { d3combobox } from '../lib/d3.combobox.js';
import { t, textDirection } from '../util/locale';
import { modeBrowse } from '../modes/index';
import { svgIcon } from '../svg/index';
import { uiDisclosure } from './disclosure';
import { uiFields } from './fields/index';
import { uiTagReference } from './tag_reference';
import {
    utilGetSetValue,
    utilNoAuto,
    utilRebind
} from '../util';

export function uiPreset(context) {
    var dispatch = d3.dispatch('change'),
        expandedPreference = (context.storage('preset_fields.expanded') !== 'false'),
        state,
        fieldsArr,
        preset,
        tags,
        id;

    // Field Constructor
    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = uiFields[field.type](field, context)
            .on('change', function(t, onInput) {
                dispatch.call('change', field, t, onInput);
            });

        if (field.input.entity) field.input.entity(entity);

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.some(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        field.present = function() {
            return _.some(field.keys, function(key) {
                return tags[key];
            });
        };

        field.remove = function() {
            var t = {};
            field.keys.forEach(function(key) {
                t[key] = undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        selection.call(uiDisclosure()
            .title(t('inspector.all_fields'))
            .expanded(expandedPreference)
            .on('toggled', toggled)
            .content(content)
        );

        function toggled(expanded) {
            expandedPreference = expanded;
            context.storage('preset_fields.expanded', expanded);
        }
    }

    function content(selection) {
        if (!fieldsArr) {
            var entity = context.entity(id),
                geometry = context.geometry(id),
                presets = context.presets();

            fieldsArr = [];

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fieldsArr.push(UIField(field, entity, true));
                }
            });

            if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
                fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
            }

            presets.universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fieldsArr.push(UIField(field, entity));
                }
            });
        }

        var shown = fieldsArr.filter(function(field) { return field.shown(); }),
            notShown = fieldsArr.filter(function(field) { return !field.shown(); });

        var form = selection.selectAll('.preset-form')
            .data([0]);

        form = form.enter()
            .append('div')
            .attr('class', 'preset-form inspector-inner fillL3')
            .merge(form);

        var fields = form.selectAll('.form-field')
            .data(shown, fieldKey);

        fields.exit()
            .remove();

        // Enter
        var enter = fields.enter()
            .append('div')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var label = enter
            .append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        var wrap = label
            .append('div')
            .attr('class', 'form-label-button-wrap');

        wrap.append('button')
            .attr('class', 'remove-icon')
            .attr('tabindex', -1)
            .call(svgIcon('#operation-delete'));

        wrap.append('button')
            .attr('class', 'modified-icon')
            .attr('tabindex', -1)
            .call(
                (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
            );

        // Update
        fields = fields
            .merge(enter);

        fields.selectAll('.form-label-button-wrap .remove-icon')
            .on('click', remove);

        fields.selectAll('.modified-icon')
            .on('click', revert);

        fields
            .order()
            .classed('modified', function(field) { return field.modified(); })
            .classed('present', function(field) { return field.present(); })
            .each(function(field) {
                var referenceKey = field.key;
                if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
                    referenceKey = referenceKey.replace(/:$/, '');
                }
                var reference = uiTagReference(field.reference || { key: referenceKey }, context);

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .selectAll('input')
                    .on('keydown', function() {
                        // if user presses enter, and combobox is not active, accept edits..
                        if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
                            context.enter(modeBrowse(context));
                        }
                    });

                d3.select(this)
                    .call(reference.body)
                    .select('.form-label-button-wrap')
                    .call(reference.button);

                field.input.tags(tags);
            });

        notShown = notShown.map(function(field) {
            return {
                title: field.label(),
                value: field.label(),
                field: field
            };
        });

        var more = selection.selectAll('.more-fields')
            .data((notShown.length > 0) ? [0] : []);

        more.exit()
            .remove();

        more = more.enter()
            .append('div')
            .attr('class', 'more-fields')
            .append('label')
            .text(t('inspector.add_fields'))
            .merge(more);

        var input = more.selectAll('.value')
            .data([0]);

        input.exit()
            .remove();

        input = input.enter()
            .append('input')
            .attr('class', 'value')
            .attr('type', 'text')
            .call(utilNoAuto)
            .merge(input);

        input
            .call(utilGetSetValue, '')
            .attr('placeholder', function() {
                var placeholder = [];
                for (var field in notShown) {
                    placeholder.push(notShown[field].title);
                }
                return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
            })
            .call(d3combobox()
                .container(context.container())
                .data(notShown)
                .minItems(1)
                .on('accept', show)
            );

        function show(field) {
            field = field.field;
            field.show = true;
            content(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.revert());
        }

        function remove(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            dispatch.call('change', field, field.remove());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        if (preset && preset.id === _.id) return presets;
        preset = _;
        fieldsArr = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fieldsArr here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        if (id === _) return presets;
        id = _;
        fieldsArr = null;
        return presets;
    };

    return utilRebind(presets, dispatch, 'on');
}
<|endoftext|>


<commit_before>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// ext. libs
var util = require('util');

/**
 * @param {Number} columns Number of columns
 * @param {Number} rows Number of rows
 * @constructor
 */

var Matrix = function (columns, rows) {
    this.M = [];
    for(var i = 0; i < columns; i++) {
        this.M[i] = [];
        for(var j = 0; j < rows; j++) {
            this.M[i][j] = 0;
        }
    }
};

/**
 * Two dimensional matrix
 *
 * @module Matrix
 * @class Matrix
 * @api
 */

Matrix.prototype = {

    /**
     * Returns clone of matrix
     *
     * @method clone
     * @return {Array} matrix Matrix clone
     */

    clone: function () {
        return [].concat(this.M);
    },

    /**
     * Writes row of values to matrix
     *
     * @method writeRow
     * @param {Number} row Position of row
     * @param {Array} data Data to write
     */

    writeRow: function (row, data) {
        if (util.isArray(data)) {
            if (row > 0 && row <= this.M[this.M.length - 1].length && data.length === this.M.length) {
                for(var i = 0; i < this.M.length; i++) {
                    this.M[i][row - 1] = data[i];
                }
            }
        }
    },

    /**
     * Toggles two columns within matrix
     *
     * @method toggleColumns
     * @param {Number} column1 Position of 1st column
     * @param {Number} column2 Position of 2nd column
     */

    toggleColumns: function (column1, column2) {
        if (column1 > column2) {
            column1 = column1 ^ column2;
            column2 = column1 ^ column2;
            column1 = column1 ^ column2;
        }
        if (this._validColumns(column1, column2)) {
            this.M = []
                .concat(this.M.slice(0, column1 - 1))
                .concat([this.M[column2 - 1]])
                .concat(this.M.slice(column1, column2 - 1))
                .concat([this.M[column1 - 1]])
                .concat(this.M.slice(column2));
        }
    },

    /**
     * Insert column into matrix
     *
     * @method insertColumn
     * @param {Number} column Insertion position
     * @param {Array} data Column data
     */

    insertColumn: function (column, data) {
        if (column >= 0 && column <= this.M.length) {
            this.M = []
                .concat(this.M.slice(0, column))
                .concat([data])
                .concat(this.M.slice(column));
        }
    },

    /**
     * Checks if positions of columns are valid
     *
     * @method _validColumns
     * @param {Number} column1 Position of 1st column
     * @param {Number} column2 Position of 2nd column
     * @private
     */

    _validColumns: function (column1, column2) {
        return column1 > 0 && column1 <= this.M.length && column2 > 0 && column2 <= this.M.length;
    }
};

// export the module
module.exports = Matrix;
<commit_msg>More conditions<commit_after>/*!
 *
 * Copyright (c) 2013 Manfred Bork
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// ext. libs
var util = require('util');

/**
 * @param {Number} columns Number of columns
 * @param {Number} rows Number of rows
 * @constructor
 */

var Matrix = function (columns, rows) {
    this.M = [];
    for(var i = 0; i < columns; i++) {
        this.M[i] = [];
        for(var j = 0; j < rows; j++) {
            this.M[i][j] = 0;
        }
    }
};

/**
 * Two dimensional matrix
 *
 * @module Matrix
 * @class Matrix
 * @api
 */

Matrix.prototype = {

    /**
     * Returns clone of matrix
     *
     * @method clone
     * @return {Array} matrix Matrix clone
     */

    clone: function () {
        return [].concat(this.M);
    },

    /**
     * Writes row of values to matrix
     *
     * @method writeRow
     * @param {Number} row Position of row
     * @param {Array} data Data to write
     */

    writeRow: function (row, data) {
        if (util.isArray(data)) {
            if (row > 0 && row <= this.M[this.M.length - 1].length && data.length === this.M.length) {
                for(var i = 0; i < this.M.length; i++) {
                    this.M[i][row - 1] = data[i];
                }
            }
        }
    },

    /**
     * Toggles two columns within matrix
     *
     * @method toggleColumns
     * @param {Number} column1 Position of 1st column
     * @param {Number} column2 Position of 2nd column
     */

    toggleColumns: function (column1, column2) {
        if (column1 > column2) {
            column1 = column1 ^ column2;
            column2 = column1 ^ column2;
            column1 = column1 ^ column2;
        }
        if (this._validColumns(column1, column2)) {
            this.M = []
                .concat(this.M.slice(0, column1 - 1))
                .concat([this.M[column2 - 1]])
                .concat(this.M.slice(column1, column2 - 1))
                .concat([this.M[column1 - 1]])
                .concat(this.M.slice(column2));
        }
    },

    /**
     * Insert column into matrix
     *
     * @method insertColumn
     * @param {Number} column Insertion position
     * @param {Array} data Column data
     */

    insertColumn: function (column, data) {
        if (util.isArray(data)) {
            if (column >= 0 && column <= this.M.length && data.length === this.M[this.M.length - 1].length) {
                this.M = []
                    .concat(this.M.slice(0, column))
                    .concat([data])
                    .concat(this.M.slice(column));
            }
        }
    },

    /**
     * Checks if positions of columns are valid
     *
     * @method _validColumns
     * @param {Number} column1 Position of 1st column
     * @param {Number} column2 Position of 2nd column
     * @private
     */

    _validColumns: function (column1, column2) {
        return column1 > 0 && column1 <= this.M.length && column2 > 0 && column2 <= this.M.length;
    }
};

// export the module
module.exports = Matrix;
<|endoftext|>


<commit_before>export { Base };

import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import * as PointDepthPoint from "../../PointDepthPoint.js";
import { Params } from "../Block_Params.js";
import { MobileNetV1 } from "./MobileNetV1.js";
import { MobileNetV2 } from "./MobileNetV2.js";
import { MobileNetV2_Thin } from "./MobileNetV2_Thin.js";
import { ShuffleNetV2 } from "./ShuffleNetV2.js";
import { ShuffleNetV2_ByPointwise22 } from "./ShuffleNetV2_ByPointwise22.js";
import { ShuffleNetV2_ByMobileNetV1 } from "./ShuffleNetV2_ByMobileNetV1.js";
import { ShuffleNetV2_ByMobileNetV1_padValid } from "./ShuffleNetV2_ByMobileNetV1_padValid.js";

/**
 * Basic class for all Params_to_PointDepthPointParams.Xxx classes.
 *
 * Note: In modern deep learning CNN, there is batch normalization after convolution and before activation. The batch normalization
 * has bias internally. We do not have batch normalization in architecture so an explicit bias will be used before every activation
 * function.
 *
 * @member {number} outChannels0
 *   The output0's channel count in current configuration.
 *
 * @member {number} outChannels1
 *   The output1's channel count in current configuration.
 *
 */
class Base {

  /**
   * @param {Params} blockParams
   *   The Block.Params object which provides basic parameters.
   */
  constructor( blockParams ) {
    this.blockParams = blockParams;

    this.inputHeight0 = this.inputWidth0 =
    this.channelCount0_pointwise1Before = this.channelCount1_pointwise1Before =
    this.pointwise1ChannelCount = this.bPointwise1Bias = this.pointwise1ActivationId =
    this.depthwise_AvgMax_Or_ChannelMultiplier = this.depthwiseFilterHeight = this.depthwiseFilterWidth =
    this.depthwiseStridesPad = this.bDepthwiseBias = this.depthwiseActivationId =
    this.pointwise21ChannelCount = this.bPointwise21Bias = this.pointwise21ActivationId =
    this.bOutput1Requested = this.bKeepInputTensor = undefined;

    this.stepCount = // How many step should be in the block.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterWidth_Default = // The default depthwise filter size.
    this.depthwiseFilterHeight_Last = this.depthwiseFilterWidth_Last =       // The last step's depthwise filter size.
    this.outChannels0 = this.outChannels1 = -1;

    this.channelShuffler = undefined;
  }

  /** Called to determine stepCount, depthwiseFilterHeight_Default, depthwiseFilterWidth_Default, depthwiseFilterHeight_Last,
    * depthwiseFilterWidth_Last.
    *
    * Sub-class could override this method to adjust data members.
    */
  determine_stepCount_depthwiseFilterHeightWidth_Default_Last() {
    let blockParams = this.blockParams;
    this.stepCount = blockParams.stepCountRequested; // By default, the step count is just the original step count.

    // By default, all steps uses the original depthwise filter size.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterHeight_Last = blockParams.depthwiseFilterHeight;
    this.depthwiseFilterWidth_Default = this.depthwiseFilterWidth_Last = blockParams.depthwiseFilterWidth;
  }

  /**
   * Called before step0 is about to be created. Sub-class should override this method to adjust data members.
   *
   * Step 0.
   *
   * The special points of a block's step 0 are:
   *   - halve the height x width. (Both ShuffleNetV2 and MobileNetV2) (by depthwise convolution with strides = 2)
   *   - Double channels. (Please see explanation of class Block.Base)
   */
  configTo_beforeStep0() {
    this.inputHeight0 = this.blockParams.sourceHeight; // step0 inputs the source image size.
    this.inputWidth0 = this.blockParams.sourceWidth;

    this.bias_activation_setup_forStep0(); // bias, activation of pointwise1, depthwise1, pointwise2
  }

  /**
   * Called after step0 is created (i.e. before step1, 2, 3, ...). Sub-class should override this method to adjust data members.
   */
  configTo_afterStep0() {
    this.inputHeight0 = this.blockParams.outputHeight; // all steps (except step0) inputs half the source image size.
    this.inputWidth0 = this.blockParams.outputWidth;
  }

  /**
   * Called before stepLast is about to be created. Sub-class could override this method to adjust data members.
   */
  configTo_beforeStepLast() {

//!!! (2022/05/04 Remarked) ShuffleNetV2_ByMobileNetV1 can not work.
//     // By default, the stepLast of this block (i.e. at-block-end) may use a different activation function after pointwise2 convolution.
//     //
//     // Even if in MobileNetV2 (pointwise2 convolution does not have activation function in default), this is still true.
//     this.pointwise21ActivationId = this.blockParams.nActivationIdAtBlockEnd;

    // Besides, the stepLast may use a different depthwise filter size. This is especially true for NotShuffleNet_NotMobileNet.
    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Last;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Last;
  }

  /**
   * Config the bias and activation of pointwise1, depthwise1, pointwise2.
   *
   * In original MobileNetV2: (note: tf.batchNorm() has bias intrinsically.)
   *   - pointwise1: bias, activation.
   *   - depthwise1: bias, activation.
   *   - pointwise2: bias, no activation.
   *
   * In original ShuffleNetV2:
   *   - pointwise1: bias, activation.
   *   - depthwise1: bias, no activation.
   *   - pointwise2: bias, activation.
   *
   * We use the former configuration (i.e. original MobileNetV2) in all classes Block.Params_to_PointDepthPointParams.Xxx.
   *
   *
   * 1. Reason
   *
   * The reason is for ShuffleNetV2_ByMobileNetV1 to undo activation escaping scales.
   *
   * In ShuffleNetV2_ByMobileNetV1, if an operation has activation function, it will scale its convolution filters for escaping
   * the activation function's non-linear parts. This results in its output is wrong (i.e. different from ShuffleNetV2). In order
   * to resolve this issue, the last operation (i.e. pointwise2) should have no activation (so it will not scale its convolution
   * filters for escaping the activation function's non-linear parts).
   *
   *
   * 2. Advantage
   *
   * Although this choice is mainly for solving ShuffleNetV2_ByMobileNetV1's issue, it does have practical advantage in fact. The
   * output could have any value (i.e. the whole number line). If the last operation (i.e. pointwise2) has activation function,
   * the output value will be restricted by the activation function (e.g. [ -1, +1 ] for tanh()).
   *
   *
   * 3. Improvement
   *
   * In some cases, the pointwise2's bias could sometimes be dropped and remedied by the bias of the next step's pointwise1 or
   * depthwise1. This could improve performance.
   *
   *
   * 3.1 Precondition of Improvement
   *
   * For affine transformation:
   *
   *   "If an operation has no activation function, it can also have no bias too because the next operation's bias can
   *    achieve the same result. (Multiple affine transformations can be combined into one affine transformation.)"
   *
   * Here, the next operation should be:
   *   - pointwise convolution with bias. or,
   *   - depthwise convolution with ( pad = "valid" ) and bias.
   *
   *
   * 3.1.1 Not workable for does depthwise convolution with ( pad = "same" )?
   *
   * The reason is that the depthwise convolution with ( pad = "same" ) will pad zero. The count of these padded zero is
   * different according to the input pixel position. The varying zero count results in that varying bias is required.
   * This is impossible since data in the same channel could only have the same bias.
   *
   * On the other hand, the depthwise convolution with ( pad = "valid" ) does not pad any value. The per channel (fixed)
   * bias is sufficient to remedy the previous affine transformation's no-bias.
   *
   *
   * 3.1.2 Not workable for ( bPointwise1 == false ), usually.
   *
   * It means that the next step will be no pointwise1. The remedy must be done by the next step's depthwise. Only in
   * ShuffleNetV2_ByMobileNetV1_padValid, the depthwise is ( pad = "valid" ) and workable. In other ConvBlockType,
   * the depthwise is ( pad = "same" ) and not workable.
   *
   *
   * 3.1.3 Not workable for ShuffleNetV2_Xxx
   *
   * The non-step0 of ShuffleNetV2_Xxx does not have any pointwise or depthwise convolution for the input1. It means
   * that there is no chance to remedy the previous step's pointwise21's no-bias before concat-shuffle-split.
   *
   * Although ShuffleNetV2_ByMobileNetV1_Xxx always has pointwise1 intrinsically no matter ( bPointwise1 == false )
   * or ( bPointwise1 == true ), however, ShuffleNetV2_ByMobileNetV1_Xxx's pointwise1's higher half just pass-through
   * input0's higher half. It is the same as no-bias and can not remedy the previous step's pointwise21's no-bias.
   *
   *
   * 3.1.4 Not workable for stepLast
   *
   * Since stepLast does not have the next step (i.e. itself is the last step), there is no next step's pointwise1 to remedy
   * stepLast's pointwise21's no-bias.
   *
   *
   * 3.2 Workable for MobileNet with ( bPointwise1 == true )

//!!! ...unfinished... (2022/05/04)
// Whether does MobileNetV2's add-input-to-output matter?

   *
   * If ( bPointwise1 == true ), it is workable for MobileNetV1, MobileNetV2 and MobileNetV2_Thin. All non-stepLast's pointwise21
   * need not bias. But the stepLast's pointwise21 still needs bias for final output.
   *
   * (Note: All steps' pointwise1 and depthwise1 need bias because they have activation function.)
   *
   * In fact, if multiple ConvBlock is used, only the last step's pointwise21 of the last block's needs bias. All other block's
   * every step's pointwise21 needs not bias.
   *
   *

//!!! ...unfinished... (2022/05/04)
// All steps (except stepLast) could use ( this.bPointwise21Bias = true ).
// stepLast uses ( this.bPointwise21Bias = false ) is enough.

   *
   *
   *
   *
   */
  bias_activation_setup_forStep0() {
    this.bPointwise1Bias = true;
    this.pointwise1ActivationId = this.blockParams.nActivationId;

    this.bDepthwiseBias = true;
    this.depthwiseActivationId = this.blockParams.nActivationId;

//!!! ...unfinished... (2022/05/04)
// All steps (except stepLast) could use ( this.bPointwise21Bias = true ).
// stepLast uses ( this.bPointwise21Bias = false ) is enough.

    this.bPointwise21Bias = true;
    this.pointwise21ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
  }

  /**
   *
   * @param {Float32Array} inputFloat32Array
   *   A Float32Array whose values will be interpreted as weights.
   *
   * @param {number} byteOffsetBegin
   *   The position to start to decode from the inputFloat32Array. This is relative to the inputFloat32Array.buffer
   * (not to the inputFloat32Array.byteOffset).
   *
   * @return {PointDepthPoint.Params}
   *   Create and return a PointDepthPoint.Params according to this object's current state.
   */
  create_PointDepthPointParams( inputFloat32Array, byteOffsetBegin ) {
    let params = new PointDepthPoint.Params(
      inputFloat32Array, byteOffsetBegin,
      this.inputHeight0, this.inputWidth0,
      this.channelCount0_pointwise1Before,
      this.channelCount1_pointwise1Before,
      this.pointwise1ChannelCount, this.bPointwise1Bias, this.pointwise1ActivationId,
      this.depthwise_AvgMax_Or_ChannelMultiplier, this.depthwiseFilterHeight, this.depthwiseFilterWidth,
      this.depthwiseStridesPad, this.bDepthwiseBias, this.depthwiseActivationId,
      this.pointwise21ChannelCount, this.bPointwise21Bias, this.pointwise21ActivationId,
      this.bOutput1Requested,
      this.bKeepInputTensor
    );
    return params;
  }

  /**
   * @param {Params} blockParams
   *   The Block.Params object to be reference.
   *
   * @return {Base}
   *   Return newly created Block.Params_to_PointDepthPointParams.Xxx object according to blockParams.nConvBlockType.
   */
  static create_byBlockParams( blockParams ) {

    tf.util.assert( ( blockParams.stepCountRequested >= 2 ),
      `Block.StepParamsCreator.Base.create_byBlockParams(): `
        + `blockParams.stepCountRequested ( ${blockParams.stepCountRequested} ) must be >= 2.` );

    switch ( blockParams.nConvBlockType ) {
      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V1: // (0)
        return new Params_to_PointDepthPointParams.MobileNetV1( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V2: // (1)
        return new Params_to_PointDepthPointParams.MobileNetV2( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V2_THIN: // (2)
        return new Params_to_PointDepthPointParams.MobileNetV2_Thin( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2: // (3)
        return new Params_to_PointDepthPointParams.ShuffleNetV2( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_POINTWISE22: // (4)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByPointwise22( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1: // (5)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByMobileNetV1( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID: // (6)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByMobileNetV1_padValid( blockParams ); break;

      default:
        tf.util.assert( false,
          `Block.StepParamsCreator.Base.create_byBlockParams(): `
            + `unknown this.nConvBlockType ( ${blockParams.nConvBlockType} ) value.` );
        break;
    }
  }

}

<commit_msg>Update Base.js<commit_after>export { Base };

import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import * as PointDepthPoint from "../../PointDepthPoint.js";
import { Params } from "../Block_Params.js";
import { MobileNetV1 } from "./MobileNetV1.js";
import { MobileNetV2 } from "./MobileNetV2.js";
import { MobileNetV2_Thin } from "./MobileNetV2_Thin.js";
import { ShuffleNetV2 } from "./ShuffleNetV2.js";
import { ShuffleNetV2_ByPointwise22 } from "./ShuffleNetV2_ByPointwise22.js";
import { ShuffleNetV2_ByMobileNetV1 } from "./ShuffleNetV2_ByMobileNetV1.js";
import { ShuffleNetV2_ByMobileNetV1_padValid } from "./ShuffleNetV2_ByMobileNetV1_padValid.js";

/**
 * Basic class for all Params_to_PointDepthPointParams.Xxx classes.
 *
 * Note: In modern deep learning CNN, there is batch normalization after convolution and before activation. The batch normalization
 * has bias internally. We do not have batch normalization in architecture so an explicit bias will be used before every activation
 * function.
 *
 * @member {number} outChannels0
 *   The output0's channel count in current configuration.
 *
 * @member {number} outChannels1
 *   The output1's channel count in current configuration.
 *
 */
class Base {

  /**
   * @param {Params} blockParams
   *   The Block.Params object which provides basic parameters.
   */
  constructor( blockParams ) {
    this.blockParams = blockParams;

    this.inputHeight0 = this.inputWidth0 =
    this.channelCount0_pointwise1Before = this.channelCount1_pointwise1Before =
    this.pointwise1ChannelCount = this.bPointwise1Bias = this.pointwise1ActivationId =
    this.depthwise_AvgMax_Or_ChannelMultiplier = this.depthwiseFilterHeight = this.depthwiseFilterWidth =
    this.depthwiseStridesPad = this.bDepthwiseBias = this.depthwiseActivationId =
    this.pointwise21ChannelCount = this.bPointwise21Bias = this.pointwise21ActivationId =
    this.bOutput1Requested = this.bKeepInputTensor = undefined;

    this.stepCount = // How many step should be in the block.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterWidth_Default = // The default depthwise filter size.
    this.depthwiseFilterHeight_Last = this.depthwiseFilterWidth_Last =       // The last step's depthwise filter size.
    this.outChannels0 = this.outChannels1 = -1;

    this.channelShuffler = undefined;
  }

  /** Called to determine stepCount, depthwiseFilterHeight_Default, depthwiseFilterWidth_Default, depthwiseFilterHeight_Last,
    * depthwiseFilterWidth_Last.
    *
    * Sub-class could override this method to adjust data members.
    */
  determine_stepCount_depthwiseFilterHeightWidth_Default_Last() {
    let blockParams = this.blockParams;
    this.stepCount = blockParams.stepCountRequested; // By default, the step count is just the original step count.

    // By default, all steps uses the original depthwise filter size.
    this.depthwiseFilterHeight_Default = this.depthwiseFilterHeight_Last = blockParams.depthwiseFilterHeight;
    this.depthwiseFilterWidth_Default = this.depthwiseFilterWidth_Last = blockParams.depthwiseFilterWidth;
  }

  /**
   * Called before step0 is about to be created. Sub-class should override this method to adjust data members.
   *
   * Step 0.
   *
   * The special points of a block's step 0 are:
   *   - halve the height x width. (Both ShuffleNetV2 and MobileNetV2) (by depthwise convolution with strides = 2)
   *   - Double channels. (Please see explanation of class Block.Base)
   */
  configTo_beforeStep0() {
    this.inputHeight0 = this.blockParams.sourceHeight; // step0 inputs the source image size.
    this.inputWidth0 = this.blockParams.sourceWidth;

    this.bias_activation_setup_forStep0(); // bias, activation of pointwise1, depthwise1, pointwise2
  }

  /**
   * Called after step0 is created (i.e. before step1, 2, 3, ...). Sub-class should override this method to adjust data members.
   */
  configTo_afterStep0() {
    this.inputHeight0 = this.blockParams.outputHeight; // all steps (except step0) inputs half the source image size.
    this.inputWidth0 = this.blockParams.outputWidth;
  }

  /**
   * Called before stepLast is about to be created. Sub-class could override this method to adjust data members.
   */
  configTo_beforeStepLast() {

//!!! (2022/05/04 Remarked) ShuffleNetV2_ByMobileNetV1 can not work.
//     // By default, the stepLast of this block (i.e. at-block-end) may use a different activation function after pointwise2 convolution.
//     //
//     // Even if in MobileNetV2 (pointwise2 convolution does not have activation function in default), this is still true.
//     this.pointwise21ActivationId = this.blockParams.nActivationIdAtBlockEnd;

    // Besides, the stepLast may use a different depthwise filter size. This is especially true for NotShuffleNet_NotMobileNet.
    this.depthwiseFilterHeight = this.depthwiseFilterHeight_Last;
    this.depthwiseFilterWidth = this.depthwiseFilterWidth_Last;
  }

  /**
   * Config the bias and activation of pointwise1, depthwise1, pointwise2.
   *
   * In original MobileNetV2: (note: tf.batchNorm() has bias intrinsically.)
   *   - pointwise1: bias, activation.
   *   - depthwise1: bias, activation.
   *   - pointwise2: bias, no activation.
   *
   * In original ShuffleNetV2:
   *   - pointwise1: bias, activation.
   *   - depthwise1: bias, no activation.
   *   - pointwise2: bias, activation.
   *
   * We use the former configuration (i.e. original MobileNetV2) in all classes Block.Params_to_PointDepthPointParams.Xxx.
   *
   *
   * 1. Reason
   *
   * The reason is for ShuffleNetV2_ByMobileNetV1 to undo activation escaping scales.
   *
   * In ShuffleNetV2_ByMobileNetV1, if an operation has activation function, it will scale its convolution filters for escaping
   * the activation function's non-linear parts. This results in its output is wrong (i.e. different from ShuffleNetV2). In order
   * to resolve this issue, the last operation (i.e. pointwise2) should have no activation (so it will not scale its convolution
   * filters for escaping the activation function's non-linear parts).
   *
   *
   * 2. Advantage
   *
   * Although this choice is mainly for solving ShuffleNetV2_ByMobileNetV1's issue, it does have practical advantage in fact. The
   * output could have any value (i.e. the whole number line). If the last operation (i.e. pointwise2) has activation function,
   * the output value will be restricted by the activation function (e.g. [ -1, +1 ] for tanh()).
   *
   *
   * 3. Improvement
   *
   * In some cases, the pointwise2's bias could sometimes be dropped and remedied by the bias of the next step's pointwise1 or
   * depthwise1. This could improve performance.
   *
   *
   * 3.1 Precondition of Improvement
   *
   * For affine transformation:
   *
   *   "If an operation has no activation function, it can also have no bias too because the next operation's bias can
   *    achieve the same result. (Multiple affine transformations can be combined into one affine transformation.)"
   *
   * Here, the next operation should be:
   *   - pointwise convolution with bias. or,
   *   - depthwise convolution with ( pad = "valid" ) and bias.
   *
   *
   * 3.1.1 Not workable for does depthwise convolution with ( pad = "same" )?
   *
   * The reason is that the depthwise convolution with ( pad = "same" ) will pad zero. The count of these padded zero is
   * different according to the input pixel position. The varying zero count results in that varying bias is required.
   * This is impossible since data in the same channel could only have the same bias.
   *
   * On the other hand, the depthwise convolution with ( pad = "valid" ) does not pad any value. The per channel (fixed)
   * bias is sufficient to remedy the previous affine transformation's no-bias.
   *
   *
   * 3.1.2 Not workable for ( bPointwise1 == false ), usually.
   *
   * It means that the next step will be no pointwise1. The remedy must be done by the next step's depthwise. Only in
   * ShuffleNetV2_ByMobileNetV1_padValid, the depthwise is ( pad = "valid" ) and workable. In other ConvBlockType,
   * the depthwise is ( pad = "same" ) and not workable.
   *
   *
   * 3.1.3 Not workable for ShuffleNetV2_Xxx
   *
   * The non-step0 of ShuffleNetV2_Xxx does not have any pointwise or depthwise convolution for the input1. It means
   * that there is no chance to remedy the previous step's pointwise21's no-bias before concat-shuffle-split.
   *
   * Although ShuffleNetV2_ByMobileNetV1_Xxx always has pointwise1 intrinsically no matter ( bPointwise1 == false )
   * or ( bPointwise1 == true ), however, ShuffleNetV2_ByMobileNetV1_Xxx's pointwise1's higher half just pass-through
   * input0's higher half. It is the same as no-bias and can not remedy the previous step's pointwise21's no-bias.
   *
   *
   * 3.1.4 Not workable for stepLast
   *
   * Since stepLast does not have the next step (i.e. itself is the last step), there is no next step's pointwise1 to
   * remedy stepLast's pointwise21's no-bias.
   *
   *
   * 3.2 Workable for MobileNet with ( bPointwise1 == true )
   *
   * In summary, when ( bPointwise1 == true ), it is workable for MobileNetV1, MobileNetV2 and MobileNetV2_Thin. All
   * non-stepLast's pointwise21 need not bias. Only the stepLast's pointwise21 needs bias for final output.
   *
   * (Note: All steps' pointwise1 and depthwise1 also need bias because they have activation function (i.e. not affine
   * transformation).)
   *
   * In fact, if multiple convolution blocks are used, only the last block's stepLast's pointwise21 needs bias. All other
   * block's every step's pointwise21 needs not bias.
   *
   *

//!!! ...unfinished... (2022/05/04)
// All steps (except stepLast) could use ( this.bPointwise21Bias = true ).
// stepLast uses ( this.bPointwise21Bias = false ) is enough.

   *
   *
   *
   *
   */
  bias_activation_setup_forStep0() {
    this.bPointwise1Bias = true;
    this.pointwise1ActivationId = this.blockParams.nActivationId;

    this.bDepthwiseBias = true;
    this.depthwiseActivationId = this.blockParams.nActivationId;

//!!! ...unfinished... (2022/05/04)
// All steps (except stepLast) could use ( this.bPointwise21Bias = true ).
// stepLast uses ( this.bPointwise21Bias = false ) is enough.

    this.bPointwise21Bias = true;
    this.pointwise21ActivationId = ValueDesc.ActivationFunction.Singleton.Ids.NONE;
  }

  /**
   *
   * @param {Float32Array} inputFloat32Array
   *   A Float32Array whose values will be interpreted as weights.
   *
   * @param {number} byteOffsetBegin
   *   The position to start to decode from the inputFloat32Array. This is relative to the inputFloat32Array.buffer
   * (not to the inputFloat32Array.byteOffset).
   *
   * @return {PointDepthPoint.Params}
   *   Create and return a PointDepthPoint.Params according to this object's current state.
   */
  create_PointDepthPointParams( inputFloat32Array, byteOffsetBegin ) {
    let params = new PointDepthPoint.Params(
      inputFloat32Array, byteOffsetBegin,
      this.inputHeight0, this.inputWidth0,
      this.channelCount0_pointwise1Before,
      this.channelCount1_pointwise1Before,
      this.pointwise1ChannelCount, this.bPointwise1Bias, this.pointwise1ActivationId,
      this.depthwise_AvgMax_Or_ChannelMultiplier, this.depthwiseFilterHeight, this.depthwiseFilterWidth,
      this.depthwiseStridesPad, this.bDepthwiseBias, this.depthwiseActivationId,
      this.pointwise21ChannelCount, this.bPointwise21Bias, this.pointwise21ActivationId,
      this.bOutput1Requested,
      this.bKeepInputTensor
    );
    return params;
  }

  /**
   * @param {Params} blockParams
   *   The Block.Params object to be reference.
   *
   * @return {Base}
   *   Return newly created Block.Params_to_PointDepthPointParams.Xxx object according to blockParams.nConvBlockType.
   */
  static create_byBlockParams( blockParams ) {

    tf.util.assert( ( blockParams.stepCountRequested >= 2 ),
      `Block.StepParamsCreator.Base.create_byBlockParams(): `
        + `blockParams.stepCountRequested ( ${blockParams.stepCountRequested} ) must be >= 2.` );

    switch ( blockParams.nConvBlockType ) {
      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V1: // (0)
        return new Params_to_PointDepthPointParams.MobileNetV1( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V2: // (1)
        return new Params_to_PointDepthPointParams.MobileNetV2( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.MOBILE_NET_V2_THIN: // (2)
        return new Params_to_PointDepthPointParams.MobileNetV2_Thin( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2: // (3)
        return new Params_to_PointDepthPointParams.ShuffleNetV2( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_POINTWISE22: // (4)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByPointwise22( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1: // (5)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByMobileNetV1( blockParams ); break;

      case ValueDesc.ConvBlockType.Ids.SHUFFLE_NET_V2_BY_MOBILE_NET_V1_PAD_VALID: // (6)
        return new Params_to_PointDepthPointParams.ShuffleNetV2_ByMobileNetV1_padValid( blockParams ); break;

      default:
        tf.util.assert( false,
          `Block.StepParamsCreator.Base.create_byBlockParams(): `
            + `unknown this.nConvBlockType ( ${blockParams.nConvBlockType} ) value.` );
        break;
    }
  }

}

<|endoftext|>


<commit_before>module.exports = MantaCouch;

var follow = require('follow');
var url = require('url');
var crypto = require('crypto');

// XXX
process.env.NODE_DEBUG='cuttlefish';
var cuttlefish = require('cuttlefish');

var path = require('path');
var fs = require('fs');
var PassThrough = require('stream').PassThrough;

if (!PassThrough)
  throw new Error('This module requires Node 0.10 or above');

function MantaCouch(opts) {
  if (!(this instanceof MantaCouch))
    return new MantaCouch(opts);

  if (!opts || typeof opts !== 'object')
    throw new TypeError('opts object required');

  console.error(opts);

  this.opts = opts;

  if (!opts.client || opts.client.constructor.name !== 'MantaClient')
    throw new TypeError('opts.client of type MantaClient is required');
  this.client = opts.client;

  if (opts.seqFile && typeof opts.seqFile !== 'string')
    throw new TypeError('opts.seqFile must be of type string');
  this.seqFile = opts.seqFile || null;
  if (this.seqFile)
    this.seqFile = path.resolve(this.seqFile);

  if (!opts.path || typeof opts.path !== 'string')
    throw new TypeError('opts.path is required');
  this.path = opts.path.replace(/\/+$/, '');

  if (!opts.db || !url.parse(opts.db).protocol)
    throw new TypeError('opts.db url is required');
  this.db = opts.db.replace(/\/+$/, '');

  this.http = url.parse(this.db).prototcol === 'https:' ?
    require('https') : require('http');

  if (opts.inactivity_ms && typeof opts.inactivity_ms !== 'number')
    throw new TypeError('opts.inactivity_ms must be of type number');
  this.inactivity_ms = opts.inactivity_ms;

  if (opts.seq && typeof opts.seq !== 'number')
    throw new TypeError('opts.seq must be of type number');
  this.seq = opts.seq || 0;

  this.following = false;
  this.savingSeq = false;
  this.start();
}

MantaCouch.prototype.saveSeq = function(file) {
  file = file || this.seqFile;
  if (!file)
    throw new Error('invalid sequence file: ' + file);
  if (!this.savingSeq)
    fs.writeFile(file, this.seq + '\n', 'ascii', this.afterSave.bind(this));
  this.savingSeq = true;
}

MantaCouch.prototype.readSeq = function(cb) {
  if (this.following)
    throw new Error('Cannot read sequence after follow starts');
  if (!this.seqFile) {
    this.seq = 0;
    cb();
  } else
    fs.readFile(this.seqFile, 'ascii', this.onReadSeq.bind(this));
}

MantaCouch.prototype.onReadSeq = function(er, data) {
  if (er)
    throw er;
  data = +data;
  if (!data && data !== 0)
    throw new Error('invalid data in seqFile');
  this.seq = +data;
  this.follow();
}

MantaCouch.prototype.afterSave = function(er) {
  if (er)
    throw er;
  this.savingSeq = false;
}

MantaCouch.prototype.start = function() {
  this.readSeq(this.follow.bind(this));
};

MantaCouch.prototype.follow = function() {
  this.follow = follow({
    db: this.db,
    since: this.seq,
    include_docs: true,
    inactivity_ms: this.inactivity_ms
  }, this.onChange.bind(this));
}

MantaCouch.prototype.onChange = function(er, change) {
  if (er)
    throw er;
  else if (change.deleted)
    this.rm(change);
  else
    this.put(change);
}

MantaCouch.prototype.rm = function(change) {
  this.log('RM ' + change.id);
  this.follow.pause();
  this.client.rmr(this.path + '/' + change.id, this.onDelete.bind(this));
}

MantaCouch.prototype.onDelete = function(er) {
  if (!er || er.statusCode === 404)
    this.follow.resume();
  else
    throw er;
}

MantaCouch.prototype.put = function(change) {
  this.log('PUT ' + change.id);
  var doc = change.doc;

  var files = Object.keys(doc._attachments || {}).reduce(function (s, k) {
    s['_attachments/' + k] = doc._attachments[k];
    return s;
  }, {});

  if (change.id === 'attachment_test') {
    this.log(files);
  } else {
    this.log('not attachment test', files);
  }

  var json = new Buffer(JSON.stringify(doc) + '\n', 'utf8');
  files['doc.json'] = {
    type: 'application/json',
    name: 'doc.json',
    length: json.length,
    data: json
  };

  cuttlefish({
    path: this.path + '/' + change.id,
    client: this.client,
    files: files,
    getMd5: this.getMd5.bind(this, doc),
    request: this.getFile.bind(this, doc),
    delete: this.delete
  }).on('complete', this.onCuttle.bind(this));
};

MantaCouch.prototype.getMd5 = function(doc, file, cb) {
  assert.equal(file.name, 'doc.json');
  var md5 = crypto.createHash('md5').update(file.data).digest('base64');
  cb(null, md5);
}

MantaCouch.prototype.getFile = function(doc, file, cb) {
  if (file.name === 'doc.json')
    this.streamDoc(doc, file, cb)
  else
    this.getAttachment(doc, file, cb)
}

MantaCouch.prototype.streamDoc = function(doc, file, cb) {
  var s = new PassThrough();
  s.end(file.data);
  cb(null, s);
}

MantaCouch.prototype.getAttachment = function(doc, file, cb) {
  var a = file.name.replace(/^_attachments/, doc._id);
  this.log('attachment', a, file, doc._attachments);
  var u = this.db + '/' + a;
  this.http.get(u, function(res) {
    cb(null, res);
  }).on('error', cb);
}

//MantaCouch.prototype.onPut = function(change, er) {
//  if (er)
//    throw er;
//  if (change.doc._attachments)
//    this.putAttachments(change.doc);
//  else
//    this.follow.resume();
//}
//
//MantaCouch.prototype.putAttachments = function(doc) {
//  cuttlefish({
//    client: this.client,
//    path: this.path + '/' + doc._id + '/_attachments',
//    files: doc._attachments,
//    request: this.getAttachment.bind(this, doc)
//  }).on('complete', this.onCuttle.bind(this));
//}

MantaCouch.prototype.onCuttle = function(results) {
  this.log(results);
  this.follow.resume();
};

MantaCouch.prototype.log = function() {
  // todo: loglevels
  console.log.apply(console, arguments);
}
<commit_msg>remove cuttlefish debug flag<commit_after>module.exports = MantaCouch;

var follow = require('follow');
var url = require('url');
var crypto = require('crypto');

var cuttlefish = require('cuttlefish');

var path = require('path');
var fs = require('fs');
var PassThrough = require('stream').PassThrough;

if (!PassThrough)
  throw new Error('This module requires Node 0.10 or above');

function MantaCouch(opts) {
  if (!(this instanceof MantaCouch))
    return new MantaCouch(opts);

  if (!opts || typeof opts !== 'object')
    throw new TypeError('opts object required');

  console.error(opts);

  this.opts = opts;

  if (!opts.client || opts.client.constructor.name !== 'MantaClient')
    throw new TypeError('opts.client of type MantaClient is required');
  this.client = opts.client;

  if (opts.seqFile && typeof opts.seqFile !== 'string')
    throw new TypeError('opts.seqFile must be of type string');
  this.seqFile = opts.seqFile || null;
  if (this.seqFile)
    this.seqFile = path.resolve(this.seqFile);

  if (!opts.path || typeof opts.path !== 'string')
    throw new TypeError('opts.path is required');
  this.path = opts.path.replace(/\/+$/, '');

  if (!opts.db || !url.parse(opts.db).protocol)
    throw new TypeError('opts.db url is required');
  this.db = opts.db.replace(/\/+$/, '');

  this.http = url.parse(this.db).prototcol === 'https:' ?
    require('https') : require('http');

  if (opts.inactivity_ms && typeof opts.inactivity_ms !== 'number')
    throw new TypeError('opts.inactivity_ms must be of type number');
  this.inactivity_ms = opts.inactivity_ms;

  if (opts.seq && typeof opts.seq !== 'number')
    throw new TypeError('opts.seq must be of type number');
  this.seq = opts.seq || 0;

  this.following = false;
  this.savingSeq = false;
  this.start();
}

MantaCouch.prototype.saveSeq = function(file) {
  file = file || this.seqFile;
  if (!file)
    throw new Error('invalid sequence file: ' + file);
  if (!this.savingSeq)
    fs.writeFile(file, this.seq + '\n', 'ascii', this.afterSave.bind(this));
  this.savingSeq = true;
}

MantaCouch.prototype.readSeq = function(cb) {
  if (this.following)
    throw new Error('Cannot read sequence after follow starts');
  if (!this.seqFile) {
    this.seq = 0;
    cb();
  } else
    fs.readFile(this.seqFile, 'ascii', this.onReadSeq.bind(this));
}

MantaCouch.prototype.onReadSeq = function(er, data) {
  if (er)
    throw er;
  data = +data;
  if (!data && data !== 0)
    throw new Error('invalid data in seqFile');
  this.seq = +data;
  this.follow();
}

MantaCouch.prototype.afterSave = function(er) {
  if (er)
    throw er;
  this.savingSeq = false;
}

MantaCouch.prototype.start = function() {
  this.readSeq(this.follow.bind(this));
};

MantaCouch.prototype.follow = function() {
  this.follow = follow({
    db: this.db,
    since: this.seq,
    include_docs: true,
    inactivity_ms: this.inactivity_ms
  }, this.onChange.bind(this));
}

MantaCouch.prototype.onChange = function(er, change) {
  if (er)
    throw er;
  else if (change.deleted)
    this.rm(change);
  else
    this.put(change);
}

MantaCouch.prototype.rm = function(change) {
  this.log('RM ' + change.id);
  this.follow.pause();
  this.client.rmr(this.path + '/' + change.id, this.onDelete.bind(this));
}

MantaCouch.prototype.onDelete = function(er) {
  if (!er || er.statusCode === 404)
    this.follow.resume();
  else
    throw er;
}

MantaCouch.prototype.put = function(change) {
  this.log('PUT ' + change.id);
  var doc = change.doc;

  var files = Object.keys(doc._attachments || {}).reduce(function (s, k) {
    s['_attachments/' + k] = doc._attachments[k];
    return s;
  }, {});

  if (change.id === 'attachment_test') {
    this.log(files);
  } else {
    this.log('not attachment test', files);
  }

  var json = new Buffer(JSON.stringify(doc) + '\n', 'utf8');
  files['doc.json'] = {
    type: 'application/json',
    name: 'doc.json',
    length: json.length,
    data: json
  };

  cuttlefish({
    path: this.path + '/' + change.id,
    client: this.client,
    files: files,
    getMd5: this.getMd5.bind(this, doc),
    request: this.getFile.bind(this, doc),
    delete: this.delete
  }).on('complete', this.onCuttle.bind(this));
};

MantaCouch.prototype.getMd5 = function(doc, file, cb) {
  assert.equal(file.name, 'doc.json');
  var md5 = crypto.createHash('md5').update(file.data).digest('base64');
  cb(null, md5);
}

MantaCouch.prototype.getFile = function(doc, file, cb) {
  if (file.name === 'doc.json')
    this.streamDoc(doc, file, cb)
  else
    this.getAttachment(doc, file, cb)
}

MantaCouch.prototype.streamDoc = function(doc, file, cb) {
  var s = new PassThrough();
  s.end(file.data);
  cb(null, s);
}

MantaCouch.prototype.getAttachment = function(doc, file, cb) {
  var a = file.name.replace(/^_attachments/, doc._id);
  this.log('attachment', a, file, doc._attachments);
  var u = this.db + '/' + a;
  this.http.get(u, function(res) {
    cb(null, res);
  }).on('error', cb);
}

//MantaCouch.prototype.onPut = function(change, er) {
//  if (er)
//    throw er;
//  if (change.doc._attachments)
//    this.putAttachments(change.doc);
//  else
//    this.follow.resume();
//}
//
//MantaCouch.prototype.putAttachments = function(doc) {
//  cuttlefish({
//    client: this.client,
//    path: this.path + '/' + doc._id + '/_attachments',
//    files: doc._attachments,
//    request: this.getAttachment.bind(this, doc)
//  }).on('complete', this.onCuttle.bind(this));
//}

MantaCouch.prototype.onCuttle = function(results) {
  this.log(results);
  this.follow.resume();
};

MantaCouch.prototype.log = function() {
  // todo: loglevels
  console.log.apply(console, arguments);
}
<|endoftext|>