From 51bd6284d440fb61c4f1eba7cac506a467509b02 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Fri, 26 Aug 2016 05:49:50 +0300 Subject: [PATCH] moved away from local object/actions/features, not yet sure if it's a good move... Signed-off-by: Alex A. Naanou --- ui (gen4)/lib/actions.js | 1408 ------------------------------------- ui (gen4)/lib/features.js | 702 ------------------ ui (gen4)/lib/object.js | 220 ------ ui (gen4)/ui.js | 43 +- 4 files changed, 41 insertions(+), 2332 deletions(-) delete mode 100755 ui (gen4)/lib/actions.js delete mode 100755 ui (gen4)/lib/features.js delete mode 100755 ui (gen4)/lib/object.js diff --git a/ui (gen4)/lib/actions.js b/ui (gen4)/lib/actions.js deleted file mode 100755 index c2afe8c1..00000000 --- a/ui (gen4)/lib/actions.js +++ /dev/null @@ -1,1408 +0,0 @@ -/********************************************************************** -* -* -* -**********************************************************************/ -((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) -(function(require){ var module={} // make module AMD/node compatible... -/*********************************************************************/ - -// XXX -// XXX replace this with ig-features/actions -// XXX - -var args2array = require('lib/util').args2array -var object = require('lib/object') - - - -/*********************************************************************/ -// Actions -// -// Actions are an extension to the JavaScript object model tailored for -// a set of specific tasks. -// -// Goals: -// - provide a unified mechanism to define and manage user API's for -// use in UI-hooks, keyboard mappings, scripting, ... etc. -// - a means to generate configuration UI's -// - a means to generate documentation -// -// -// The main entities: -// -// Action set -// - an object containing a number of actions, -// - optionally, directly or indirectly inherited from MetaActions -// and/or other action sets, -// - the action handlers are bound relative to it (._action_handlers) -// -// Action -// -// + pre + pre + + post + post + -// Action event handler: o-------x o-------x -// v ^ -// Actions o-------x o-------x -// v ^ -// Root Action o---|---x -// -// - a method, created by Action(..), -// - calls all the shadowed/overloaded actions in the inheritance -// chain in sequence implicitly, -// NOTE: there is no way to prevent an action in the chain from -// running, this is by design, i.e. no way to fully shadow. -// - actions that do not shadow anything are called root actions. -// - returns the action set by default (for call chaining), -// - the base/root action can return any value. -// NOTE: if undefined is returned, it will be replaced by the -// action context/action set. -// NOTE: there is no distinction between root and other actions -// other than that root action's return values are not -// ignored. -// - can consist of two parts: the first is called before the -// shadowed action (pre-callback) and the second after (post-callback). -// - post-callback has access to the return value and can modify it -// but not replace it. -// - can be bound to, a-la an event, calling the handlers when it is -// called, -// -// Action (event) handler -// - a function, -// - can be bound to run before and/or after the action itself, -// - is local to an action set it was bound via, -// - when an action is triggered from an action set, all the pre -// handlers in its inheritance chain will be called before the -// respective actions they are bound to and all the post handlers -// are called directly after. -// - pre handlers are passed the same arguments the original actions -// got when it was called. -// - post action handlers will get the root action result as first -// argument succeeded by the action arguments. -// -// -// -// The action system main protocols: -// -// 1) Documentation generation and introspection (MetaActions) -// -// .toString() -// -> code of original action function -// -// .getDoc() -// .getDoc([, ..]) -// -> dict of action-name, doc -// -// .a.getHandlerDocStr() -// -> formated string of action handlers -// -// .actions -// -> list of action names -// -// .length -// -> number of actions -// -// -// 2) Event-like callbacks for actions (MetaActions, Action) -// -// .on('action', function(){ ... }) -// .on('action.post', function(){ ... }) -// -// .on('action.pre', function(){ ... }) -// -// -// 3) A mechanism to define and extend already defined actions -// This replaces / complements the standard JavaScript overloading -// mechanisms (Action, Actions) -// -// // Actions... -// var X = Actions({ -// m: [function(){ console.log('m') }] -// }) -// var O = Actions(X, { -// m: [function(){ -// console.log('pre') -// return function(res){ -// console.log('post') -// } -// }] -// }) -// -// NOTE: what is done here is similar to calling O.__proto__.m.call(..) -// but is implicit, and not dependant on the original containing -// object name/reference ('O'), thus enabling an action to be -// referenced and called from any object and still chain correctly. -// -// -// -// Secondary action protocols: -// -// 1) A mechanism to manually call the pre/post stages of an action -// -// Pre phase... -// .pre() -// .pre(, [, ..]) -// -> -// -// Post phase... -// .post(, ) -// -> -// -// This is internally used to implement the action call as well as the -// chaining callbacks (see below). -// -// All action protocol details apply. -// -// NOTE: there is not reliable way to call the post phase without first -// calling the pre phase due to how the pre phase is defined (i.e. -// pre phase functions can return post phase functions). -// -// -// 2) A mechanism to chain/wrap actions or an action and a function. -// This enables us to call a callback or another action (inner) between -// the root action's (outer) pre and post stages. -// -// Outer action o-------x o-------x -// v ^ -// Inner action/callback o---|---x -// -// A trivial example: -// -// actionSet.someAction.chainApply(actionsSet, -// function(){ -// // this gets run between someAction's pre and post -// // stages... -// }, -// args) -// -// This is intended to implement protocols where a single action is -// intended to act as a hook point (outer) and multiple different -// implementations (inner) within a single action set can be used as -// entry points. -// -// // Protocol root action (outer) definition... -// protocolAction: [function(){}], -// -// // Implementation actions (inner)... -// implementationAction1: [function(){ -// return this.protocolAction.chainApply(this, function(){ -// // ... -// }, ..) -// }] -// -// implementationAction2: [function(){ -// return this.protocolAction.chainApply(this, function(){ -// // ... -// }, ..) -// }] -// -// Now calling any of the 'implementation' actions will execute code -// in the following order: -// 1) pre phase of protocol action (outer) -// 2) implementation action (inner) -// 3) post phase of protocol action (outer) -// -// NOTE: this will not affect to protocol/signature of the outer action -// in any way. -// NOTE: both the inner and outer actions will get passed the same -// arguments. -// NOTE: another use-case is testing/debugging actions. -// NOTE: this is effectively the inside-out of normal action overloading. -// NOTE: there is intentionally no shorthand for this feature, to avoid -// confusion and to discourage the use of this feature unless -// really necessary. -// -// -// 3) .__call__ action / handler -// This action if defined is called for every action called. It behaves -// like any other action but with a fixed signature, it always receives -// the action name as first argument and a list of action arguments as -// the second arguments, and as normal a result on the post phase. -// -// NOTE: it is not necessary to define the actual action, binding to a -// handler will also work. -// NOTE: one should not call actions directly from within a __call__ -// handler as that will result in infinite recursion. -// XXX need a way to prevent this... -// NOTE: one should use this with extreme care as this will introduce -// an overhead on all the actions if not done carefully. -// -// -// -/*********************************************************************/ -// helpers... - -var normalizeTabs = function(str){ - str = str.split(/\n/g) - - // get min number of leading tabs... - var i = str.length == 2 && /^\t/.test(str[1]) ? - str[1].split(/^(\t+)/)[1].length - 1 - : Math.min.apply(null, str - // skip first line... - .slice(1) - // skip empty strings... - .filter(function(l){ return l.trim() != '' }) - // count leading tabs... - .map(function(l){ - return /^\t+/.test(l) ? - l.split(/^(\t+)/)[1].length - : 0})) - - return (str[0] +'\n' - + str - .slice(1) - // trim leading tabs... - .map(function(l){ return l.slice(i) }).join('\n') - // replace tabs... - .replace(/\t/g, ' ')) - // remove leading and trailing whitespace... - .trim() -} - - -var doWithRootAction = -module.doWithRootAction = -function(func){ - return function(){ - var args = args2array(arguments) - var handlers = (this.getHandlerList - || MetaActions.getHandlerList) - .apply(this, args) - - return func.apply(this, [handlers.pop()].concat(args)) - } -} - - - -/*********************************************************************/ - -// Construct an action object... -// -// Action function format: -// -// // pre event code... -// function(..){ -// ... // pre code -// } -// -// // pre/post event code... -// function(..){ -// ... // pre code -// return function(, ..){ -// ... // post code -// } -// } -// -// // same as above but using a deferred instead of a callback... -// function(..){ -// ... // pre code -// return $.Deferred() -// .done(function(, ..){ -// ... // post code -// }) -// } -// -// -// An action is essentially a method with several additional features: -// -// - actions are split into two stages: -// pre: the code of the method is executed before the action -// event is fired -// post: if the action returns a callback function or a deferred -// object it will be executed after the event is fired -// NOTE: the signature if the post stage is the same as the -// action's with the added return value as first argument -// (the rest og the arguments are shifted by 1). -// -// - actions automatically call the shadowed action, the pre stage is -// executed down-up while the post stage is run in reverse order, -// i.e. the pre is going down and the post is going up. -// -// - actions provide an event-like mechanism to register handlers or -// callbacks. These callbacks are local to a specific object and will -// be fired on action event/call starting from the current action -// caller and down the inheritance chain, i.e. all event handlers -// registered from the current object and up to the base action set -// will be fired. -// -// - an action will return the deepest (root) action's return, if that -// return is undefined, then the action set is returned instead. -// -// - action arguments are "threaded" through the action chain down and -// root action return value and arguments are threaded back up the -// action chain. -// -// NOTE: actions once defined do not depend on the inheritance hierarchy, -// other than the .getHandlerList(..) method. If this method is not -// found in the inheritance chain (i.e. the link to MetaActions) -// was severed, then the default will be used: -// MetaActions.getHandlerList(..) -// This makes it possible to redefine the method if needed but -// prevents the system from breaking when an action set gets -// disconnected from MetaActions. This can be useful, for example, -// to remove .on(..) / .off(..) handler functionality. -// XXX is this correct?? -// NOTE: by default an action will return 'this', i.e. the action set -// object the action was called from. -// -// XXX add more metadata/docs: -// .section -// .category -// ... -// XXX might be a good idea to add an option to return the full results... -var Action = -module.Action = -function Action(name, doc, ldoc, func){ - // we got called without a 'new'... - if(this == null || this.constructor !== Action){ - // XXX using something like .apply(.., arguemnts) would be more - // generel but have no time to figure out how to pass it - // to new without the later complaining... - return new Action(name, doc, ldoc, func) - } - - // prevent action overloading... - if(this[name] != null){ - throw 'action "'+name+'" already exists.' - } - - // create the actual instance we will be returning... - //var meth = function(){ - // return meth.chainApply(this, null, arguments) } - var meth = function(){ - return meth.chainApply(this, null, arguments) } - meth.__proto__ = this.__proto__ - - // populate the action attributes... - //meth.name = name - Object.defineProperty(meth, 'name', { - value: name, - }) - meth.doc = doc - meth.long_doc = ldoc - - meth.func = func - - // make introspection be a bit better... - meth.toString = func.toString.bind(func) - - return meth -} -// this will make action instances behave like real functions... -Action.prototype.__proto__ = Function - -// The pre/post stage runners... -// -// .pre(context, args) -// -> data -// -// .post(context, data) -// -> result -// -// -// NOTE: All the defaults should be handled by the pre stage, post will -// process data assuming that it is correct. -// -// XXX revise the structure.... -// ...is it a better idea to define action methods in an object -// and assign that??? -Action.prototype.pre = function(context, args){ - args = args || [] - - var res = context - var outer = this.name - - // get the handler list... - var getHandlers = context.getHandlers || MetaActions.getHandlers - var handlers = getHandlers.call(context, outer) - - // special case: see if we need to handle the call without handlers... - var preActionHandler = context.preActionHandler || MetaActions.preActionHandler - if(preActionHandler){ - // XXX signature needs work... - var res = preActionHandler.call(context, outer, handlers, args) - if(res !== undefined){ - return res - } - } - - var call_wrapper = outer != '__call__' ? - getHandlers.call(context, '__call__') - : [] - - // wrapper handlers: pre phase... - call_wrapper = call_wrapper - .map(function(a){ - if(a.pre){ - res = a.pre.call(context, outer, args) - - // if a handler returns a function or a deferred, - // register is as a post handler... - if(res - && res !== context - && (res instanceof Function - || res.resolve instanceof Function)){ - a.post = res - } - } - return a - }) - - // handlers: pre phase... - handlers - // NOTE: current action will get included and called by the code - // above and below, so no need to explicitly call func... - // NOTE: pre handlers are called FIFO, i.e. the last defined first... - .map(function(a){ - if(a.pre){ - res = a.pre.apply(context, args) - - // if a handler returns a function or a deferred, - // register is as a post handler... - if(res - && res !== context - && (res instanceof Function - || res.resolve instanceof Function)){ - a.post = res - - // reset the result... - res = context - } - } - return a - }) - - // return context if nothing specific is returned... - res = res === undefined ? context : res - - return { - arguments: args, - - wrapper: call_wrapper, - handlers: handlers, - - result: res, - } -} -Action.prototype.post = function(context, data){ - var res = data.result - - var args = data.arguments || [] - // the post handlers get the result as the first argument... - args.splice(0, 0, res) - - var outer = this.name - - // handlers: post phase... - data.handlers && data.handlers - // NOTE: post handlers are called LIFO -- last defined last... - .reverse() - .forEach(function(a){ - a.post - && (a.post.resolve ? - a.post.resolve.apply(a.post, args) - : a.post.apply(context, args)) - }) - - // wrapper handlers: post phase... - data.wrapper && data.wrapper - // NOTE: post handlers are called LIFO -- last defined last... - .reverse() - .forEach(function(a){ - a.post - && (a.post.resolve ? - a.post.resolve.apply(a.post, res, outer, args.slice(1)) - : a.post.call(context, res, outer, args.slice(1))) - }) - - return res -} - -// Chaining... -Action.prototype.chainApply = function(context, inner, args){ - args = [].slice.call(args || []) - var res = context - var outer = this.name - - var data = this.pre(context, args) - - // call the inner action/function if preset.... - if(inner){ - //res = inner instanceof Function ? - inner instanceof Function ? - inner.call(context, args) - : inner instanceof Array && inner.length > 0 ? - context[inner.pop()].chainCall(context, inner, args) - : typeof(inner) == typeof('str') ? - context[inner].chainCall(context, null, args) - : null - } - - return this.post(context, data) -} -Action.prototype.chainCall = function(context, inner){ - return this.chainApply(context, inner, args2array(arguments).slice(2)) -} - - - -//--------------------------------------------------------------------- - -// A base action-set object... -// -// This will define a set of action-set specific methods and helpers. -// -// XXX .off(...) needs more work... -// XXX need a mechanism to publish specific attrs... -var MetaActions = -module.MetaActions = { - // List actions... - // - get actions(){ - var res = [] - for(var k in this){ - // avoid recursion, skip props... - var cur = this - var prop = Object.getOwnPropertyDescriptor(cur, k) - while(!prop && cur.__proto__ != null){ - var cur = cur.__proto__ - var prop = Object.getOwnPropertyDescriptor(cur, k) - } - if(prop.get != null){ - continue - } - //if(k == 'actions' || k == 'length'){ - // continue - //} - // get only actions... - if(this[k] instanceof Action){ - res.push(k) - } - } - return res - }, - - // Number of defined actions... - // - get length(){ - return this.actions.length - }, - - // Get action documentation... - // - getDoc: function(actions){ - var res = {} - var that = this - actions = actions == null ? this.actions - : arguments.length > 1 ? args2array(arguments) - : typeof(actions) == typeof('str') ? [actions] - : actions - - // get the first defined set of docs in the inheritance chain... - actions.forEach(function(n){ - var cur = that - res[n] = [] - // go up the proto chain... - while(cur.__proto__ != null){ - if(cur[n] != null && cur[n].doc != null){ - res[n] = [ cur[n].doc, cur[n].long_doc, cur[n].name ] - break - } - cur = cur.__proto__ - } - }) - return res - }, - - getPath: function(actions){ - var res = {} - var that = this - actions = actions == null ? this.actions - : arguments.length > 1 ? args2array(arguments) - : typeof(actions) == typeof('str') ? [actions] - : actions - - // get the first defined set of docs in the inheritance chain... - actions.forEach(function(n){ - var cur = that - // go up the proto chain... - while(cur.__proto__ != null){ - if(cur[n] != null && cur[n].doc != null){ - var doc = cur[n].doc - var long_doc = cur[n].long_doc - break - } - cur = cur.__proto__ - } - - res[(doc && doc.replace(/[\\\/]$/, '/'+n)) || n] = [n, doc, long_doc] - }) - return res - }, - - - // Get action handlers from the inheritance chain... - // - // NOTE: this collects both the event handlers (in order of hierarchy, - // then order of definition) and actions (in order of hierarchy) - // NOTE: this is the correct order for 'pre' calling, but is the - // reverse of how the 'post' handlers must be called. - // - // For more docs on handler sequencing and definition see: .on(..) - getHandlerList: function(name){ - var handlers = [] - var cur = this - while(cur.__proto__ != null){ - // get action "event" handlers... - if(cur.hasOwnProperty('_action_handlers') - && name in cur._action_handlers){ - handlers.splice.apply(handlers, - [handlers.length, 0].concat(cur._action_handlers[name])) - } - - // get the overloading action... - // NOTE: this will get all the handlers including the root - // and the current handlers... - // NOTE: this will ignore "shadows" that are not actions... - if(cur.hasOwnProperty(name) && cur[name] instanceof Action){ - handlers.push(cur[name].func) - } - - cur = cur.__proto__ - } - return handlers - }, - - // Get structured action handler definitions... - // - // Format: - // [ - // { - // // NOTE: only one handler per level can be present, either - // // .pre or .post, this does not mean that one can - // // not define both, just that they are stored separately - // pre|post: , - // }, - // ... - // ] - // - // XXX need to get parent action or definition context for each level... - // XXX is this simpler to use than the original .getHandlerList(..) - // XXX rename this.... - getHandlers: function(name){ - return (this.getHandlerList || MetaActions.getHandlerList).call(this, name) - .map(function(a){ - var res = { - // action doc... - // XXX - } - - if(!a.post_handler){ - res.pre = a - - } else { - res.post = a.post_handler - } - - return res - }) - }, - - // Handler for cases when we need to avoid the pre/post handlers... - // - // Returns: - // - undefined - handle the action normally. - // - object - bypass action handlers. - // - // NOTE: the object result must be compatible with Action.pre(..) - // return value... - // NOTE: this is mostly a stub, here for documentation reasons... - //preActionHandler: doWithRootAction( - // function(action, name, handlers, args){ return null }), - - - // Register an action callback... - // - // Register a post action callback - // .on('action', [, ]) - // .on('action.post', [, ]) - // -> - // - // Register a pre action callback - // .on('action.pre', [, ]) - // -> - // - // Modes: - // 'pre' - the handler is fired before the action is triggered, - // and if the handler returns a deferred or a function - // then that will get resolved, called resp. after - // the action is done. - // 'post' - the handler is fired after the action is finished. - // this is the default. - // - // Handler Arguments: - // 'pre' - the handler will get the same arguments as the main - // action when called. - // 'post' - the handler will get the action return value followed - // by action arguments. - // - // The optional tag marks the handler to enable group removal via - // .off(..) - // - // NOTE: 'post' mode is the default. - // - // XXX should we have multiple tags per handler??? - on: function(actions, b, c){ - var handler = typeof(c) == 'function' ? c : b - var tag = typeof(c) == 'function' ? b : c - - // XXX make this split by whitespace... - actions = typeof(actions) == 'string' ? actions.split(/ +/) : actions - - var that = this - actions.forEach(function(action){ - // prepare the handler... - var mode = action.split('.') - action = mode[0] - mode = mode[1] - - // keep the original handler for future use... - var a_handler = handler - - // a post handler (default)... - if(mode == null || mode == 'post'){ - var old_handler = a_handler - a_handler = function(){ return old_handler } - a_handler.post_handler = old_handler - // NOTE: this is set so as to identify the handler - // for removal via. .off(..) - a_handler.orig_handler = old_handler.orig_handler || old_handler - - // not pre mode... - } else if(mode != 'pre') { - // XXX - throw 'Unknown action mode: '+action+'.'+mode - } - - a_handler.tag = tag - - // register handlers locally only... - if(!that.hasOwnProperty('_action_handlers')){ - that._action_handlers = {} - } - if(!(action in that._action_handlers)){ - that._action_handlers[action] = [] - } - // register a handler only once... - if(that._action_handlers[action].indexOf(a_handler) < 0){ - // NOTE: last registered is first... - that._action_handlers[action].splice(0, 0, a_handler) - } - }) - - return this - }, - - // Remove an action callback... - // - // Remove all handlers from action: - // .off('action') - // .off('action', '*') - // .off('action', 'all') - // -> - // - // Remove specific handler from action: - // .off('action', ) - // -> - // - // Remove handlers from action by tag: - // .off('action', ) - // -> - // - // NOTE: the handler passed to .off(..) for removal must be the same - // as the handler passed to .on(..) / .one(..) - off: function(actions, handler){ - if(this.hasOwnProperty('_action_handlers')){ - - actions = actions == '*' ? Object.keys(this._action_handlers) - : typeof(actions) == 'string' ? actions.split(' ') - : actions - - var that = this - actions.forEach(function(action){ - var mode = action.split('.') - action = mode[0] - mode = mode[1] - - // get the handlers... - var h = that._action_handlers[action] || [] - - // remove explicit handler... - if(typeof(handler) == 'function'){ - var i = -1 - if(mode == null || mode == 'post'){ - // XXX find via e.orig_handler == handler && e.mode == 'post' - h.forEach(function(e, j){ - // NOTE: we will only get the first match... - if(e.orig_handler === handler && i == -1){ - i = j - } - }) - - } else if(mode == 'pre'){ - i = h.indexOf(handler) - } - - // NOTE: unknown modes are skipped... - if(i >= 0){ - h.splice(i, 1) - } - - // remove all handlers... - } else if(handler == null || handler == 'all' || handler == '*'){ - h.splice(0, h.length) - - // remove handlers by tag... - } else { - // filter out everything that mathches a tag in-place... - h.splice.apply(h, - [0, h.length] - .concat(h.filter(function(e){ - return e.tag != handler }))) - } - }) - } - - return this - }, - - // Register an action callback that will only fire once per event... - // - // This is signature compatible with .on(..) - one: function(actions, b, c){ - var _handler = typeof(c) == 'function' ? c : b - var tag = typeof(c) == 'function' ? b : c - - actions = typeof(actions) == 'string' ? actions.split(' *') : actions - - var that = this - actions.forEach(function(action){ - // NOTE: we are using both 'that' below and 'this', so as - // to separate the call context and the bind context, - // .off(..) must be called at the bind context while - // the actual action is called from the call context - // NOTE: we are not using the closure _handler below to - // keep the code introspectable, and direct the user - // to the original function. - var handler = function(){ - // remove handler... - that.off(action, handler.orig_handler) - - // call the actual supplied handler function... - return handler.orig_handler.apply(this, arguments) - } - handler.orig_handler = _handler - that.on(action, tag, handler) - }) - - return this - }, - - // Apply/call a function/action "inside" an action... - // - // .chainApply(outer, inner) - // .chainApply(outer, inner, arguments) - // -> result - // - // .chainCall(outer, inner) - // .chainCall(outer, inner, ..) - // -> result - // - // - // The inner action call is completely nested as base of the outer - // action. - // - // Outer action o-------x o-------x - // v ^ - // Inner action o---|---x - // - // The given arguments are passed as-is to both the outer and inner - // actions. - // The base inner action return value is passed to the outer action - // .post handlers. - // - // NOTE: these call the action's .chainApply(..) and .chainCall(..) - // methods, thus is not compatible with non-action methods... - // NOTE: .chianCall('action', ..) is equivalent to .action.chianCall(..) - chainApply: function(outer, inner, args){ - return this[outer].chainApply(this, inner, args) }, - chainCall: function(outer, inner){ - return this[outer].chainApply(this, inner, args2array(arguments).slice(2)) }, - - // Get mixin object in inheritance chain... - // - // NOTE: if pre is true this will return the chain item before the - // mixin, this is useful, for example, to remove mixins, see - // .mixout(..) for an example... - getMixin: function(from, pre){ - var cur = this - var proto = this.__proto__ - while(proto != null){ - // we have a hit... - if(proto.hasOwnProperty('__mixin_source') - && proto.__mixin_source === from){ - return pre ? cur : proto - } - // go to next item in chain... - cur = proto - proto = cur.__proto__ - } - return null - }, - - // Mixin a set of actions into this... - // - // NOTE: if 'all' is set them mixin all the actions available, - // otherwise only mixin local actions... - // NOTE: this will override existing own attributes. - inlineMixin: function(from, all, descriptors, all_attr_types){ - // defaults... - descriptors = descriptors || true - all_attr_types = all_attr_types || false - - if(all){ - var keys = [] - for(var k in from){ - keys.push(k) - } - } else { - var keys = Object.keys(from) - } - - var that = this - keys.forEach(function(k){ - /* - // XXX is this the right way to go??? - // check if we are not overwriting anything... - if(that.hasOwnProperty(k)){ - console.warn('WARNING:', that,'already has attribute', k, '- skipping...') - return - } - */ - - // properties.... - var prop = Object.getOwnPropertyDescriptor(from, k) - if(descriptors && prop.get != null){ - // NOTE: so as to be able to delete this on mixout... - prop.configurable = true - Object.defineProperty(that, k, prop) - - - // actions and other attributes... - } else { - var attr = from[k] - if(all_attr_types || attr instanceof Action){ - that[k] = attr - } - } - }) - - return this - }, - - // Same as .inlineMixin(..) but isolates a mixin in a seporate object - // in the inheritance chain... - // - mixin: function(from, all, descriptors, all_attr_types){ - var proto = Object.create(this.__proto__) - - // mixinto an empty object - proto.inlineMixin(from, all, descriptors, all_attr_types) - - // mark the mixin for simpler removal... - proto.__mixin_source = from - - this.__proto__ = proto - - return this - }, - - // Mixin a set of local actions into an object... - // - // XXX this will not work on non-actions... - mixinTo: function(to, all, descriptors, all_attr_types){ - return this.mixin.call(to, this, all, descriptors, all_attr_types) - }, - - - // Remove mixed in actions from this... - // - // NOTE: this will only remove local actions, inherited actions will - // not be affected... - // NOTE: this will not affect event handlers, they should be removed - // manually if needed... - inlineMixout: function(from, all, descriptors, all_attr_types){ - // defaults... - descriptors = descriptors || true - all_attr_types = all_attr_types || false - - if(all){ - var keys = [] - for(var k in from){ - keys.push(k) - } - } else { - var keys = Object.keys(from) - } - - var locals = Object.keys(this) - var that = this - keys.forEach(function(k){ - var prop = Object.getOwnPropertyDescriptor(from, k) - - // descriptor... - if(descriptors && prop.get != null){ - if(prop.get === Object.getOwnPropertyDescriptor(that, k).get){ - delete that[k] - } - - // actions and other attrs... - } else { - var attr = from[k] - if((all_attr_types || attr instanceof Action) - // remove only local attrs... - && locals.indexOf(k) >= 0){ - delete that[k] - } - } - }) - - return this - }, - - // This is similare in effect but different in mechanics to .inlineMixout(..) - // - // This will find and remove a mixin object from the inheritance chian. - // - // NOTE: this will remove only the first occurance of a mixin. - mixout: function(from){ - var o = this.getMixin(from, true) - - // pop the mixin off the chain... - if(o != null){ - o.__proto__ = o.__proto__.__proto__ - } - - return this - }, - - // Remove a set of local mixed in actions from object... - // - mixoutFrom: function(to, all, descriptors, all_attr_types){ - return this.mixout.call(to, this, all, descriptors, all_attr_types) - }, - - // Create a child object... - // - // NOTE: this will create a .config in the instance that inherits from - // this.config... - // NOTE: this will not copy/clone any data. - // - // XXX is this correct??? - // XXX should this be an action??? - clone: function(full){ - var o = Object.create(this) - if(this.config){ - if(full){ - o.config = JSON.parse(JSON.stringify(this.config)) - } else { - o.config = Object.create(this.config) - } - } - return o - }, - - // doc generators... - // - // XXX would be nice to make these prop of the action itself but I - // do not see a way to do this properly yet -- we can't get to - // the action context from the action dynamically... - getHandlerDocStr: function(name){ - var lst = this.getHandlers(name) - var str = '' - - var handler = function(p){ - if(lst.length == 0){ - //str += p + '---' - return - } - - // indicate root action... - p = lst.length == 1 ? p+'| ' : p+' ' - - var cur = lst.shift() - - if(cur.pre){ - str += p - + normalizeTabs(cur.pre.toString()).replace(/\n/g, p) - + p - } - - handler(p + ' |') - - str += p - - if(cur.post){ - str += p + p - + normalizeTabs(cur.post.toString()).replace(/\n/g, p) - } - } - - handler('\n|') - - return str - }, - getHandlerDocHTML: function(name){ - var lst = this.getHandlers(name) - var res = $('
') - - var handler = function(p){ - if(lst.length == 0){ - return - } - - var cur = lst.shift() - p = $('
') - .appendTo(p) - - if(cur.pre){ - p.append($('
').html(
-					normalizeTabs(cur.pre.toString())
-						.replace(/return/g, 'return')))
-			}
-
-			handler(p)
-
-			if(cur.post){
-				p.append($('
').html(
-					normalizeTabs(cur.post.toString())))
-			}
-		}
-
-		handler(res)
-
-		return res
-	},
-
-
-	// This will create a .config in instances...
-	// NOTE: this makes Actions compatible with lib/object.js...
-	__init__: function(){
-		if(this.__proto__.config && !Object.hasOwnProperty(this, 'config')){
-			this.config = Object.create(this.__proto__.config)
-		}
-	},
-}
-
-
-var ActionSet =
-module.ActionSet =
-object.makeConstructor('ActionSet', MetaActions)
-
-
-
-// An action set...
-//
-//	Actions()
-//	Actions(, )
-//		-> actions
-//
-// This will pre-process an object to setup the action mechanics.
-//
-// If the 'this and prototype both contain a .config attribute then this
-// will make set .config.__proto__ = .config 
-//
-//
-// The action format:
-// 	{
-// 		// full format...
-// 		 : [
-// 			,
-// 			,
-// 			
-// 		],
-//
-// 		// short doc only...
-// 		 : [
-// 			,
-// 			
-// 		],
-//
-// 		// only the code...
-// 		 : [
-// 			
-// 		],
-// 		...
-// 	}
-//
-//
-// NOTE: the action function is always last.
-// NOTE: if  is not given, MetaActions will be used as default.
-//
-// For more documentation see: Action(..).
-//
-// XXX add doc, ldoc, tags and save them to each action...
-// XXX is .config processing correct here???
-var Actions =
-module.Actions =
-function Actions(a, b){
-	var obj = b == null ? a : b
-	var proto = b == null ? b : a
-	obj = obj || new ActionSet()
-
-	// NOTE: this is intentionally done only for own attributes...
-	Object.keys(obj).forEach(function(k){
-		// NOTE: we are not getting the attrs directly (vars = obj[k])
-		// 		as that will trigger the getters on an object that is
-		// 		not in a consistent state...
-		// NOTE: this will skip all the getters and setters, they will 
-		// 		be included as-is...
-		var arg = Object.getOwnPropertyDescriptor(obj, k).value
-
-		// skip non-arrays...
-		if(arg == null 
-				|| arg.constructor !== Array 
-				// and arrays the last element of which is not a function...
-				|| !(arg[arg.length-1] instanceof Function)){
-			return
-		}
-
-		var func = arg.pop()
-
-		// create a new action...
-		obj[k] = new Action(k, arg[0], arg[1], func)
-	})
-
-	if(proto != null){
-		obj.__proto__ = proto
-
-		// XXX is this the right way to go???
-		if(obj.config != null && proto.config != null){
-			obj.config.__proto__ = proto.config
-		}
-	}
-
-	return obj
-}
-
-
-
-/*********************************************************************/
-
-var test =
-module.test =
-function test(){
-	// NOTE: this is needed only to add action methods to TestActions...
-	var BaseActions = new ActionSet()
-
-	var TestActions = 
-	module.TestActions = 
-	Actions(BaseActions, {
-		testActionGen1: ['baisc test action...',
-			'some extra info',
-			function(){
-				console.log('  test 1!')
-				return function(){
-					console.log('  test 2!')
-				}
-			}],
-
-		testActionGen2: ['baisc 2\'nd gen test action...',
-			// no extra info...
-			function(){
-				console.log('  test gen 2!')
-				this.testActionGen1()
-			}],
-	})
-
-	var TestActions2 = 
-	module.TestActions2 = 
-	Actions(TestActions, {
-		// NOTE: this looks like an action and feels like an action but 
-		// 		actually this is a callback as an action with this name 
-		// 		already exists...
-		testActionGen1: [
-			function(){
-				console.log('  pre callback!')
-				return function(){
-					console.log('  post callback!')
-				}
-			}],
-
-		testAction2: ['this is an action',
-			function(){
-				console.log('testAction2 args:', arguments)
-			}],
-
-	})
-
-	// XXX the main question here is that there is no way to know if a 
-	// 		particular action is going to be a root action or an action
-	// 		callback because we do not know if the action in the parent 
-	// 		will be available at mix time or not, and the two models 
-	// 		are different...
-	// 		XXX one way to do this is to make all code a callback and 
-	// 			just use the root as an event trigger...
-	//
-	// 			...but this effectively means we are implementing 
-	// 			inheritance ourselves as the traditional name resolution
-	// 			will no longer be used, and as in the case we implement
-	// 			MRO why not go the whole way and implement multiple 
-	// 			inheritance in the first place...
-	//
-	// 			...let's try and avoid this...
-	/*
-	var TestActionMixin =
-	module.TestActionMixin = 
-	ActionMixin({
-		// XXX
-	})
-	*/
-
-
-	console.log('TestActions.testActionGen1()')
-	TestActions.testActionGen1()
-	console.log('TestActions.testActionGen2()')
-	TestActions.testActionGen2()
-
-		
-	// both of these should cet a callback...
-	console.log('TestActions2.testActionGen1()')
-	TestActions2.testActionGen1()
-	console.log('TestActions2.testActionGen2()')
-	TestActions2.testActionGen2()
-
-	// and an event-like handler...
-	TestActions2.on('testActionGen1.post', 
-			function(){ console.log('  post handler! (first defined)') })
-	TestActions2.on('testActionGen1', 
-			function(){ console.log('  post handler! (last defined)') })
-
-	console.log('TestActions2.testActionGen1()')
-	TestActions2.testActionGen1()
-
-	TestActions2.on('testActionGen2.pre', 
-			function(){ console.log('  pre handler! (first defined)') })
-	TestActions2.on('testActionGen2.pre', 
-			function(){ console.log('  pre handler! (last defined)') })
-
-	console.log('TestActions2.testActionGen2()')
-	TestActions2.testActionGen2()
-}
-
-
-
-/**********************************************************************
-* vim:set ts=4 sw=4 :                                                */
-return module })
diff --git a/ui (gen4)/lib/features.js b/ui (gen4)/lib/features.js
deleted file mode 100755
index b9fa94a1..00000000
--- a/ui (gen4)/lib/features.js	
+++ /dev/null
@@ -1,702 +0,0 @@
-/**********************************************************************
-* 
-*
-*
-**********************************************************************/
-((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
-(function(require){ var module={} // make module AMD/node compatible...
-/*********************************************************************/
-
-// XXX
-// XXX replace this with ig-features
-// XXX
-
-var args2array = require('lib/util').args2array
-
-var object = require('lib/object')
-var actions = module.actions = require('lib/actions')
-
-
-
-/*********************************************************************/
-//
-// Feature attributes:
-// 	.tag			- feature tag (string)
-// 					  this is used to identify the feature, its event handlers
-// 					  and DOM elements.
-//
-// 	.title			- feature name (string | null)
-// 	.doc			- feature description (string | null)
-//
-// 	.priority		- feature priority
-// 					  can be:
-// 					  	- 'high' (99) | 'medium' (0) | 'low' (-99)
-// 					  	- number
-// 					  	- null (0, default)
-// 					  features with higher priority will be setup first,
-// 					  features with the same priority will be run in order of
-// 					  occurrence.
-// 	.suggested		- list of optional suggested features, these are not 
-// 					  required but setup if available.
-// 					  This is useful for defining meta features but without
-// 					  making each sub-feature a strict dependency.
-// 	.depends		- feature dependencies -- tags of features that must setup
-// 					  before the feature (list | null)
-// 	.exclusive		- feature exclusivity tags (list | null)
-// 					  an exclusivity group enforces that only one feature in
-// 					  it will be run, i.e. the first / highest priority.
-//
-// 	.actions		- action object containing feature actions (ActionSet | null)
-// 					  this will be mixed into the base object on .setup()
-// 					  and mixed out on .remove()
-// 	.config			- feature configuration, will be merged with base 
-// 					  object's .config
-// 					  NOTE: the final .config is an empty object with
-// 					  		.__proto__ set to the merged configuration
-// 					  		data...
-// 	.handlers		- feature event handlers (list | null)
-// 
-//
-//
-// .handlers format:
-// 	[
-// 		[ ,  ],
-// 		...
-// 	]
-//
-// NOTE: both  and  must be compatible with
-// 		Action.on(..)
-//
-//
-// Feature applicability:
-// 	If feature.isApplicable(..) returns false then the feature will not be
-// 	considered on setup...
-//
-//
-// XXX this could install the handlers in two locations:
-// 		- mixin if available...
-// 		- base object (currently implemented)
-// 		should the first be done?
-var FeatureProto =
-module.FeatureProto = {
-	tag: null,
-
-	isApplicable: function(actions){
-		return true
-	},
-
-	getPriority: function(){
-		var res = this.priority || 0
-		return res == 'high' ? 99
-			: res == 'low' ? -99
-			: res == 'medium' ? 0
-			: res
-	},
-
-	setup: function(actions){
-		var that = this
-
-		// mixin actions...
-		if(this.actions != null){
-			actions.mixin(this.actions)
-		}
-
-		// install handlers...
-		if(this.handlers != null){
-			this.handlers.forEach(function(h){
-				actions.on(h[0], that.tag, h[1])
-			})
-		}
-
-		// merge config...
-		// NOTE: this will merge the actual config in .config.__proto__
-		// 		keeping the .config clean for the user to lay with...
-		if(this.config != null 
-				|| (this.actions != null 
-					&& this.actions.config != null)){
-			var config = this.config = this.config || this.actions.config
-
-			if(actions.config == null){
-				actions.config = Object.create({})
-			}
-			Object.keys(config).forEach(function(n){
-				// NOTE: this will overwrite existing values...
-				actions.config.__proto__[n] = config[n]
-			})
-		}
-
-		// custom setup...
-		// XXX is this the correct way???
-		if(this.hasOwnProperty('setup') && this.setup !== FeatureProto.setup){
-			this.setup(actions)
-		}
-
-		return this
-	},
-	remove: function(actions){
-		if(this.actions != null){
-			actions.mixout(this.actions)
-		}
-
-		if(this.handlers != null){
-			actions.off('*', this.tag)
-		}
-
-		if(this.hasOwnProperty('remove') && this.setup !== FeatureProto.remove){
-			this.remove(actions)
-		}
-
-		// remove feature DOM elements...
-		actions.ribbons.viewer.find('.' + this.tag).remove()
-
-		return this
-	},
-}
-
-
-// XXX is hard-coded default feature-set a good way to go???
-//
-// 	Feature(obj)
-// 		-> feature
-//
-// 	Feature(feature-set, obj)
-// 		-> feature
-//
-// 	Feature(tag, obj)
-// 		-> feature
-//
-//
-// 	Feature(tag, actions)
-// 		-> feature
-//
-// 	Feature(feature-set, tag, actions)
-// 		-> feature
-//
-var Feature =
-module.Feature =
-function Feature(feature_set, tag, obj){
-	if(arguments.length == 2){
-		// Feature(, )
-		if(typeof(feature_set) == typeof('str')){
-			obj = tag
-			tag = feature_set
-			feature_set = Features
-
-		// Feature(, )
-		} else {
-			obj = tag
-			tag = null
-		}
-
-	// Feature()
-	} else if(arguments.length == 1){
-		obj = feature_set
-		feature_set = Features
-	}
-
-	if(tag != null && obj.tag != null && obj.tag != tag){
-		throw 'Error: tag and obj.tag mismatch, either use one or both must match.'
-	}
-
-	// action...
-	if(obj instanceof actions.Action){
-		if(tag == null){
-			throw 'Error: need a tag to make a feature out of an action'
-		}
-		var f = {
-			tag: tag,
-			actions: obj,
-		}
-		obj = f
-
-	// meta-feature...
-	} else if(obj.constructor === Array){
-		if(tag == null){
-			throw 'Error: need a tag to make a meta-feature'
-		}
-		var f = {
-			tag: tag,
-			suggested: obj,
-		}
-		obj = f
-
-	// feature...
-	} else {
-		obj.__proto__ = FeatureProto
-	}
-
-	if(feature_set){
-		feature_set[obj.tag] = obj
-	}
-
-	return obj
-}
-Feature.prototype = FeatureProto
-Feature.prototype.constructor = Feature
-
-
-var FeatureSetProto = {
-	__feature__: Feature,
-	__actions__: actions.Actions,
-
-	// if true, .setup(..) will report things it's doing... 
-	__verbose__: null,
-
-	// List of registered features...
-	get features(){
-		var that = this
-		return Object.keys(this)
-			.filter(function(e){ 
-				return e != 'features' 
-					&& that[e] instanceof Feature }) 
-	},
-
-	// Build list of features...
-	//
-	//	Build list of all features for an empty object...
-	//	.buildFeatureList()
-	//	.buildFeatureList({})
-	//	.buildFeatureList({}, '*')
-	//		-> data
-	//
-	//	Build a list of features for a specific root feature and object...
-	//	.buildFeatureList(object, feature)
-	//		-> data
-	//
-	//	Build a list of features for a specific set of root features and object...
-	//	.buildFeatureList(object, [feature, ..])
-	//		-> data
-	//		NOTE: to disable a feature and all of it's dependants prefix
-	//			it's tag with '-' in the list.
-	//			e.g. including 'some-feature' will include the feature
-	//			and its dependants while '-some-feature' will remove
-	//			it and it's dependants.
-	//
-	//
-	// This will build from user input a loadable list of features taking 
-	// into account feature dependencies, priorities and suggestions.
-	//
-	// Roughly this is done in this order starting with the given features:
-	// 	- include all dependencies (recursively)
-	// 	- include all suggested features (recursively)
-	// 	- sort features by priority
-	// 	- sort features by dependency
-	// 	- check for feature applicability
-	// 	- remove non-applicable features and all dependants (recursively)
-	// 	- remove disabled features and all dependants (recursively)
-	// 	- check and resolve exclusivity conflicts (XXX needs revision)
-	// 	- check for missing features and dependencies
-	//
-	//
-	// Return format:
-	// 	{
-	// 		// list of input features...
-	// 		input: [ .. ],
-	//
-	//		// features in correct load order...
-	//		features: [ .. ],
-	//
-	//		// features disabled explicitly and their dependants...
-	//		disabled: [ .. ],
-	//		// unapplicable features and their dependants...
-	//		unapplicable: [ .. ],
-	//
-	//		// features removed due to exclusivity conflict...
-	//		excluded: [ .. ],
-	//
-	//		missing: {
-	//			// features explicitly given by user but missing...
-	//			USER: [ .. ],
-	//			// missing  dependencies...
-	//			: [ .. ],
-	//			...
-	//		},
-	//		conflicts: {
-	//			XXX
-	//		},
-	// 	}
-	//
-	//
-	// NOTE: obj (action set) here is used only for applicability testing...
-	// NOTE: some feature applicability checks (.isApplicable(..)) may 
-	// 		require a real action set, thus for correct operation one 
-	// 		should be provided.
-	// NOTE: all feature sorting is done maintaining relative feature order
-	// 		when possible...
-	// NOTE: meta-features are not included in the list as they do not 
-	// 		need to be setup.
-	// 		...this is because they are not Feature objects.
-	//
-	// XXX should meta-features be MetaFeature objects???
-	// XXX not sure about handling excluded features (see inside)...
-	// XXX add dependency loops to .conflicts...
-	// XXX might be a good idea to check dependency loops on feature 
-	// 		construction, too... (???)
-	buildFeatureList: function(obj, lst){
-		var that = this
-		obj = obj || {}
-
-		lst = (lst == null || lst == '*') ? this.features : lst
-		lst = lst.constructor !== Array ? [lst] : lst
-
-		var input = lst.slice()
-		var disabled = [] 
-		var excluded = []
-		var unapplicable = []
-		var missing = {}
-		var conflicts = {}
-
-
-		// reverse dependency cache... 
-		var dependants = {}
-
-		// build dependency list...
-		var _buildDepList = function(n, seen){
-			seen = seen || []
-			return seen.indexOf(n) >= 0 ? []
-				: seen.push(n) && dependants[n] ? []
-					.concat.apply(
-						dependants[n], 
-						dependants[n]
-							.map(function(n){ return _buildDepList(n, seen) }))
-				: []
-		}
-
-
-		// missing stage 1: check if all user included features exist...
-		// NOTE: we'll ignore missing disabled features too...
-		lst.forEach(function(n){
-			if(!that[n] && n[0] != '-'){
-				var m = missing['USER'] = missing['USER'] || []
-				m.push(n)
-			}
-		})
-
-		// include all dependencies...
-		//
-		// NOTE: this should never fall into an infinite loop as we do 
-		// 		not include feature already seen...
-		// 		...unless there is an infinite number of features, but 
-		// 		I'll try to avoid that big a feature creep.
-		// XXX should we check for dependency loops here???
-		// 		...this would have been simple if this was a recursion
-		// 		(just check if cur is in path), but here it is not 
-		// 		trivial...
-		for(var i=0; i < lst.length; i++){
-			var k = lst[i]
-
-			// skip disabled or missing features....
-			if(k[0] == '-' || !that[k]){
-				continue
-			}
-
-			var deps = that[k].depends || []
-			var refs = that[k].suggested || []
-
-			deps.forEach(function(n){
-				// expand lst with dependencies....
-				lst.indexOf(n) < 0 && lst.push(n)
-
-				// build reverse dependency index...
-				var d = dependants[n] = dependants[n] || []
-				d.indexOf(k) < 0 && d.push(k)
-			})
-
-			// expand lst with suggenstions....
-			refs.forEach(function(n){
-				lst.indexOf(n) < 0 && lst.push(n)
-			})
-		}
-
-		// sort features by priority or position...
-		lst = lst
-			// remove undefined and non-features...
-			.filter(function(n){ 
-				// feature disabled -> record and skip...
-				if(n[0] == '-'){
-					disabled.push(n.slice(1))
-					return false
-				}
-				var f = that[n]
-				// feature not defined or is not a feature...
-				if(f == null || !(f instanceof Feature)){
-					return false
-				}
-				// check applicability...
-				if(f.isApplicable && !f.isApplicable.call(that, obj)){
-					unapplicable.push(n)
-					return false
-				}
-				return true
-			})
-			// remove disabled...
-			.filter(function(e){ return disabled.indexOf(e) < 0 })
-			// build the sort table: [ , ,  ]
-			.map(function(e, i){ return [ that[e].getPriority(), i, e ] })
-			// do the sort...
-			// NOTE: JS compares lists as strings so we have to compare 
-			// 		the list manually...
-			.sort(function(a, b){ return a[0] - b[0] || a[1] - b[1] })
-			// cleanup -- drop the sort table...
-			.map(function(e){ return e[2] })
-
-		// remove dependants on not applicable and on disabled...
-		var _unapplicable = unapplicable.slice()
-		var _disabled = disabled.slice()
-		// build the full lists of features to remove...
-		_unapplicable
-			.forEach(function(n){ _unapplicable = _unapplicable.concat(_buildDepList(n)) })
-		_disabled
-			.forEach(function(n){ _disabled = _disabled.concat(_buildDepList(n)) })
-		// clear...
-		// NOTE: in case of intersection disabled has priority...
-		lst = lst
-			.filter(function(n){
-				return _disabled.indexOf(n) >= 0 ?
-						disabled.push(n) && false
-					: _unapplicable.indexOf(n) >= 0 ?
-						unapplicable.push(n) && false
-					: true })
-
-		// missing stage 2: dependencies...
-		lst.forEach(function(k){
-			(that[k].depends || []).forEach(function(d){
-				// NOTE: we do not need to check disabled or unapplicable
-				// 		here as if the feature depended on dropped feature
-				// 		it would have been already dropped too...
-				if(!that[k]){
-					var m = missing[k] = missing[k] || []
-					m.push(d)
-				}
-			})
-		})
-
-		// check exclusive -> excluded...
-		//
-		// NOTE: this is the right spot for this, just after priority 
-		// 		sorting and clearing but before dependency sorting.
-		//
-		// XXX do we need to clear dependencies pulled by excluded features???
-		// 		ways to go:
-		// 			- drop excluded and continue (current state)
-		// 			- disable excluded, add to original input and rebuild
-		// 			- err and let the user decide
-		var _exclusive = []
-		lst = lst.filter(function(n){
-			var e = that[n]
-
-			// keep non-exclusive stuff...
-			if(!e || e.exclusive == null){
-				return true
-			}
-
-			// count the number of exclusive features already present...
-			var res = e.exclusive
-				.filter(function(n){
-					if(_exclusive.indexOf(n) < 0){
-						_exclusive.push(n)
-						return false
-					}
-					return true
-				})
-				.length == 0
-
-			!res 
-				&& excluded.push(n)
-				// warn the user...
-				// XXX not sure if this is the right place for this...
-				&& console.warn(
-					'Excluding unaplicable:', n, '(reccomended to exclude manually)')
-
-			return res
-		})
-
-		// sort by dependency...
-		var l = lst.length
-		// get maximum possible length...
-		// ...the worst case length appears to be (for full reversal):
-		// 		S(2*(n-1) + 1)
-		// 			S = n => n > 0 ? 2*(n-1)+1 + S(n-1) : 0
-		// 			S = n => n > 0 ? 2*n-1 + S(n-1) : 0
-		//
-		// 		2 * S(n) - n
-		// 			S = n => n > 0 ? n + S(n-1) : 0
-		// 			f = n => 2 * S(n) - n
-		//
-		//		N^2 + C
-		//			S = n => n * n
-		//
-		// NOTE: this is the brute force way to check if we have a 
-		// 		dependency loop, need something faster...
-		//
-		// XXX is O(n^2) good enough worst case here?
-		// 		...at this point I think it is acceptable as we'll not 
-		// 		expect dependency graphs too saturated, and the average 
-		// 		complexity is far better...
-		var max = l * l
-
-		for(var i=0; i < lst.length; i++){
-			var k = lst[i]
-			var depends = that[k].depends || []
-
-			// list of dependencies to move...
-			var move = []
-
-			lst
-				.slice(0, i)
-				.forEach(function(n, j){
-					// if n is a dependency of k, prepare to move...
-					if(depends.indexOf(n) >= 0){
-						delete lst[j] 
-						move.push(n)
-					}
-				})
-
-			// move the dependencies after k...
-			// NOTE: this will keep the order within the dependencies...
-			move.length > 0
-				&& lst.splice.apply(lst, [i+1, 0].concat(move))
-
-			// check for cyclic dependencies...
-			// XXX loop signs:
-			// 		- the tail length stops changing -- we stop progressing to list end
-			// 		- the loop is packed
-			// 			- each element includes a set of dependencies
-			// 			- this set is of the same length when at a specific element
-			// 		- we only shift the same set of N elements over N iterations
-			// 		- ...
-			if(lst.length >= max){
-				// XXX get the actual cycle...
-				console.error('Feature cyclic dependency...')
-				break
-			}
-		}
-
-		// cleanup after sort...
-		lst = lst
-			// remove undefined and non-features...
-			.filter(function(e){ 
-				return that[e] != null && that[e] instanceof Feature })
-			.reverse()
-
-
-		return {
-			input: input,
-
-			features: lst,
-
-			disabled: disabled,
-			unapplicable: unapplicable,
-			excluded: excluded,
-
-			missing: missing,
-			conflicts: conflicts,
-		}
-	},
-
-
-	//
-	//	.setup(, [, ...])
-	//		-> 
-	//
-	//	.setup([, ...])
-	//		-> 
-	//
-	setup: function(obj, lst){
-		// if no explicit object is given, just the list...
-		if(lst == null){
-			lst = obj
-			obj = null
-		}
-
-		obj = obj || (this.__actions__ || actions.Actions)()
-
-		lst = lst.constructor !== Array ? [lst] : lst
-		var features = this.buildFeatureList(obj, lst)
-		lst = features.features
-
-		// check for conflicts...
-		if(Object.keys(features.conflicts).length != 0
-				|| Object.keys(features.missing).length != 0){
-			var m = features.missing
-			var c = features.conflicts
-
-			// build a report...
-			var report = []
-
-			// missing deps...
-			Object.keys(m).forEach(function(k){
-				report.push(k + ': missing but required by:\n          ' + m[k].join(', '))
-			})
-			report.push('\n')
-
-			// conflicts...
-			Object.keys(c).forEach(function(k){
-				report.push(k + ': must setup after:\n          ' + c[k].join(', '))
-			})
-
-			// break...
-			throw 'Feature dependency error:\n    ' + report.join('\n    ') 
-		}
-
-		// report excluded features...
-		if(this.__verbose__ && features.excluded.length > 0){
-			console.warn('Excluded features due to exclusivity conflict:', 
-					features.excluded.join(', '))
-		}
-
-		// report unapplicable features...
-		if(this.__verbose__ && features.unapplicable.length > 0){
-			console.log('Features not applicable in current context:', 
-					features.unapplicable.join(', '))
-		}
-
-		// do the setup...
-		var that = this
-		var setup = FeatureProto.setup
-		lst.forEach(function(n){
-			// setup...
-			if(that[n] != null){
-				this.__verbose__ && console.log('Setting up feature:', n)
-				setup.call(that[n], obj)
-			}
-		})
-
-		// XXX should we extend this if it already was in the object???
-		obj.features = features
-
-		return obj
-	},
-	remove: function(obj, lst){
-		lst = lst.constructor !== Array ? [lst] : lst
-		var that = this
-		lst.forEach(function(n){
-			if(that[n] != null){
-				console.log('Removing feature:', n)
-				that[n].remove(obj)
-			}
-		})
-	},
-
-	// shorthand for: Feature(, ...)
-	// XXX should this return this?
-	Feature: function(){
-		return this.__feature__.apply(null, [this].concat(args2array(arguments)))
-	},
-}
-
-
-var FeatureSet =
-module.FeatureSet = object.makeConstructor('FeatureSet', FeatureSetProto)
-
-
-//---------------------------------------------------------------------
-
-var Features =
-module.Features = new FeatureSet()
-
-
-
-
-/**********************************************************************
-* vim:set ts=4 sw=4 :                               */ return module })
diff --git a/ui (gen4)/lib/object.js b/ui (gen4)/lib/object.js
deleted file mode 100755
index 5f747821..00000000
--- a/ui (gen4)/lib/object.js	
+++ /dev/null
@@ -1,220 +0,0 @@
-/**********************************************************************
-* 
-*
-*
-**********************************************************************/
-((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
-(function(require){ var module={} // make module AMD/node compatible...
-/*********************************************************************/
-
-return require('../node_modules/ig-object/object')
-
-// XXX
-// XXX replace this with ig-object
-// XXX
-
-
-/*********************************************************************/
-
-
-// Make a JavaScrip object constructor...	
-//
-//
-// 	Make a constructor with an object prototype...
-// 		makeConstructor(, )
-// 			-> constructor
-//
-// 	Make a constructor with an init function prototype...
-// 		makeConstructor(, )
-// 			-> constructor
-//
-// 	Make a constructor with a prototype (object/function) and a class
-// 	prototype...
-// 		makeConstructor(, , )
-// 		makeConstructor(, , )
-// 			-> constructor
-// 			NOTE: the  defines a set of class methods and 
-// 					attributes.
-//
-//
-//
-// The resulting constructor can produce objects in one of these ways:
-//
-// 	Basic constructor use...
-// 		constructor()
-// 		new constructor
-// 		new constructor()
-// 			-> instance
-//
-// 	Pass arguments to the constructor...
-// 		constructor([, ...])
-// 		new constructor([, ...])
-// 			-> instance
-//
-//
-// All produced objects are instances of the constructor
-// 		instance instanceof constructor
-// 			-> true
-//
-//
-//
-// Init protocol:
-// 	1) the base instance object is prepared (.__proto__ is set)
-// 	2) if  is present, then it is called with instance as 
-// 		context and passed the constructor arguments
-// 	3) if .__init__(..) is present, it is called with the instance
-// 		as context and passed the constructor arguments.
-//
-//
-//
-// Inheritance:
-// 	A simple way to build C -> B -> A chain would be:
-//
-// 		var A = makeConstructor('A', {})
-//
-// 		// NOTE: the prototype is an instance and not a constructor,
-// 		//		this is obvious if one considers that in JS there are
-// 		//		no classes and inheritance is done via object prototypes
-// 		//		but this might be a gotcha to people coming from the 
-// 		//		class-object world.
-// 		var B = makeConstructor('B', A())
-//
-// 		var C = makeConstructor('C', B())
-//
-// 		var c = C()
-//
-// 		c instanceof C		// -> true
-// 		c instanceof B		// -> true
-// 		c instanceof A		// -> true
-//
-// 		A.prototype.x = 123
-//
-// 		c.x 				// -> 123
-//
-//
-//
-// Motivation:
-// 	The general motivation here is to standardise the constructor protocol
-// 	and make a single simple way to go with minimal variation. This is due
-// 	to the JavaScript base protocol though quite simple, being too flexible
-// 	making it very involved to produce objects in a consistent manner by 
-// 	hand, especially in long running projects, in turn spreading all the 
-// 	refactoring over multiple sites and styles.
-//
-// 	This removes part of the flexibility and in return gives us:
-// 		- single, well defined protocol
-// 		- one single spot where all the "magic" happens
-// 		- full support for existing JavaScript ways of doing things
-// 		- easy refactoring without touching the client code
-//
-//
-// NOTE: this sets the proto's .constructor attribute, this rendering it
-// 		not reusable, to use the same prototype for multiple objects clone
-// 		it via. Object.create(..) or copy it...
-//
-// XXX might be a good idea to be able to make an instance without 
-// 		initializing it...
-// 		...mainly for inheritance.
-// 		...would also be helpful in this case to call all the 
-// 		constructors in the chain
-var makeConstructor =
-module.makeConstructor =
-function makeConstructor(name, a, b){
-	var proto = b == null ? a : b
-	var cls_proto = b == null ? b : a
-
-	var _constructor = function Constructor(){
-		/*
-		// XXX BUG: if the constructor is called from it's instance this will 
-		// 		return the instance and not a new object...
-		// in case this is called as a function (without new)...
-		if(this.constructor !== _constructor){
-			// NOTE: the following does the job of the 'new' operator but
-			// 		with one advantage, we can now pass arbitrary args 
-			// 		in...
-			// 		This is equivalent to:
-			//			return new _constructor(json)
-			var obj = {}
-			obj.__proto__ = _constructor.prototype
-			// XXX for some reason this does not resolve from .__proto__
-			obj.constructor = _constructor
-			//obj.__proto__.constructor = _constructor
-
-		} else {
-			var obj = this
-		}
-		*/
-
-		// NOTE: the following does the job of the 'new' operator but
-		// 		with one advantage, we can now pass arbitrary args 
-		// 		in...
-		// 		This is equivalent to:
-		//			return new _constructor(json)
-		var obj = {}
-		obj.__proto__ = _constructor.prototype
-		// XXX for some reason this does not resolve from .__proto__
-		// XXX this also is a regular attr and not a prop...
-		//obj.constructor = _constructor
-		Object.defineProperty(obj, 'constructor', {
-			value: _constructor,
-			enumerable: false,
-		})
-		//obj.__proto__.constructor = _constructor
-
-		// explicit init...
-		if(proto instanceof Function){
-			proto.apply(obj, arguments)
-		}
-
-		// load initial state...
-		if(obj.__init__ != null){
-			obj.__init__.apply(obj, arguments)
-		}
-
-		return obj
-	}
-
-	/* XXX for some reason this works for the _constructor but all 
-	 * 		instances get the wrong name resolved...
-	Object.defineProperty(_constructor, 'name', {
-		value: name,
-	})
-	*/
-
-	// just in case the browser refuses to change the name, we'll make it
-	// a different offer ;)
-	if(_constructor.name == 'Constructor'){
-			// skip for chrome app...
-			//&& !(window.chrome && chrome.runtime && chrome.runtime.id)){
-		eval('_constructor = '+ _constructor
-				.toString()
-				.replace(/Constructor/g, name))
-	}
-
-	_constructor.__proto__ = cls_proto
-	_constructor.prototype = proto
-	_constructor.prototype.constructor = _constructor
-
-	return _constructor
-}
-
-
-// super equivalent...
-//
-// 	superMethod(, ).call(this, ...)
-// 		-> 
-//
-// This will return a next method in inheritance chain after  by
-// its name ().
-// In the normal use-case  is the current class and 
-// is the name of the current method.
-var superMethod =
-module.superMethod =
-function superMethod(cls, meth){
-	return cls.prototype.__proto__[meth]
-}
-
-
-
-/**********************************************************************
-* vim:set ts=4 sw=4 :                               */ return module })
diff --git a/ui (gen4)/ui.js b/ui (gen4)/ui.js
index 79114c11..e8f15aa8 100755
--- a/ui (gen4)/ui.js	
+++ b/ui (gen4)/ui.js	
@@ -15,6 +15,36 @@ if((typeof(process) != 'undefined' ? process : {}).__nwjs){
 		.addPath(path.dirname(process.execPath) + '/node_modules/')
 }
 
+//*
+// Setup modules loaded from npm...
+//
+// XXX for some reason this breaks in browser if run after the if below...
+// XXX not sure if this strategy is correct...
+// 		...most likely this is not actually a good idea, need to think of
+// 		a way of organizing things without so much manual hoop jumping...
+var requirejs_cfg = {
+	paths: {
+		// XXX one approach to avoid at least this section is to copy the
+		// 		modules to lib/*, this way we'll need the map section below
+		// 		only...	(without automation this also sounds bad)
+		'lib/object': './node_modules/ig-object/object',
+		'lib/actions': './node_modules/ig-features/actions',
+		'lib/features': './node_modules/ig-features/features',
+	},	
+	map: {
+		'*': {
+			// back-refs
+			// ...these enable the npm modules reference each other in 
+			// a cross-platform manner....
+			'ig-object': 'lib/object',
+			'ig-actions': 'lib/actions',
+			'ig-features': 'lib/features',
+		},
+	},
+}
+// config the browser version of requirejs...
+requirejs.config(requirejs_cfg)
+//*/
 
 // Setup requirejs if we are in node/nw...
 //
@@ -26,18 +56,27 @@ if((typeof(process) != 'undefined' ? process : {}).__nwjs){
 // XXX setting nodeRequire on existing requirejs will change how 
 // 		everything is loaded...
 if(typeof(process) != 'undefined'){
-	var requirejs = 
+	requirejs = 
 	global.requirejs = 
 	window.requirejs = 
+		// XXX for some reason we can't just use the browser requirejs 
+		// 		even if we pass it nodeRequire, it still can't pass the
+		// 		node stuff to node...
 		require('requirejs')
 
-	var nodeRequire =
+	// config the node version of requirejs...
+	requirejs.config(requirejs_cfg)
+
+	nodeRequire =
 	global.nodeRequire = 
 	window.nodeRequire =
 		require
 }
 
 
+
+
+
 /*********************************************************************/
 (typeof(define)[0]=='u'?function(f){module.exports=f(require)}:define)(
 function(require){ var module={} // makes module AMD/node compatible...