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

	var VERSION = 1.1;

	// initialize options
	var options = {};

	// language
	var translator = require('./custom_modules/translator');
	var lang = translator.getLanguage();

	// logger
	var logger = {
		v: function(str) {
			console.log(str);
		},
		i: function(str) {
			console.info('%c' + str, 'color: dodgerblue');
		},
		w: function(str) {
			console.warn('%c' + str, 'color: orange');
		},
		e: function(str) {
			console.error('%c' + str, 'color: red');
		}
	};
	require('./custom_modules/logger').set(logger);

	// server
	var server = require('./custom_modules/entry');
	server.open(logger);

	// router
	var router = require('./custom_modules/router').init(server);
	window.router = router;

	// flasher
	var flasher = require('./custom_modules/flasher');
	// ui & control
	$('#driver').text(translator.translate('Install Device Driver'));
	$('#firmware').text(translator.translate('Install Firmware'));
	$('#other-robot .text').text(translator.translate('Connect Other Hardware'));
	$('#entry .text').text(translator.translate('Show Entry Web Page'));

	var ui = {
		countRobot: 0,
		showRobotList: function() {
			router.close();
			router.stopScan();
			delete window.currentConfig;
			$('#title').text(translator.translate('Select hardware'));
			$('#hwList').show();
			$('#hwPanel').css('display', 'none');
			ui.showIeGuide();
			this.hideAlert();
		},
		showConnecting: function() {
			$('#title').text(translator.translate('hardware > connecting'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Connecting to hardware device.'));
		},
		showConnected: function() {
			$('#title').text(translator.translate('hardware > connected'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Connected to hardware device.'), 2000);
		},
		showDisconnected: function() {
			$('#title').text(translator.translate('hardware > disconnected'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Hardware device is disconnected. Please restart this program.'));
		},
		showAlert: function(message, duration) {
			$('#alert').text(message);

			$('#alert').css({
				height: '0px'
			});
			$('#alert').animate({
				height: '35px'
			});

			if (duration) {
				setTimeout(function(){
					$('#alert').animate({
						height: '0px'
					});
				}, duration);
			}
		},
		hideAlert: function(message) {
			$('#alert').animate({
				height: '0px'
			});
		},
		addRobot: function(config) {
			ui.showRobotList();
			var name;
			if(config.name) {
				name = config.name[lang] || config.name['en'];
			}

			$('#hwList').append(
					'
' +
					'' +
					'
' + name + '

');

			$('#' + config.id).click(function() {
				if(config.hardware.type === 'bluetooth') {
					is_select_port = true;
				}

				var newSelectList = selectedList.filter(function (item) {
					return item !== config.name.ko;
				});
				newSelectList.push(config.name.ko);
				localStorage.setItem('hardwareList', JSON.stringify(newSelectList));
				selectedList = newSelectList;
				ui.hardware = config.id.substring(0, 4);
				ui.numLevel = 1;
				ui.showConnecting();
				router.startScan(config);
				window.currentConfig = config;

				var icon = './modules/' + config.icon;
				$('#selectedHWThumb').attr('src', icon);

				if(config.url) {
					$('#url').text(config.url);
					$('#url').show();
					$('#url').unbind('click');
					$('#url').click(function() {
						shell.openItem(config.url);
					});
				} else {
					$('#url').hide();
				}

				$('#driver').hide();
				$('#firmware').hide();
				$('#extFirmware').hide();
				$('#extFirmwarea').hide();
				$('#firmware').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});
				$('#extFirmware').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});
				$('#extFirmwarea').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});

				if(config.driver) {
					var os = process.platform + '-' + (isOSWin64() ? 'x64' : process.arch);
					var driverPath = config.driver[os];
					if(driverPath) {
						$('#driver').show();
						$('#driver').unbind('click');
						$('#driver').click(function() {
							var driversPath;
							if(__dirname.indexOf('.asar') >= 0) {
								driversPath = path.join(__dirname, '..', 'drivers', driverPath);
							} else {
								driversPath = path.join(__dirname, 'drivers', driverPath);
							}
							shell.openItem(driversPath);
						});
					}
					if (config.firmware) {
						$('#firmware').show();
						if(typeof config.firmware === 'string') {
							$('#firmware').text(translator.translate('Install Firmware'));
							$('#firmware').prop('firmware', config.firmware);
						} else if(Array.isArray(config.firmware)) {
							var firmware = config.firmware[0];
							var extFirmware = config.firmware[1];
							var extFirmwarea = config.firmware[2];
							$('#extFirmware').show().text(translator.translate(extFirmware.translate));
							$('#extFirmware').prop('firmware', extFirmware.name);
							$('#extFirmwarea').show().text(translator.translate(extFirmwarea.translate));
							$('#extFirmwarea').prop('firmware', extFirmwarea.name);
							$('#firmware').text(translator.translate(firmware.translate));
							$('#firmware').prop('firmware', firmware.name);
						}

					}
				}
			});
		},
		flashFirmware: function(firmware, config) {
			$('#firmwareButtonSet').hide();
			try{
				if (!router.connector) {
					alert(translator.translate('Hardware Device Is Not Connected'));
					$('#firmwareButtonSet').show();
					return;
				}
				ui.showAlert(translator.translate("Firmware Uploading..."));
				var port = router.connector.sp.path;
				var baudRate = config.firmwareBaudRate;
				router.close();
	            setTimeout(function () {
	    			flasher.flash(
	    				firmware,
	    				port,
	    				baudRate
	    				,
	    				function(error, stdout, stderr) {
	    					$('#firmwareButtonSet').show();
	    					ui.showAlert(translator.translate("Firmware Uploaded!"));
	    					router.startScan(config);
	    				}
	    			);
	            }, 200);
			} catch(e) {
				$('#firmwareButtonSet').show();
			}
		},
		setState: function(state) {
			if(state == 'connected') {
				ui.showConnected();
			} else if(state == 'lost') {
				$('#message').text(translator.translate('Connecting...'));
			} else if(state == 'disconnected') {
				ui.showDisconnected();
			}
		},
		quit: function() {
			// win.close();
		},
		showIeGuide: function() {
			$('#ieGuide').show();
		},
		hideIeGuide: function() {
			$('#ieGuide').hide();
		}
	};

	$('#back.navigate_button').click(function(e) {
		delete window.currentConfig.this_com_port;
		ui.showRobotList();
		router.close();
	});

	$('.chromeButton').click(function(e) {
		shell.openItem("https://www.google.com/chrome/browser/desktop/index.html");
	});

	function isOSWin64() {
  		return process.arch === 'x64' || process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
	};

	// close
	window.onbeforeunload = function(e) {
		var isQuit = true;
		if(router.connector && router.connector.connected) {
			isQuit = confirm(translator.translate('Connection to the hardware will terminate once program is closed.'));
		}

		if(isQuit) {
			router.close();
			server.close();
		} else {
			e.preventDefault();
			e.returnValue = false;
		}
	};

	$('#select_port').dblclick(function () {
		$('#btn_select_port').trigger('click');
	});

	$('#btn_select_port').click(function(e) {
		var com_port = $("#select_port").val();
		if(!com_port) {
			alert('연결할 COM PORT를 선택하세요.');
		} else {
			window.currentConfig.this_com_port = com_port[0];
			clear_select_port();
		}
	});

	$('#btn_select_port_cancel').click(function(e) {
		clear_select_port();
		clearTimeout(select_port_connection);
		ui.showRobotList();
	});

	function clear_select_port() {
		is_select_port = false;
		_cache_object = '';
		$('#select_port_box').css('display', 'none');
	}

	var _cache_object = '';
	var _com_port = '';
	var is_select_port = true;
	var select_port_connection;
	// state
	router.on('state', function(state, data) {
		if (state === "select_port") {
			router.close();
			var _temp = JSON.stringify(data);
			if(_temp !== _cache_object && is_select_port) {
				var port_html = '';
				data.forEach(function (port) {
					port_html += '<option>' + port.comName + '</option>';
				});

				$('#select_port_box').css('display', 'flex');
				$('#select_port_box select').html(port_html);

				_cache_object = _temp;
			}
			if(is_select_port) {
				select_port_connection = setTimeout(function () {
					router.startScan(window.currentConfig);
				}, 1000);
			} else {
				is_select_port = true;
			}
			return;
		} else if (state === "flash") {
			console.log('flash');
            $('#firmware').trigger('click');
		} else if (state === "connect" && window.currentConfig.softwareReset) {
			var sp = router.connector.sp;
			sp.set({dtr: false}, function(){});
			setTimeout(function() {sp.set({dtr: true}, function(){})}, 1000);
			return;
		} else if ((state === "lost" || state === "disconnected") && window.currentConfig.reconnect) {
			router.close();
			ui.showConnecting();
			router.startScan(window.currentConfig);
			return;
		} else if(state === 'before_connect' && window.currentConfig.firmware) {
			ui.showAlert(translator.translate('Connecting to hardware device.') + ' 펌웨어를 선택해 주세요.');
		}
		ui.setState(state);
		server.setState(state);
	});

	//ipcEvent
	ipcRenderer.on('update-message', function (e, message) {

	});

	// configuration
	var fs = require('fs');
	var path = require('path');
	fs.readdir(path.join(__dirname, 'modules'), function(error, files) {
		if(error) {
			logger.e(error);
			return;
		}
		var hardwareList = [];
		files.filter(function(file) {
			return /(?:\.([^.]+))?$/.exec(file)[1] == 'json';
		}).forEach(function(file) {
			try {
				var config = fs.readFileSync(path.join(__dirname, 'modules', file));
				hardwareList.push(JSON.parse(config));
			} catch(e) {}
		});

		hardwareList.sort(function (left, right) {
			var lName = left.name.ko.trim();
			var rName = right.name.ko.trim();
			var lIndex = (Array.isArray(selectedList)) ? selectedList.indexOf(lName) : 0;
			var rIndex = (Array.isArray(selectedList)) ? selectedList.indexOf(rName) : 0;
			if(lIndex < rIndex) {
				return 1;
			} else if (lIndex > rIndex) {
				return -1;
			} else if(lName > rName) {
				return 1;
			} else if(lName < rName) {
				return -1;
			} else {
				return 0;
			}
		});

		hardwareList.forEach(function (config) {
			ui.addRobot(config);
		});
	});
}());
<commit_msg>gpg sign test<commit_after>(function() {
	'use strict';

	var VERSION = 1.1;

	// initialize options
	var options = {};

	// language
	var translator = require('./custom_modules/translator');
	var lang = translator.getLanguage();

	// logger
	var logger = {
		v: function(str) {
			console.log(str);
		},
		i: function(str) {
			console.info('%c' + str, 'color: dodgerblue');
		},
		w: function(str) {
			console.warn('%c' + str, 'color: orange');
		},
		e: function(str) {
			console.error('%c' + str, 'color: red');
		}
	};
	require('./custom_modules/logger').set(logger);

	// server
	var server = require('./custom_modules/entry');
	server.open(logger);

	// router
	var router = require('./custom_modules/router').init(server);
	window.router = router;

	// flasher
	var flasher = require('./custom_modules/flasher');
	// ui & control
	$('#driver').text(translator.translate('Install Device Driver'));
	$('#firmware').text(translator.translate('Install Firmware'));
	$('#other-robot .text').text(translator.translate('Connect Other Hardware'));
	$('#entry .text').text(translator.translate('Show Entry Web Page'));

	var ui = {
		countRobot: 0,
		showRobotList: function() {
			router.close();
			router.stopScan();
			delete window.currentConfig;
			$('#title').text(translator.translate('Select hardware'));
			$('#hwList').show();
			$('#hwPanel').css('display', 'none');
			ui.showIeGuide();
			this.hideAlert();
		},
		showConnecting: function() {
			$('#title').text(translator.translate('hardware > connecting'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Connecting to hardware device.'));
		},
		showConnected: function() {
			$('#title').text(translator.translate('hardware > connected'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Connected to hardware device.'), 2000);
		},
		showDisconnected: function() {
			$('#title').text(translator.translate('hardware > disconnected'));
			$('#hwList').hide();
			$('#hwPanel').css('display', 'flex');
			ui.hideIeGuide();
			this.showAlert(translator.translate('Hardware device is disconnected. Please restart this program.'));
		},
		showAlert: function(message, duration) {
			$('#alert').text(message);

			$('#alert').css({
				height: '0px'
			});
			$('#alert').animate({
				height: '35px'
			});

			if (duration) {
				setTimeout(function(){
					$('#alert').animate({
						height: '0px'
					});
				}, duration);
			}
		},
		hideAlert: function(message) {
			$('#alert').animate({
				height: '0px'
			});
		},
		addRobot: function(config) {
			ui.showRobotList();
			var name;
			if(config.name) {
				name = config.name[lang] || config.name['en'];
			}

			$('#hwList').append(
					'
' +
					'' +
					'
' + name + '

');

			$('#' + config.id).click(function() {
				if(config.hardware.type === 'bluetooth') {
					is_select_port = true;
				}

				var newSelectList = selectedList.filter(function (item) {
					return item !== config.name.ko;
				});
				newSelectList.push(config.name.ko);
				localStorage.setItem('hardwareList', JSON.stringify(newSelectList));
				selectedList = newSelectList;
				ui.hardware = config.id.substring(0, 4);
				ui.numLevel = 1;
				ui.showConnecting();
				router.startScan(config);
				window.currentConfig = config;

				var icon = './modules/' + config.icon;
				$('#selectedHWThumb').attr('src', icon);

				if(config.url) {
					$('#url').text(config.url);
					$('#url').show();
					$('#url').unbind('click');
					$('#url').click(function() {
						shell.openItem(config.url);
					});
				} else {
					$('#url').hide();
				}

				$('#driver').hide();
				$('#firmware').hide();
				$('#extFirmware').hide();
				$('#extFirmwarea').hide();
				$('#firmware').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});
				$('#extFirmware').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});
				$('#extFirmwarea').on('click', function () {
					ui.flashFirmware(this.firmware, config);
				});

				if(config.driver) {
					var os = process.platform + '-' + (isOSWin64() ? 'x64' : process.arch);
					var driverPath = config.driver[os];
					if(driverPath) {
						$('#driver').show();
						$('#driver').unbind('click');
						$('#driver').click(function() {
							var driversPath;
							if(__dirname.indexOf('.asar') >= 0) {
								driversPath = path.join(__dirname, '..', 'drivers', driverPath);
							} else {
								driversPath = path.join(__dirname, 'drivers', driverPath);
							}
							shell.openItem(driversPath);
						});
					}
					if (config.firmware) {
						$('#firmware').show();
						if(typeof config.firmware === 'string') {
							$('#firmware').text(translator.translate('Install Firmware'));
							$('#firmware').prop('firmware', config.firmware);
						} else if(Array.isArray(config.firmware)) {
							var firmware = config.firmware[0];
							var extFirmware = config.firmware[1];
							var extFirmwarea = config.firmware[2];
							$('#extFirmware').show().text(translator.translate(extFirmware.translate));
							$('#extFirmware').prop('firmware', extFirmware.name);
							$('#extFirmwarea').show().text(translator.translate(extFirmwarea.translate));
							$('#extFirmwarea').prop('firmware', extFirmwarea.name);
							$('#firmware').text(translator.translate(firmware.translate));
							$('#firmware').prop('firmware', firmware.name);
						}

					}
				}
			});
		},
		flashFirmware: function(firmware, config) {
			$('#firmwareButtonSet').hide();
			try{
				if (!router.connector) {
					alert(translator.translate('Hardware Device Is Not Connected'));
					$('#firmwareButtonSet').show();
					return;
				}
				ui.showAlert(translator.translate("Firmware Uploading..."));
				var port = router.connector.sp.path;
				var baudRate = config.firmwareBaudRate;
				router.close();
	            setTimeout(function () {
	    			flasher.flash(
	    				firmware,
	    				port,
	    				baudRate
	    				,
	    				function(error, stdout, stderr) {
	    					$('#firmwareButtonSet').show();
	    					ui.showAlert(translator.translate("Firmware Uploaded!"));
	    					router.startScan(config);
	    				}
	    			);
	            }, 200);
			} catch(e) {
				$('#firmwareButtonSet').show();
			}
		},
		setState: function(state) {
			if(state == 'connected') {
				ui.showConnected();
			} else if(state == 'lost') {
				$('#message').text(translator.translate('Connecting...'));
			} else if(state == 'disconnected') {
				ui.showDisconnected();
			}
		},
		quit: function() {

		},
		showIeGuide: function() {
			$('#ieGuide').show();
		},
		hideIeGuide: function() {
			$('#ieGuide').hide();
		}
	};

	$('#back.navigate_button').click(function(e) {
		delete window.currentConfig.this_com_port;
		ui.showRobotList();
		router.close();
	});

	$('.chromeButton').click(function(e) {
		shell.openItem("https://www.google.com/chrome/browser/desktop/index.html");
	});

	function isOSWin64() {
  		return process.arch === 'x64' || process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
	};

	// close
	window.onbeforeunload = function(e) {
		var isQuit = true;
		if(router.connector && router.connector.connected) {
			isQuit = confirm(translator.translate('Connection to the hardware will terminate once program is closed.'));
		}

		if(isQuit) {
			router.close();
			server.close();
		} else {
			e.preventDefault();
			e.returnValue = false;
		}
	};

	$('#select_port').dblclick(function () {
		$('#btn_select_port').trigger('click');
	});

	$('#btn_select_port').click(function(e) {
		var com_port = $("#select_port").val();
		if(!com_port) {
			alert('연결할 COM PORT를 선택하세요.');
		} else {
			window.currentConfig.this_com_port = com_port[0];
			clear_select_port();
		}
	});

	$('#btn_select_port_cancel').click(function(e) {
		clear_select_port();
		clearTimeout(select_port_connection);
		ui.showRobotList();
	});

	function clear_select_port() {
		is_select_port = false;
		_cache_object = '';
		$('#select_port_box').css('display', 'none');
	}

	var _cache_object = '';
	var _com_port = '';
	var is_select_port = true;
	var select_port_connection;
	// state
	router.on('state', function(state, data) {
		if (state === "select_port") {
			router.close();
			var _temp = JSON.stringify(data);
			if(_temp !== _cache_object && is_select_port) {
				var port_html = '';
				data.forEach(function (port) {
					port_html += '<option>' + port.comName + '</option>';
				});

				$('#select_port_box').css('display', 'flex');
				$('#select_port_box select').html(port_html);

				_cache_object = _temp;
			}
			if(is_select_port) {
				select_port_connection = setTimeout(function () {
					router.startScan(window.currentConfig);
				}, 1000);
			} else {
				is_select_port = true;
			}
			return;
		} else if (state === "flash") {
			console.log('flash');
            $('#firmware').trigger('click');
		} else if (state === "connect" && window.currentConfig.softwareReset) {
			var sp = router.connector.sp;
			sp.set({dtr: false}, function(){});
			setTimeout(function() {sp.set({dtr: true}, function(){})}, 1000);
			return;
		} else if ((state === "lost" || state === "disconnected") && window.currentConfig.reconnect) {
			router.close();
			ui.showConnecting();
			router.startScan(window.currentConfig);
			return;
		} else if(state === 'before_connect' && window.currentConfig.firmware) {
			ui.showAlert(translator.translate('Connecting to hardware device.') + ' 펌웨어를 선택해 주세요.');
		}
		ui.setState(state);
		server.setState(state);
	});

	//ipcEvent
	ipcRenderer.on('update-message', function (e, message) {

	});

	// configuration
	var fs = require('fs');
	var path = require('path');
	fs.readdir(path.join(__dirname, 'modules'), function(error, files) {
		if(error) {
			logger.e(error);
			return;
		}
		var hardwareList = [];
		files.filter(function(file) {
			return /(?:\.([^.]+))?$/.exec(file)[1] == 'json';
		}).forEach(function(file) {
			try {
				var config = fs.readFileSync(path.join(__dirname, 'modules', file));
				hardwareList.push(JSON.parse(config));
			} catch(e) {}
		});

		hardwareList.sort(function (left, right) {
			var lName = left.name.ko.trim();
			var rName = right.name.ko.trim();
			var lIndex = (Array.isArray(selectedList)) ? selectedList.indexOf(lName) : 0;
			var rIndex = (Array.isArray(selectedList)) ? selectedList.indexOf(rName) : 0;
			if(lIndex < rIndex) {
				return 1;
			} else if (lIndex > rIndex) {
				return -1;
			} else if(lName > rName) {
				return 1;
			} else if(lName < rName) {
				return -1;
			} else {
				return 0;
			}
		});

		hardwareList.forEach(function (config) {
			ui.addRobot(config);
		});
	});
}());
<|endoftext|>


<commit_before>import {EventAggregator} from 'aurelia-event-aggregator';
import {ViewResources} from 'aurelia-templating';
import {DefaultLoader} from 'aurelia-loader-default';
import {BindingSignaler} from 'aurelia-templating-resources';

import {I18N} from './i18n';
import {RelativeTime} from './relativeTime';
import {DfValueConverter} from './df';
import {NfValueConverter} from './nf';
import {RtValueConverter} from './rt';
import {TValueConverter} from './t';
import {TBindingBehavior} from './t';
import {TCustomAttribute} from './t';
import {TParamsCustomAttribute} from './t';
import {BaseI18N} from './base-i18n';

function configure(frameworkConfig, cb) {
  if (cb === undefined || typeof cb !== 'function') {
    let errorMsg = 'You need to provide a callback method to properly configure the library';
    throw errorMsg;
  }

  frameworkConfig.globalResources('./t');
  frameworkConfig.globalResources('./nf');
  frameworkConfig.globalResources('./df');
  frameworkConfig.globalResources('./rt');

  let instance = new I18N(frameworkConfig.container.get(EventAggregator),
    frameworkConfig.container.get(DefaultLoader), frameworkConfig.container.get(BindingSignaler));
  frameworkConfig.container.registerInstance(I18N, instance);

  let ret = cb(instance);

  frameworkConfig.postTask(() => {
    let resources = frameworkConfig.container.get(ViewResources);
    let htmlBehaviorResource = resources.getAttribute('t');
    let attributes = instance.i18next.options.attributes;

    // Register default attributes if none provided
    if (!attributes) {
      attributes = ['t', 'i18n'];
    }

    attributes.forEach(alias => resources.registerAttribute(alias, htmlBehaviorResource, 't'));
    attributes.forEach(alias => resources.registerAttribute(alias + '-params', htmlParamsResource, 't-params'));
  });

  return ret;
}

export {
  configure,
  I18N,
  RelativeTime,
  DfValueConverter,
  NfValueConverter,
  RtValueConverter,
  TValueConverter,
  TBindingBehavior,
  TCustomAttribute,
  TParamsCustomAttribute,
  BaseI18N,
  EventAggregator
};
<commit_msg>fix(params): add missing htmlParamsResource<commit_after>import {EventAggregator} from 'aurelia-event-aggregator';
import {ViewResources} from 'aurelia-templating';
import {DefaultLoader} from 'aurelia-loader-default';
import {BindingSignaler} from 'aurelia-templating-resources';

import {I18N} from './i18n';
import {RelativeTime} from './relativeTime';
import {DfValueConverter} from './df';
import {NfValueConverter} from './nf';
import {RtValueConverter} from './rt';
import {TValueConverter} from './t';
import {TBindingBehavior} from './t';
import {TCustomAttribute} from './t';
import {TParamsCustomAttribute} from './t';
import {BaseI18N} from './base-i18n';

function configure(frameworkConfig, cb) {
  if (cb === undefined || typeof cb !== 'function') {
    let errorMsg = 'You need to provide a callback method to properly configure the library';
    throw errorMsg;
  }

  frameworkConfig.globalResources('./t');
  frameworkConfig.globalResources('./nf');
  frameworkConfig.globalResources('./df');
  frameworkConfig.globalResources('./rt');

  let instance = new I18N(frameworkConfig.container.get(EventAggregator),
    frameworkConfig.container.get(DefaultLoader), frameworkConfig.container.get(BindingSignaler));
  frameworkConfig.container.registerInstance(I18N, instance);

  let ret = cb(instance);

  frameworkConfig.postTask(() => {
    let resources = frameworkConfig.container.get(ViewResources);
    let htmlBehaviorResource = resources.getAttribute('t');
    let htmlParamsResource   = resources.getAttribute('t-params');
    let attributes = instance.i18next.options.attributes;

    // Register default attributes if none provided
    if (!attributes) {
      attributes = ['t', 'i18n'];
    }

    attributes.forEach(alias => resources.registerAttribute(alias, htmlBehaviorResource, 't'));
    attributes.forEach(alias => resources.registerAttribute(alias + '-params', htmlParamsResource, 't-params'));
  });

  return ret;
}

export {
  configure,
  I18N,
  RelativeTime,
  DfValueConverter,
  NfValueConverter,
  RtValueConverter,
  TValueConverter,
  TBindingBehavior,
  TCustomAttribute,
  TParamsCustomAttribute,
  BaseI18N,
  EventAggregator
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.comics.v2',
  name: 'DAOSummaryView',
  extends: 'foam.u2.View',

  documentation: `
    A configurable summary view for a specific instance
  `,

  topics: [
    'finished',
    'throwError'
  ],

  axioms: [
    foam.pattern.Faceted.create()
  ],

  css:`
    ^ {
      padding: 32px
    }

    ^ .foam-u2-ActionView-back {
      display: flex;
      align-items: center;
      width: 30%;
    }

    ^account-name {
      font-size: 36px;
      font-weight: 600;
    }

    ^actions-header .foam-u2-ActionView {
      margin-right: 24px;
      line-height: 1.5
    }

    ^view-container {
      margin: auto;
    }
  `,

  requires: [
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.dialog.NotificationMessage',
    'foam.u2.dialog.Popup',
  ],

  imports: [
    'stack'
  ],

  exports: [
    'controllerMode'
  ],

  properties: [
    {
      class: 'FObjectProperty',
      name: 'data'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.comics.v2.DAOControllerConfig',
      name: 'config'
    },
    {
      name: 'controllerMode',
      factory: function() {
        return this.ControllerMode.VIEW;
      }
    },
    {
      name: 'primary',
      expression: function(config$of) {
        var allActions = config$of.getAxiomsByClass(foam.core.Action);
        var defaultAction = allActions.filter((a) => a.isDefault);
        return defaultAction.length >= 1 ? defaultAction[0] : allActions[0];
      }
    },
    {
      class: 'foam.u2.ViewSpecWithJava',
      name: 'viewView',
      expression: function() {
        return foam.u2.detail.SectionedDetailView;
      }
    }
  ],

  actions: [
    {
      name: 'edit',
      isAvailable: function(config$editEnabled) {
        return config$editEnabled;
      },
      code: function() {
        if ( ! this.stack ) return;
        this.stack.push({
          class: 'foam.comics.v2.DAOUpdateView',
          data: this.data,
          config: this.config,
          of: this.config.of
        });
      }
    },
    {
      name: 'delete',
      isAvailable: function(config$deleteEnabled) {
        return config$deleteEnabled;
      },
      code: function() {
        this.add(this.Popup.create().tag({
          class: 'foam.u2.DeleteModal',
          dao: this.config.dao,
          onDelete: () => {
            this.finished.pub();
            this.stack.back();
          },
          data: this.data
        }));
      }
    }
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();
      this
        .addClass(this.myClass())
        .add(self.slot(function(data, data$id, config$CRUDActionsAuth$update, config$CRUDActionsAuth$delete,config$browseTitle, config$viewBorder, viewView) {

          // iterate through permissions and replace % with data$id
          var editAction = self.EDIT;
          var deleteAction = self.DELETE;

          if ( config$CRUDActionsAuth$update ){
            var editArray = config$CRUDActionsAuth$update;

            editArray = editArray.map(permission => {
              return permission.replace("%", data$id);
            });

            editAction = self.EDIT.clone().copyFrom({
              availablePermissions: self.EDIT.availablePermissions.concat(editArray)
            });
          }

          if ( config$CRUDActionsAuth$delete ){
            var deleteArray = config$CRUDActionsAuth$delete;

            deleteArray = deleteArray.map(permission => {
              return permission.replace("%", data$id);
            });

            deleteAction = self.DELETE.copyFrom({
              availablePermissions: deleteArray
            });
          }

          return self.E()
            .start(self.Rows)
              .start(self.Rows)
                // we will handle this in the StackView instead
                .startContext({ data: self.stack })
                  .tag(self.stack.BACK, {
                    buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                    icon: 'images/back-icon.svg',
                    label: `All ${config$browseTitle}`
                  })
                .endContext()
                .start(self.Cols).style({ 'align-items': 'center' })
                  .start()
                    .add(data.toSummary())
                    .addClass(this.myClass('account-name'))
                  .end()
                  .startContext({ data }).add(self.primary).endContext()
                .end()
              .end()

              .start(self.Cols)
                .start(self.Cols).addClass(this.myClass('actions-header'))
                  .startContext({ data: self })
                    .tag(editAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/edit-icon.svg'
                    })
                    .tag(deleteAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/delete-icon.svg'
                    })
                  .endContext()
                .end()
              .end()

              .start(config$viewBorder)
                .start(viewView, { data }).addClass(this.myClass('view-container')).end()
              .end()
            .end();
        }));
    }
  ]
});
<commit_msg>Update src/foam/comics/v2/DAOSummaryView.js<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.comics.v2',
  name: 'DAOSummaryView',
  extends: 'foam.u2.View',

  documentation: `
    A configurable summary view for a specific instance
  `,

  topics: [
    'finished',
    'throwError'
  ],

  axioms: [
    foam.pattern.Faceted.create()
  ],

  css:`
    ^ {
      padding: 32px
    }

    ^ .foam-u2-ActionView-back {
      display: flex;
      align-items: center;
      width: 30%;
    }

    ^account-name {
      font-size: 36px;
      font-weight: 600;
    }

    ^actions-header .foam-u2-ActionView {
      margin-right: 24px;
      line-height: 1.5
    }

    ^view-container {
      margin: auto;
    }
  `,

  requires: [
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.dialog.NotificationMessage',
    'foam.u2.dialog.Popup',
  ],

  imports: [
    'stack'
  ],

  exports: [
    'controllerMode'
  ],

  properties: [
    {
      class: 'FObjectProperty',
      name: 'data'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.comics.v2.DAOControllerConfig',
      name: 'config'
    },
    {
      name: 'controllerMode',
      factory: function() {
        return this.ControllerMode.VIEW;
      }
    },
    {
      name: 'primary',
      expression: function(config$of) {
        var allActions = config$of.getAxiomsByClass(foam.core.Action);
        var defaultAction = allActions.filter((a) => a.isDefault);
        return defaultAction.length >= 1 ? defaultAction[0] : allActions[0];
      }
    },
    {
      class: 'foam.u2.ViewSpecWithJava',
      name: 'viewView',
      expression: function() {
        return foam.u2.detail.SectionedDetailView;
      }
    }
  ],

  actions: [
    {
      name: 'edit',
      isAvailable: function(config$editEnabled) {
        return config$editEnabled;
      },
      code: function() {
        if ( ! this.stack ) return;
        this.stack.push({
          class: 'foam.comics.v2.DAOUpdateView',
          data: this.data,
          config: this.config,
          of: this.config.of
        });
      }
    },
    {
      name: 'delete',
      isAvailable: function(config$deleteEnabled) {
        return config$deleteEnabled;
      },
      code: function() {
        this.add(this.Popup.create().tag({
          class: 'foam.u2.DeleteModal',
          dao: this.config.dao,
          onDelete: () => {
            this.finished.pub();
            this.stack.back();
          },
          data: this.data
        }));
      }
    }
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();
      this
        .addClass(this.myClass())
        .add(self.slot(function(data, data$id, config$CRUDActionsAuth$update, config$CRUDActionsAuth$delete,config$browseTitle, config$viewBorder, viewView) {

          // iterate through permissions and replace % with data$id
          var editAction = self.EDIT;
          var deleteAction = self.DELETE;

          if ( config$CRUDActionsAuth$update ) {
            var editArray = config$CRUDActionsAuth$update;

            editArray = editArray.map(permission => {
              return permission.replace("%", data$id);
            });

            editAction = self.EDIT.clone().copyFrom({
              availablePermissions: self.EDIT.availablePermissions.concat(editArray)
            });
          }

          if ( config$CRUDActionsAuth$delete ){
            var deleteArray = config$CRUDActionsAuth$delete;

            deleteArray = deleteArray.map(permission => {
              return permission.replace("%", data$id);
            });

            deleteAction = self.DELETE.copyFrom({
              availablePermissions: deleteArray
            });
          }

          return self.E()
            .start(self.Rows)
              .start(self.Rows)
                // we will handle this in the StackView instead
                .startContext({ data: self.stack })
                  .tag(self.stack.BACK, {
                    buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                    icon: 'images/back-icon.svg',
                    label: `All ${config$browseTitle}`
                  })
                .endContext()
                .start(self.Cols).style({ 'align-items': 'center' })
                  .start()
                    .add(data.toSummary())
                    .addClass(this.myClass('account-name'))
                  .end()
                  .startContext({ data }).add(self.primary).endContext()
                .end()
              .end()

              .start(self.Cols)
                .start(self.Cols).addClass(this.myClass('actions-header'))
                  .startContext({ data: self })
                    .tag(editAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/edit-icon.svg'
                    })
                    .tag(deleteAction, {
                      buttonStyle: foam.u2.ButtonStyle.TERTIARY,
                      icon: 'images/delete-icon.svg'
                    })
                  .endContext()
                .end()
              .end()

              .start(config$viewBorder)
                .start(viewView, { data }).addClass(this.myClass('view-container')).end()
              .end()
            .end();
        }));
    }
  ]
});
<|endoftext|>


<commit_before>/* @flow */
import queryString from 'query-string'
import { decodeToken } from 'jsontokens'
import { makeAuthRequest, verifyAuthResponse } from './index'
import protocolCheck from 'custom-protocol-detection-blockstack'
import { BLOCKSTACK_HANDLER } from '../utils'
import { makeECPrivateKey } from '../index'
import { BLOCKSTACK_APP_PRIVATE_KEY_LABEL,
         BLOCKSTACK_STORAGE_LABEL,
         DEFAULT_BLOCKSTACK_HOST,
         DEFAULT_SCOPE } from './authConstants'

/**
 * Generates a ECDSA keypair and stores the hex value of the private key in
 * local storage.
 * @return {String} the hex encoded private key
 * @private
 */
export function generateAndStoreAppKey() {
  const transitKey = makeECPrivateKey()
  localStorage.setItem(BLOCKSTACK_APP_PRIVATE_KEY_LABEL, transitKey)
  return transitKey
}

/**
 * Check if a user is currently signed in.
 * @return {Boolean} `true` if the user is signed in, `false` if not.
 */
export function isUserSignedIn() {
  return !!window.localStorage.getItem(BLOCKSTACK_STORAGE_LABEL)
}

/**
 * Redirects the user to the Blockstack browser to approve the sign in request
 * given.
 *
 * The user is redirected to the `blockstackIDHost` if the `blockstack:`
 * protocol handler is not detected. Please note that the protocol handler detection
 * does not work on all browsers.
 * @param  {String} authRequest - the authentication request generated by `makeAuthRequest`
 * @param  {String} blockstackIDHost - the URL to redirect the user to if the blockstack
 *                                     protocol handler is not detected
 * @return {void}
 */
export function redirectToSignInWithAuthRequest(authRequest: string = makeAuthRequest(),
                                     blockstackIDHost: string = DEFAULT_BLOCKSTACK_HOST) {
  const protocolURI = `${BLOCKSTACK_HANDLER}:${authRequest}`
  const httpsURI = `${blockstackIDHost}?authRequest=${authRequest}`
  function successCallback() {
    console.log('protocol handler detected')
    // protocolCheck should open the link for us
  }

  function failCallback() {
    console.log('protocol handler not detected')
    window.location = httpsURI
  }

  function unsupportedBrowserCallback() { // Safari is unsupported by protocolCheck
    console.log('can not detect custom protocols on this browser')
    window.location = protocolURI
  }

  protocolCheck(protocolURI, failCallback, successCallback, unsupportedBrowserCallback)
}

/**
 * Generates an authentication request and redirects the user to the Blockstack
 * browser to approve the sign in request.
 *
 * Please note that this requires that the web browser properly handles the
 * `blockstack:` URL protocol handler.
 *
 * Most applications should use this
 * method for sign in unless they require more fine grained control over how the
 * authentication request is generated. If your app falls into this category,
 * use `generateAndStoreAppKey`, `makeAuthRequest`,
 * and `redirectToSignInWithAuthRequest` to build your own sign in process.
 *
 * @param {String} [redirectURI=`${window.location.origin}/`]
 * The location to which the identity provider will redirect the user after
 * the user approves sign in.
 * @param  {String} [manifestURI=`${window.location.origin}/manifest.json`]
 * Location of the manifest file.
 * @param  {Array} [scopes=DEFAULT_SCOPE] Defaults to requesting write access to
 * this app's data store.
 * An array of strings indicating which permissions this app is requesting.
 * @return {void}
 */
export function redirectToSignIn(redirectURI: string = `${window.location.origin}/`,
                                 manifestURI: string = `${window.location.origin}/manifest.json`,
                                 scopes: Array<string> = DEFAULT_SCOPE) {
  const authRequest = makeAuthRequest(generateAndStoreAppKey(), redirectURI, manifestURI, scopes)
  redirectToSignInWithAuthRequest(authRequest)
}

/**
 * Retrieve the authentication token from the URL query
 * @return {String} the authentication token if it exists otherwise `null`
 */
export function getAuthResponseToken() {
  const queryDict = queryString.parse(location.search)
  return queryDict.authResponse ? queryDict.authResponse : null
}

/**
 * Check if there is a authentication request that hasn't been handled.
 * @return {Boolean} `true` if there is a pending sign in, otherwise `false`
 */
export function isSignInPending() {
  return !!getAuthResponseToken()
}

/**
 * Try to process any pending sign in request by returning a `Promise` that resolves
 * to the user data object if the sign in succeeds.
 *
 * @param {String} nameLookupURL - the endpoint against which to verify public
 * keys match claimed username
 *
 * @return {Promise} that resolves to the user data object if successful and rejects
 * if handling the sign in request fails or there was no pending sign in request.
 */
export function handlePendingSignIn(nameLookupURL: string = 'https://core.blockstack.org/v1/names/') {
  const authResponseToken = getAuthResponseToken()

  return new Promise((resolve, reject) => {
    verifyAuthResponse(authResponseToken, nameLookupURL)
    .then(isValid => {
      if (isValid) {
        const tokenPayload = decodeToken(authResponseToken).payload
        const userData = {
          username: tokenPayload.username,
          profile: tokenPayload.profile,
          appPrivateKey: tokenPayload.private_key,
          coreSessionToken: tokenPayload.core_token,
          authResponseToken
        }
        window.localStorage.setItem(
          BLOCKSTACK_STORAGE_LABEL, JSON.stringify(userData))
        resolve(userData)
      } else {
        reject()
      }
    })
  })
}

/**
 * Retrieves the user data object. The user's profile is stored in the key `profile`.
 * @return {Object} User data object.
 */
export function loadUserData() {
  return JSON.parse(window.localStorage.getItem(BLOCKSTACK_STORAGE_LABEL))
}

/**
 * Sign the user out and redirect to given location.
 * @param  {String} [redirectURL='/'] Location to redirect user to after sign out.
 * @return {void}
 */
export function signUserOut(redirectURL: string = null) {
  window.localStorage.removeItem(BLOCKSTACK_STORAGE_LABEL)

  if (redirectURL != null){
    window.location = redirectURL
  }
}
<commit_msg>Update authApp.js<commit_after>/* @flow */
import queryString from 'query-string'
import { decodeToken } from 'jsontokens'
import { makeAuthRequest, verifyAuthResponse } from './index'
import protocolCheck from 'custom-protocol-detection-blockstack'
import { BLOCKSTACK_HANDLER } from '../utils'
import { makeECPrivateKey } from '../index'
import { BLOCKSTACK_APP_PRIVATE_KEY_LABEL,
         BLOCKSTACK_STORAGE_LABEL,
         DEFAULT_BLOCKSTACK_HOST,
         DEFAULT_SCOPE } from './authConstants'

/**
 * Generates a ECDSA keypair and stores the hex value of the private key in
 * local storage.
 * @return {String} the hex encoded private key
 * @private
 */
export function generateAndStoreAppKey() {
  const transitKey = makeECPrivateKey()
  localStorage.setItem(BLOCKSTACK_APP_PRIVATE_KEY_LABEL, transitKey)
  return transitKey
}

/**
 * Check if a user is currently signed in.
 * @return {Boolean} `true` if the user is signed in, `false` if not.
 */
export function isUserSignedIn() {
  return !!window.localStorage.getItem(BLOCKSTACK_STORAGE_LABEL)
}

/**
 * Redirects the user to the Blockstack browser to approve the sign in request
 * given.
 *
 * The user is redirected to the `blockstackIDHost` if the `blockstack:`
 * protocol handler is not detected. Please note that the protocol handler detection
 * does not work on all browsers.
 * @param  {String} authRequest - the authentication request generated by `makeAuthRequest`
 * @param  {String} blockstackIDHost - the URL to redirect the user to if the blockstack
 *                                     protocol handler is not detected
 * @return {void}
 */
export function redirectToSignInWithAuthRequest(authRequest: string = makeAuthRequest(),
                                     blockstackIDHost: string = DEFAULT_BLOCKSTACK_HOST) {
  const protocolURI = `${BLOCKSTACK_HANDLER}:${authRequest}`
  const httpsURI = `${blockstackIDHost}?authRequest=${authRequest}`
  function successCallback() {
    console.log('protocol handler detected')
    // protocolCheck should open the link for us
  }

  function failCallback() {
    console.log('protocol handler not detected')
    window.location = httpsURI
  }

  function unsupportedBrowserCallback() { // Safari is unsupported by protocolCheck
    console.log('can not detect custom protocols on this browser')
    window.location = protocolURI
  }

  protocolCheck(protocolURI, failCallback, successCallback, unsupportedBrowserCallback)
}

/**
 * Generates an authentication request and redirects the user to the Blockstack
 * browser to approve the sign in request.
 *
 * Please note that this requires that the web browser properly handles the
 * `blockstack:` URL protocol handler.
 *
 * Most applications should use this
 * method for sign in unless they require more fine grained control over how the
 * authentication request is generated. If your app falls into this category,
 * use `generateAndStoreAppKey`, `makeAuthRequest`,
 * and `redirectToSignInWithAuthRequest` to build your own sign in process.
 *
 * @param {String} [redirectURI=`${window.location.origin}/`]
 * The location to which the identity provider will redirect the user after
 * the user approves sign in.
 * @param  {String} [manifestURI=`${window.location.origin}/manifest.json`]
 * Location of the manifest file.
 * @param  {Array} [scopes=DEFAULT_SCOPE] Defaults to requesting write access to
 * this app's data store.
 * An array of strings indicating which permissions this app is requesting.
 * @return {void}
 */
export function redirectToSignIn(redirectURI: string = `${window.location.origin}/`,
                                 manifestURI: string = `${window.location.origin}/manifest.json`,
                                 scopes: Array<string> = DEFAULT_SCOPE) {
  const authRequest = makeAuthRequest(generateAndStoreAppKey(), redirectURI, manifestURI, scopes)
  redirectToSignInWithAuthRequest(authRequest)
}

/**
 * Retrieve the authentication token from the URL query
 * @return {String} the authentication token if it exists otherwise `null`
 */
export function getAuthResponseToken() {
  const queryDict = queryString.parse(location.search)
  return queryDict.authResponse ? queryDict.authResponse : null
}

/**
 * Check if there is a authentication request that hasn't been handled.
 * @return {Boolean} `true` if there is a pending sign in, otherwise `false`
 */
export function isSignInPending() {
  return !!getAuthResponseToken()
}

/**
 * Try to process any pending sign in request by returning a `Promise` that resolves
 * to the user data object if the sign in succeeds.
 *
 * @param {String} nameLookupURL - the endpoint against which to verify public
 * keys match claimed username
 *
 * @return {Promise} that resolves to the user data object if successful and rejects
 * if handling the sign in request fails or there was no pending sign in request.
 */
export function handlePendingSignIn(nameLookupURL: string = 'https://core.blockstack.org/v1/names/') {
  const authResponseToken = getAuthResponseToken()

  return new Promise((resolve, reject) => {
    verifyAuthResponse(authResponseToken, nameLookupURL)
    .then(isValid => {
      if (isValid) {
        const tokenPayload = decodeToken(authResponseToken).payload
        const userData = {
          username: tokenPayload.username,
          profile: tokenPayload.profile,
          appPrivateKey: tokenPayload.private_key,
          coreSessionToken: tokenPayload.core_token,
          authResponseToken
        }
        window.localStorage.setItem(
          BLOCKSTACK_STORAGE_LABEL, JSON.stringify(userData))
        resolve(userData)
      } else {
        reject()
      }
    })
  })
}

/**
 * Retrieves the user data object. The user's profile is stored in the key `profile`.
 * @return {Object} User data object.
 */
export function loadUserData() {
  return JSON.parse(window.localStorage.getItem(BLOCKSTACK_STORAGE_LABEL))
}

/**
 * Sign the user out and optionally redirect to given location.
 * @param  {String} [redirectURL=null] Location to redirect user to after sign out.
 * @return {void}
 */
export function signUserOut(redirectURL: string = null) {
  window.localStorage.removeItem(BLOCKSTACK_STORAGE_LABEL)

  if (redirectURL !== null) {
    window.location = redirectURL
  }
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'ReciprocalSearch',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.search.SearchManager',
    'foam.u2.view.SearchViewWrapper'
  ],

  imports: [
    'dao',
    'searchColumns'
  ],

  exports: [
    'as filterController',
    'as data'
  ],

  // TODO: CSS classname shouldn't be .net-nanopay-ui-ActionView, fix.
  css: `
    ^ {
      background-color: white;
      border-radius: 2px;
      min-width: 250px;
      font-size: smaller;
    }

    ^ input {
      font-size: medium;
    }

    ^ .foam-u2-tag-Input {
      width: 100%;
    }

    ^ input:not([type="checkbox"]):focus,
    ^ select:focus {
      outline: none;
      border: 1px solid %SECONDARYCOLOR%;
    }

    ^ .general-query {
      padding: 16px 20px;
    }

    ^count {
      font-size: 12pt;
      color: #555;
      margin: 20px 20px 0 20px;
    }

    ^ .net-nanopay-ui-ActionView-clear {
      width: 60px;
      height: 32px;
      margin: 20px;
    }
  `,

  properties: [
    {
      class: 'Class',
      name: 'of'
    },
    {
      name: 'data'
    },
    {
      class: 'Array',
      name: 'filters',
      factory: null,
      expression: function(dao, searchColumns) {
        var of = dao && dao.of;

        if ( ! of ) return [];

        if ( searchColumns ) return searchColumns;

        if ( of.model_.searchColumns ) return of.model_.searchColumns;

        if ( of.model_.tableColumns ) {
          return of.model_.tableColumns.filter(function(c) {
            var axiom = of.getAxiomByName(c);
            return axiom && axiom.searchView;
          });
        }

        return of.getAxiomsByClass(foam.core.Property)
            .filter((prop) => prop.searchView && ! prop.hidden)
            .map(foam.core.Property.NAME.f);
      }
    },
    {
      class: 'Int',
      name: 'selectedCount'
    },
    {
      class: 'Int',
      name: 'totalCount'
    },
  ],

  methods: [
    function initE() {
      var self = this;

      this.dao.on.sub(this.updateTotalCount);
      this.updateTotalCount();

      this.
        addClass(self.myClass()).
        add(this.slot(function(filters) {
          self.show(filters.length);

          var searchManager = self.SearchManager.create({
            dao$: self.dao$,
            predicate$: self.data$
          });

          searchManager.filteredDAO$.sub(self.updateSelectedCount);
          self.updateSelectedCount(0, 0, 0, searchManager.filteredDAO$);

          var e = this.E('div');

          e.onDetach(searchManager);

          var generalQueryView = foam.u2.ViewSpec.createView(
              { class: 'foam.u2.search.TextSearchView' },
              {
                richSearch: true,
                of: self.dao.of.id,
                onKey: true,
                viewSpec: {
                  class: 'foam.u2.tag.Input',
                  focused: true
                }
              },
              this,
              this.__subSubContext__);
          searchManager.add(generalQueryView);
          e.start(generalQueryView).addClass('general-query').end();

          e.forEach(filters, function(f) {
            // TODO: See if this can be cleaned up somehow, if searchView didn't
            // require the proprety explicitly, or could find the search manager
            // via the context and add itself to that.
            var axiom = self.dao.of.getAxiomByName(f);
            var spec = axiom.searchView;
            var view = foam.u2.ViewSpec.createView(spec, {
              property: axiom,
              dao: self.dao
            }, this, this.__subSubContext__);

            searchManager.add(view);
            this
              .start(self.SearchViewWrapper, { searchView: view })
                .addClass(self.myClass('filter'))
              .end();
          });

          return e;
        }, this.filters$))
        .start()
          .addClass(self.myClass('count'))
          // TODO: move formatting function to stdlib
          .add(self.selectedCount$.map(function(a) {
            return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
          }))
          .entity('nbsp')
          .add('of')
          .entity('nbsp')
          .add(self.totalCount$.map(function(a) {
            return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
          }))
          .entity('nbsp')
          .add('selected')
        .end()
        .add(this.CLEAR);
    },

    function addFilter(key) {
      this.filters = this.filters.concat(key);
    },

    function removeFilter(key) {
      this.filters = this.filters.filter(function(k) {
        return key !== k;
      });
    }
  ],

  actions: [
    {
      name: 'clear',
      isSecondary: true,
      code: function() {
        this.data = undefined;
        this.filters = this.filters.slice();
      }
    }
  ],

  listeners: [
    {
      name: 'updateTotalCount',
      isFramed: true,
      code: function() {
        this.dao.select(foam.mlang.sink.Count.create()).then(function(c) {
          this.totalCount = c.value;
        }.bind(this));
      }
    },
    {
      name: 'updateSelectedCount',
      isFramed: true,
      code: function(_, __, ___, dao) {
        dao.get().select(foam.mlang.sink.Count.create()).then(function(c) {
          this.selectedCount = c.value;
        }.bind(this));
      }
    }
  ]
});
<commit_msg>Fix clear button size<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'ReciprocalSearch',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.search.SearchManager',
    'foam.u2.view.SearchViewWrapper'
  ],

  imports: [
    'dao',
    'searchColumns'
  ],

  exports: [
    'as filterController',
    'as data'
  ],

  // TODO: CSS classname shouldn't be .net-nanopay-ui-ActionView, fix.
  css: `
    ^ {
      background-color: white;
      border-radius: 2px;
      min-width: 250px;
      font-size: smaller;
    }

    ^ input {
      font-size: medium;
    }

    ^ .foam-u2-tag-Input {
      width: 100%;
    }

    ^ input:not([type="checkbox"]):focus,
    ^ select:focus {
      outline: none;
      border: 1px solid %SECONDARYCOLOR%;
    }

    ^ .general-query {
      padding: 16px 20px;
    }

    ^count {
      font-size: 12pt;
      color: #555;
      margin: 20px 20px 0 20px;
    }

    ^ .net-nanopay-ui-ActionView-clear {
      margin: 20px;
    }
  `,

  properties: [
    {
      class: 'Class',
      name: 'of'
    },
    {
      name: 'data'
    },
    {
      class: 'Array',
      name: 'filters',
      factory: null,
      expression: function(dao, searchColumns) {
        var of = dao && dao.of;

        if ( ! of ) return [];

        if ( searchColumns ) return searchColumns;

        if ( of.model_.searchColumns ) return of.model_.searchColumns;

        if ( of.model_.tableColumns ) {
          return of.model_.tableColumns.filter(function(c) {
            var axiom = of.getAxiomByName(c);
            return axiom && axiom.searchView;
          });
        }

        return of.getAxiomsByClass(foam.core.Property)
            .filter((prop) => prop.searchView && ! prop.hidden)
            .map(foam.core.Property.NAME.f);
      }
    },
    {
      class: 'Int',
      name: 'selectedCount'
    },
    {
      class: 'Int',
      name: 'totalCount'
    },
  ],

  methods: [
    function initE() {
      var self = this;

      this.dao.on.sub(this.updateTotalCount);
      this.updateTotalCount();

      this.
        addClass(self.myClass()).
        add(this.slot(function(filters) {
          self.show(filters.length);

          var searchManager = self.SearchManager.create({
            dao$: self.dao$,
            predicate$: self.data$
          });

          searchManager.filteredDAO$.sub(self.updateSelectedCount);
          self.updateSelectedCount(0, 0, 0, searchManager.filteredDAO$);

          var e = this.E('div');

          e.onDetach(searchManager);

          var generalQueryView = foam.u2.ViewSpec.createView(
              { class: 'foam.u2.search.TextSearchView' },
              {
                richSearch: true,
                of: self.dao.of.id,
                onKey: true,
                viewSpec: {
                  class: 'foam.u2.tag.Input',
                  focused: true
                }
              },
              this,
              this.__subSubContext__);
          searchManager.add(generalQueryView);
          e.start(generalQueryView).addClass('general-query').end();

          e.forEach(filters, function(f) {
            // TODO: See if this can be cleaned up somehow, if searchView didn't
            // require the proprety explicitly, or could find the search manager
            // via the context and add itself to that.
            var axiom = self.dao.of.getAxiomByName(f);
            var spec = axiom.searchView;
            var view = foam.u2.ViewSpec.createView(spec, {
              property: axiom,
              dao: self.dao
            }, this, this.__subSubContext__);

            searchManager.add(view);
            this
              .start(self.SearchViewWrapper, { searchView: view })
                .addClass(self.myClass('filter'))
              .end();
          });

          return e;
        }, this.filters$))
        .start()
          .addClass(self.myClass('count'))
          // TODO: move formatting function to stdlib
          .add(self.selectedCount$.map(function(a) {
            return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
          }))
          .entity('nbsp')
          .add('of')
          .entity('nbsp')
          .add(self.totalCount$.map(function(a) {
            return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
          }))
          .entity('nbsp')
          .add('selected')
        .end()
        .add(this.CLEAR);
    },

    function addFilter(key) {
      this.filters = this.filters.concat(key);
    },

    function removeFilter(key) {
      this.filters = this.filters.filter(function(k) {
        return key !== k;
      });
    }
  ],

  actions: [
    {
      name: 'clear',
      isSecondary: true,
      code: function() {
        this.data = undefined;
        this.filters = this.filters.slice();
      }
    }
  ],

  listeners: [
    {
      name: 'updateTotalCount',
      isFramed: true,
      code: function() {
        this.dao.select(foam.mlang.sink.Count.create()).then(function(c) {
          this.totalCount = c.value;
        }.bind(this));
      }
    },
    {
      name: 'updateSelectedCount',
      isFramed: true,
      code: function(_, __, ___, dao) {
        dao.get().select(foam.mlang.sink.Count.create()).then(function(c) {
          this.selectedCount = c.value;
        }.bind(this));
      }
    }
  ]
});
<|endoftext|>


<commit_before>function toDouble(x) {
  return Number(x);
}

function toBoolean(x) {
  return Boolean(x);
}

function toUint(x) {
  var obj = x | 0;
  return obj < 0 ? (obj + 4294967296) : obj;
}

function toInt(x) {
  return parseInt(x);
}

function deleteProperty(obj, multiname) {
  // TODO: This is not correct.
  return delete obj[multiname.getQualifiedName()];
}

var globalObject = function () {
  var global = {};
  global.print = global.trace = function (val) {
    console.info(val);
  };
  global.Number = Number;
  global.Boolean = Boolean;
  global.Date = Date;
  global.Array = Array;
  global.Math = Math;
  global.Object = Object;
  global.String = String;
  global.RegExp = RegExp;
  global.Function = Function;
  global.undefined = undefined;
  global.NaN = NaN;
  global.Infinity = Infinity;
  global.JS = (function() { return this || (1,eval)('this'); })();

  global.parseInt = parseInt;

  global.Capabilities = {
    'playerType': 'AVMPlus'
  };

  global.Namespace = (function() {
    function namespace() {
      this.prefix = arguments.length > 1 ? arguments[0] : undefined;
      this.uri = arguments.length == 1 ? arguments[0] : arguments[1];
    }
    return namespace;
  })();

  global.toString = function () {
    return "[object global]";
  };

  return global;
}();

/**
 * Scopes are used to emulate the scope stack as a linked list of scopes, rather than a stack. Each
 * scope holds a reference to a scope [object] (which may exist on multiple scope chains, thus preventing
 * us from chaining the scope objects together directly).
 *
 * Scope Operations:
 *
 *  push scope: scope = new Scope(scope, object)
 *  pop scope: scope = scope.parent
 *  get global scope: scope.global
 *  get scope object: scope.object
 *
 * Method closures have a [savedScope] property which is bound when the closure is created. Since we use a
 * linked list of scopes rather than a scope stack, we don't need to clone the scope stack, we can bind
 * the closure to the current scope.
 *
 * The "scope stack" for a method always starts off as empty and methods push and pop scopes on their scope
 * stack explicitly. If a property is not found on the current scope stack, it is then looked up
 * in the [savedScope]. To emulate this we actually wrap every generated function in a closure, such as
 *
 *  function fnClosure(scope) {
 *    return function fn() {
 *      ... scope;
 *    };
 *  }
 *
 * When functions are created, we bind the function to the current scope, using fnClosure.bind(null, this)();
 */
var Scope = (function () {
  function scope(parent, object) {
    this.parent = parent;
    this.object = object;
  }

  Object.defineProperty(scope.prototype, "global", {
    get: function () {
      if (this.parent === null) {
        return this;
      } else {
        return this.parent.global;
      }
    }
  });

  scope.prototype.findProperty = function findProperty(multiname, strict) {
    for (var i = 0; i < multiname.namespaceCount(); i++) {
      if (this.object.hasOwnProperty(multiname.getQName(i).getQualifiedName())) {
        return this.object;
      }
    }
    if (this.parent) {
      return this.parent.findProperty(multiname, strict);
    }
    if (strict) {
      unexpected("Cannot find property " + multiname);
    }
    return this.global.object;
  };

  /**
   * Returns the first multiname that binds to a property in the scope chain.
   */
  scope.prototype.resolveMultiname = function(multiname) {
    assert (!multiname.isQName());
    var resolved = resolveMultiname(this.object, multiname);
    if (resolved) {
      return resolved;
    }
    if (this.parent) {
      return this.parent.resolveMultiname(multiname);
    }
    return null;
  };

  return scope;
})();

/**
 * Resolve the [multiname] to a QName in the specified [obj], this is a linear that uses [hasOwnProperty]
 * with the qualified name.
 */
function resolveMultiname(obj, multiname, checkPrototype) {
  assert (!multiname.isQName(), "We shouldn't resolve already resolved names.");
  obj = Object(obj);
  for (var i = 0; i < multiname.namespaceCount(); i++) {
    var name = multiname.getQName(i);
    if (checkPrototype) {
      if (name.getQualifiedName() in obj) {
        return name;
      }
    } else {
      if (obj.hasOwnProperty(name.getQualifiedName())) {
        return name;
      }
    }
  }
  return null;
}

function getProperty(obj, multiname) {
  if (multiname.isQName()) {
    return obj[multiname.getQualifiedName()];
  } else {
    var resolved = resolveMultiname(obj, multiname, true);
    if (resolved) {
      return obj[resolved.getQualifiedName()];
    }
  }
  return undefined;
}

/**
 * Execution context for a script.
 */
var Runtime = (function () {
  var functionCount = 0;
  function runtime(abc) {
    this.abc = abc;
    this.compiler = new Compiler(abc);
  }

  runtime.prototype.createActivation = function (method) {
    var obj = {};
    this.applyTraits(obj, method.traits);
    return obj;
  };

  runtime.prototype.createFunction = function (method, scope)  {
    /**
     * TODO: This is terrible, we overwrite the default implementation of call/apply because
     * we need to pass the globalObject whenever call/apply is passed null or undefined for the
     * [this] pointer. We could solve this by merging the AS global object with the JS global
     * object, but that may open up another bag of warms.
     */
    function overwriteCallAndApply(fn) {
      fn.apply = function ($this, args) {
        if ($this === null || $this === undefined) {
          $this = globalObject;
        }
        return Function.prototype.apply.apply(fn, [$this, args]);
      };
      /* Temporarily disable this because it prevents the Chrome debugger from stepping into callees.
      fn.call = function ($this) {
        if ($this === null || $this === undefined) {
          $this = globalObject;
        }
        return Function.prototype.apply.apply(fn, [$this, Array.prototype.slice.call(arguments).slice(1)]);
      };
      */
      return fn;
    }

    if (method.compiledMethodClosure) {
      return overwriteCallAndApply(method.compiledMethodClosure.bind(null, scope)());
    }
    method.analysis = new Analysis(method, { massage: true });
    method.analysis.restructureControlFlow();
    var result = this.compiler.compileMethod(method, scope);

    var parameters = method.parameters.map(function (p) {
      return p.name;
    });

    function flatten(array, indent) {
      var str = "";
      array.forEach(function (x) {
        if (x instanceof Indent) {
          str += flatten(x.statements, indent + "  ");
        } else if (x instanceof Array) {
          str += flatten(x, indent);
        } else {
          str += indent + x + "\n";
        }
      });
      return str;
    }

    // TODO: Use function constructurs,
    // method.compiledMethod = new Function(parameters, flatten(result.statements, ""));

    /* Hook to set breakpoints in compiled code. */
    var body = flatten(result.statements, "");
    if (functionCount == 13) {
      body = "stop();" + body;
    }

    // Eval hack to give generated functions proper names so that stack traces are helpful.
    eval("function fnClosure" + functionCount + "(" + SAVED_SCOPE_NAME + ") { return function fn" + functionCount + " (" + parameters.join(", ") + ") { " + body + " }; }");
    method.compiledMethodClosure = eval("fnClosure" + functionCount);

    if (traceLevel.value > 0) {
      /* Unfortunately inner functions are not pretty-printed by the JS engine, so here we recompile the
       * inner function by itself just for pretty printing purposes.
       */
      eval ("function fnSource" + functionCount + " (" + parameters.join(", ") + ") { " + body + " }");
      print('\033[92m' + eval("fnSource" + functionCount) + '\033[0m');
    }

    functionCount ++;
    return overwriteCallAndApply(method.compiledMethodClosure.bind(null, scope)());
  };

  /**
   * ActionScript Classes are modeled as constructor functions (class objects) which hold additional properties:
   *
   * [scope]: a scope object holding the current class object
   *
   * [baseClass]: a reference to the base class object
   *
   * [instanceTraits]: an accumulated set of traits that are to be applied to instances of this class
   *
   * [prototype]: the prototype object of this constructor function  is populated with the set of instance traits,
   *   when instances are of this class are created, their __proto__ is set to this object thus inheriting this
   *   default set of properties.
   *
   * [construct]: a reference to the class object itself, this is used when invoking the constructor with an already
   *   constructed object (i.e. constructsuper)
   *
   * additionally, the class object also has a set of class traits applied to it which are visible via scope lookups.
   */
  runtime.prototype.createClass = function createClass(classInfo, baseClass, scope) {
    scope = new Scope(scope, null);

    var cls = this.createFunction(classInfo.instance.init, scope);
    scope.object = cls;

    cls.scope = scope;
    cls.classInfo = classInfo;
    cls.baseClass = baseClass;

    if (baseClass) {
      cls.instanceTraits = baseClass.instanceTraits.concat(classInfo.instance.traits);
    } else {
      cls.instanceTraits = classInfo.instance.traits;
      assert (cls.instanceTraits);
    }

    cls.prototype = {};
    this.applyTraits(cls.prototype, cls.instanceTraits);
    this.applyTraits(cls, classInfo.traits);

    /* Call the static constructor. */
    this.createFunction(classInfo.init, this.scope).call(cls);
    cls.construct = cls;
    return cls;
  };

  /* Extend builtin Objects so they behave as classes. */
  Object.construct = function () { /* NOP */ };
  Object.instanceTraits = [];

  /**
   * Apply a set of traits to an object. Slotted traits may alias named properties, thus for
   * every slotted trait we create two properties: one to hold the actual value, one to hold
   * a getter/setter that reads the actual value. For instance, for the slot trait "7:Age" we
   * generated three properties: "S7" to hold the actual value, and an "Age" getter/setter pair
   * that mutate the "S7" property. The invariant we want to maintain is [obj.S7 === obj.Age].
   *
   * This means that there are two ways to get to any slotted trait, a fast way and a slow way.
   * I guess we should profile and find out which type of access is more common (by slotId or
   * by name).
   */
  runtime.prototype.applyTraits = function applyTraits(obj, traits) {
    function setProperty(name, slotId, value) {
      if (slotId) {
        obj["S" + slotId] = value;
        Object.defineProperty(obj, name, {
          get: function () {
            return obj["S" + slotId];
          },
          set: function (val) {
            return obj["S" + slotId] = val;
          }
        });
      } else {
        obj[name] = value;
      }
    }
    traits.forEach(function (trait) {
      if (trait.isSlot() || trait.isConst()) {
      setProperty(trait.name.getQualifiedName(), trait.slotId, trait.value);
      } else if (trait.isMethod()) {
        var closure = this.createFunction(trait.method, new Scope(null, obj));
        setProperty(trait.name.getQualifiedName(), undefined, closure);
      } else if (trait.isClass()) {
        setProperty(trait.name.getQualifiedName(), trait.slotId, null);
      } else {
        assert(false, trait);
      }
    }.bind(this));
  };

  runtime.prototype.isType = function isType(value, multiname) {
    return true;
  };

  return runtime;
})();

/**
 * Initializes an abc file's runtime and traits, and returns the entryPoint function.
 */
function createEntryPoint(abc, global) {
  assert (!abc.hasOwnProperty("runtime"));
  abc.runtime = new Runtime(abc);
  abc.runtime.applyTraits(global, abc.lastScript.traits);
  return abc.runtime.createFunction(abc.lastScript.entryPoint, null);
}

/**
 * This is the main entry point to the VM. To re-execute an abc file, call [createEntryPoint] once and
 * cache its result for repeated evaluation;
 */
function executeAbc(abc, global) {
  var fn = createEntryPoint(abc, global);
  fn.call(global, null);
}
<commit_msg>Define int/uint types in the global object.<commit_after>function toDouble(x) {
  return Number(x);
}

function toBoolean(x) {
  return Boolean(x);
}

function toUint(x) {
  var obj = x | 0;
  return obj < 0 ? (obj + 4294967296) : obj;
}

function toInt(x) {
  return parseInt(x);
}

function deleteProperty(obj, multiname) {
  // TODO: This is not correct.
  return delete obj[multiname.getQualifiedName()];
}

var globalObject = function () {
  var global = {};
  global.print = global.trace = function (val) {
    console.info(val);
  };
  global.Number = Number;
  global.Boolean = Boolean;
  global.Date = Date;
  global.Array = Array;
  global.Math = Math;
  global.Object = Object;
  global.String = String;
  global.RegExp = RegExp;
  global.Function = Function;
  global.undefined = undefined;
  global.NaN = NaN;
  global.Infinity = Infinity;
  global.JS = (function() { return this || (1,eval)('this'); })();

  function defineReadOnlyProperty(obj, name, value) {
    Object.defineProperty(obj, name,
      { value: value, writable: false, configurable: false, enumerable: false });
  }

  global.int = {};
  defineReadOnlyProperty(global.int, "MIN_VALUE", -0x80000000);
  defineReadOnlyProperty(global.int, "MAX_VALUE", 0x7fffffff);

  global.uint = {};
  defineReadOnlyProperty(global.uint, "MIN_VALUE", 0);
  defineReadOnlyProperty(global.uint, "MAX_VALUE", 0x7fffffff);

  global.parseInt = parseInt;

  global.Capabilities = {
    'playerType': 'AVMPlus'
  };

  global.Namespace = (function() {
    function namespace() {
      this.prefix = arguments.length > 1 ? arguments[0] : undefined;
      this.uri = arguments.length == 1 ? arguments[0] : arguments[1];
    }
    return namespace;
  })();

  global.toString = function () {
    return "[object global]";
  };

  return global;
}();

/**
 * Scopes are used to emulate the scope stack as a linked list of scopes, rather than a stack. Each
 * scope holds a reference to a scope [object] (which may exist on multiple scope chains, thus preventing
 * us from chaining the scope objects together directly).
 *
 * Scope Operations:
 *
 *  push scope: scope = new Scope(scope, object)
 *  pop scope: scope = scope.parent
 *  get global scope: scope.global
 *  get scope object: scope.object
 *
 * Method closures have a [savedScope] property which is bound when the closure is created. Since we use a
 * linked list of scopes rather than a scope stack, we don't need to clone the scope stack, we can bind
 * the closure to the current scope.
 *
 * The "scope stack" for a method always starts off as empty and methods push and pop scopes on their scope
 * stack explicitly. If a property is not found on the current scope stack, it is then looked up
 * in the [savedScope]. To emulate this we actually wrap every generated function in a closure, such as
 *
 *  function fnClosure(scope) {
 *    return function fn() {
 *      ... scope;
 *    };
 *  }
 *
 * When functions are created, we bind the function to the current scope, using fnClosure.bind(null, this)();
 */
var Scope = (function () {
  function scope(parent, object) {
    this.parent = parent;
    this.object = object;
  }

  Object.defineProperty(scope.prototype, "global", {
    get: function () {
      if (this.parent === null) {
        return this;
      } else {
        return this.parent.global;
      }
    }
  });

  scope.prototype.findProperty = function findProperty(multiname, strict) {
    for (var i = 0; i < multiname.namespaceCount(); i++) {
      if (this.object.hasOwnProperty(multiname.getQName(i).getQualifiedName())) {
        return this.object;
      }
    }
    if (this.parent) {
      return this.parent.findProperty(multiname, strict);
    }
    if (strict) {
      unexpected("Cannot find property " + multiname);
    }
    return this.global.object;
  };

  /**
   * Returns the first multiname that binds to a property in the scope chain.
   */
  scope.prototype.resolveMultiname = function(multiname) {
    assert (!multiname.isQName());
    var resolved = resolveMultiname(this.object, multiname);
    if (resolved) {
      return resolved;
    }
    if (this.parent) {
      return this.parent.resolveMultiname(multiname);
    }
    return null;
  };

  return scope;
})();

/**
 * Resolve the [multiname] to a QName in the specified [obj], this is a linear search that uses [hasOwnProperty]
 * with the qualified name.
 */
function resolveMultiname(obj, multiname, checkPrototype) {
  assert (!multiname.isQName(), "We shouldn't resolve already resolved names.");
  obj = Object(obj);
  for (var i = 0; i < multiname.namespaceCount(); i++) {
    var name = multiname.getQName(i);
    if (checkPrototype) {
      if (name.getQualifiedName() in obj) {
        return name;
      }
    } else {
      if (obj.hasOwnProperty(name.getQualifiedName())) {
        return name;
      }
    }
  }
  return null;
}

function getProperty(obj, multiname) {
  if (multiname.isQName()) {
    return obj[multiname.getQualifiedName()];
  } else {
    var resolved = resolveMultiname(obj, multiname, true);
    if (resolved) {
      return obj[resolved.getQualifiedName()];
    }
  }
  return undefined;
}

/**
 * Execution context for a script.
 */
var Runtime = (function () {
  var functionCount = 0;
  function runtime(abc) {
    this.abc = abc;
    this.compiler = new Compiler(abc);
  }

  runtime.prototype.createActivation = function (method) {
    var obj = {};
    this.applyTraits(obj, method.traits);
    return obj;
  };

  runtime.prototype.createFunction = function (method, scope)  {
    /**
     * TODO: This is terrible, we overwrite the default implementation of call/apply because
     * we need to pass the globalObject whenever call/apply is passed null or undefined for the
     * [this] pointer. We could solve this by merging the AS global object with the JS global
     * object, but that may open up another bag of warms.
     */
    function overwriteCallAndApply(fn) {
      fn.apply = function ($this, args) {
        if ($this === null || $this === undefined) {
          $this = globalObject;
        }
        return Function.prototype.apply.apply(fn, [$this, args]);
      };
      /* Temporarily disable this because it prevents the Chrome debugger from stepping into callees.
      fn.call = function ($this) {
        if ($this === null || $this === undefined) {
          $this = globalObject;
        }
        return Function.prototype.apply.apply(fn, [$this, Array.prototype.slice.call(arguments).slice(1)]);
      };
      */
      return fn;
    }

    if (method.compiledMethodClosure) {
      return overwriteCallAndApply(method.compiledMethodClosure.bind(null, scope)());
    }
    method.analysis = new Analysis(method, { massage: true });
    method.analysis.restructureControlFlow();
    var result = this.compiler.compileMethod(method, scope);

    var parameters = method.parameters.map(function (p) {
      return p.name;
    });

    function flatten(array, indent) {
      var str = "";
      array.forEach(function (x) {
        if (x instanceof Indent) {
          str += flatten(x.statements, indent + "  ");
        } else if (x instanceof Array) {
          str += flatten(x, indent);
        } else {
          str += indent + x + "\n";
        }
      });
      return str;
    }

    // TODO: Use function constructurs,
    // method.compiledMethod = new Function(parameters, flatten(result.statements, ""));

    /* Hook to set breakpoints in compiled code. */
    var body = flatten(result.statements, "");
    if (functionCount == 13) {
      body = "stop();" + body;
    }

    // Eval hack to give generated functions proper names so that stack traces are helpful.
    eval("function fnClosure" + functionCount + "(" + SAVED_SCOPE_NAME + ") { return function fn" + functionCount + " (" + parameters.join(", ") + ") { " + body + " }; }");
    method.compiledMethodClosure = eval("fnClosure" + functionCount);

    if (traceLevel.value > 0) {
      /* Unfortunately inner functions are not pretty-printed by the JS engine, so here we recompile the
       * inner function by itself just for pretty printing purposes.
       */
      eval ("function fnSource" + functionCount + " (" + parameters.join(", ") + ") { " + body + " }");
      print('\033[92m' + eval("fnSource" + functionCount) + '\033[0m');
    }

    functionCount ++;
    return overwriteCallAndApply(method.compiledMethodClosure.bind(null, scope)());
  };

  /**
   * ActionScript Classes are modeled as constructor functions (class objects) which hold additional properties:
   *
   * [scope]: a scope object holding the current class object
   *
   * [baseClass]: a reference to the base class object
   *
   * [instanceTraits]: an accumulated set of traits that are to be applied to instances of this class
   *
   * [prototype]: the prototype object of this constructor function  is populated with the set of instance traits,
   *   when instances are of this class are created, their __proto__ is set to this object thus inheriting this
   *   default set of properties.
   *
   * [construct]: a reference to the class object itself, this is used when invoking the constructor with an already
   *   constructed object (i.e. constructsuper)
   *
   * additionally, the class object also has a set of class traits applied to it which are visible via scope lookups.
   */
  runtime.prototype.createClass = function createClass(classInfo, baseClass, scope) {
    scope = new Scope(scope, null);

    var cls = this.createFunction(classInfo.instance.init, scope);
    scope.object = cls;

    cls.scope = scope;
    cls.classInfo = classInfo;
    cls.baseClass = baseClass;

    if (baseClass) {
      cls.instanceTraits = baseClass.instanceTraits.concat(classInfo.instance.traits);
    } else {
      cls.instanceTraits = classInfo.instance.traits;
      assert (cls.instanceTraits);
    }

    cls.prototype = {};
    this.applyTraits(cls.prototype, cls.instanceTraits);
    this.applyTraits(cls, classInfo.traits);

    /* Call the static constructor. */
    this.createFunction(classInfo.init, this.scope).call(cls);
    cls.construct = cls;
    return cls;
  };

  /* Extend builtin Objects so they behave as classes. */
  Object.construct = function () { /* NOP */ };
  Object.instanceTraits = [];

  /**
   * Apply a set of traits to an object. Slotted traits may alias named properties, thus for
   * every slotted trait we create two properties: one to hold the actual value, one to hold
   * a getter/setter that reads the actual value. For instance, for the slot trait "7:Age" we
   * generated three properties: "S7" to hold the actual value, and an "Age" getter/setter pair
   * that mutate the "S7" property. The invariant we want to maintain is [obj.S7 === obj.Age].
   *
   * This means that there are two ways to get to any slotted trait, a fast way and a slow way.
   * I guess we should profile and find out which type of access is more common (by slotId or
   * by name).
   */
  runtime.prototype.applyTraits = function applyTraits(obj, traits) {
    function setProperty(name, slotId, value) {
      if (slotId) {
        obj["S" + slotId] = value;
        Object.defineProperty(obj, name, {
          get: function () {
            return obj["S" + slotId];
          },
          set: function (val) {
            return obj["S" + slotId] = val;
          }
        });
      } else {
        obj[name] = value;
      }
    }
    traits.forEach(function (trait) {
      if (trait.isSlot() || trait.isConst()) {
      setProperty(trait.name.getQualifiedName(), trait.slotId, trait.value);
      } else if (trait.isMethod()) {
        var closure = this.createFunction(trait.method, new Scope(null, obj));
        setProperty(trait.name.getQualifiedName(), undefined, closure);
      } else if (trait.isClass()) {
        setProperty(trait.name.getQualifiedName(), trait.slotId, null);
      } else {
        assert(false, trait);
      }
    }.bind(this));
  };

  runtime.prototype.isType = function isType(value, multiname) {
    return true;
  };

  return runtime;
})();

/**
 * Initializes an abc file's runtime and traits, and returns the entryPoint function.
 */
function createEntryPoint(abc, global) {
  assert (!abc.hasOwnProperty("runtime"));
  abc.runtime = new Runtime(abc);
  abc.runtime.applyTraits(global, abc.lastScript.traits);
  return abc.runtime.createFunction(abc.lastScript.entryPoint, null);
}

/**
 * This is the main entry point to the VM. To re-execute an abc file, call [createEntryPoint] once and
 * cache its result for repeated evaluation;
 */
function executeAbc(abc, global) {
  var fn = createEntryPoint(abc, global);
  fn.call(global, null);
}
<|endoftext|>


<commit_before><commit_msg>fix case<commit_after><|endoftext|>