2015-12-17 03:34:20 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Core features that setup the life-cycle and the base interfaces for
|
|
|
|
|
* features to use...
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
|
|
define(function(require){ var module = {}
|
|
|
|
|
|
|
|
|
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
|
|
|
|
|
|
|
|
|
var actions = require('lib/actions')
|
|
|
|
|
var features = require('lib/features')
|
2016-03-28 22:07:38 +03:00
|
|
|
var toggler = require('lib/toggler')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
2016-05-01 21:54:44 +03:00
|
|
|
|
|
|
|
|
var protocolAction =
|
|
|
|
|
module.protocol = function(protocol, func){
|
|
|
|
|
return function(){
|
|
|
|
|
this[protocol].chainCall(this, func, arguments)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-28 22:07:38 +03:00
|
|
|
|
|
|
|
|
// NOTE: if not state is set this assumes that the first state is the
|
|
|
|
|
// default...
|
|
|
|
|
var makeConfigToggler =
|
|
|
|
|
module.makeConfigToggler =
|
2016-04-22 16:13:20 +03:00
|
|
|
function(attr, states, a, b){
|
|
|
|
|
|
|
|
|
|
var pre = a
|
|
|
|
|
var post = b || function(action){ action != null && this.focusImage() }
|
|
|
|
|
|
2016-03-28 22:07:38 +03:00
|
|
|
return toggler.Toggler(null,
|
|
|
|
|
function(_, action){
|
|
|
|
|
var lst = states.constructor === Array ? states : states.call(this)
|
|
|
|
|
|
|
|
|
|
//console.log('action', action)
|
|
|
|
|
|
|
|
|
|
if(action == null){
|
|
|
|
|
return this.config[attr] || lst[lst.indexOf('none')] || lst[0]
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
this.config[attr] = action
|
|
|
|
|
//this.focusImage()
|
|
|
|
|
}
|
|
|
|
|
},
|
2016-04-22 16:13:20 +03:00
|
|
|
states, pre, post)
|
2016-03-28 22:07:38 +03:00
|
|
|
}
|
|
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2016-04-27 08:59:13 +03:00
|
|
|
// Root ImageGrid.viewer object...
|
|
|
|
|
//
|
2015-12-17 03:34:20 +03:00
|
|
|
var ImageGridFeatures =
|
|
|
|
|
module.ImageGridFeatures = Object.create(features.FeatureSet)
|
|
|
|
|
|
|
|
|
|
|
2016-04-27 08:59:13 +03:00
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// Setup runtime info...
|
|
|
|
|
|
2016-04-09 18:39:01 +03:00
|
|
|
// nw or node...
|
2015-12-29 07:28:19 +03:00
|
|
|
if(typeof(process) != 'undefined'){
|
|
|
|
|
|
2016-04-09 18:39:01 +03:00
|
|
|
// nw.js 0.13+
|
|
|
|
|
if(typeof(nw) != 'undefined'){
|
|
|
|
|
ImageGridFeatures.runtime = 'nw'
|
|
|
|
|
|
2016-04-10 14:04:44 +03:00
|
|
|
// NOTE: jli is patching the Date object and with two separate
|
|
|
|
|
// instances we'll need to sync things up...
|
2016-04-11 15:58:12 +03:00
|
|
|
// XXX HACK: if node and chrome Date implementations ever
|
|
|
|
|
// significantly diverge this will break things + this is
|
|
|
|
|
// a potential data leak between contexts...
|
|
|
|
|
//global.Date = window.Date
|
|
|
|
|
|
|
|
|
|
// XXX this is less of a hack but it is still an implicit
|
|
|
|
|
patchDate(global.Date)
|
|
|
|
|
patchDate(window.Date)
|
2016-04-10 14:04:44 +03:00
|
|
|
|
2016-04-09 18:39:01 +03:00
|
|
|
// node...
|
|
|
|
|
} else {
|
|
|
|
|
ImageGridFeatures.runtime = 'node'
|
2016-04-11 15:58:12 +03:00
|
|
|
|
|
|
|
|
// XXX patch Date...
|
|
|
|
|
// XXX this will not work directly as we will need to explicitly
|
|
|
|
|
// require jli...
|
|
|
|
|
//patchDate(global.Date)
|
2016-04-09 18:39:01 +03:00
|
|
|
}
|
2015-12-29 07:28:19 +03:00
|
|
|
|
|
|
|
|
// browser...
|
2016-04-09 18:39:01 +03:00
|
|
|
// NOTE: we're avoiding detecting browser specifics for as long as possible,
|
|
|
|
|
// this will minimize the headaches of supporting several non-standard
|
|
|
|
|
// versions of code...
|
2015-12-31 10:37:21 +03:00
|
|
|
} else if(typeof(window) != 'undefined'){
|
2015-12-29 07:28:19 +03:00
|
|
|
ImageGridFeatures.runtime = 'browser'
|
|
|
|
|
|
|
|
|
|
// unknown...
|
2016-04-09 18:39:01 +03:00
|
|
|
// XXX do we need to detect chrome app???
|
2015-12-29 07:28:19 +03:00
|
|
|
} else {
|
|
|
|
|
ImageGridFeatures.runtime = 'unknown'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
/*********************************************************************/
|
2016-04-27 08:59:13 +03:00
|
|
|
// System life-cycle...
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
// XXX should this be a generic library thing???
|
|
|
|
|
// XXX should his have state???
|
|
|
|
|
// ...if so, should this be a toggler???
|
|
|
|
|
var LifeCycleActions = actions.Actions({
|
|
|
|
|
start: ['- System/',
|
|
|
|
|
function(){
|
|
|
|
|
var that = this
|
|
|
|
|
this.logger && this.logger.emit('start')
|
|
|
|
|
|
|
|
|
|
// NOTE: jQuery currently provides no way to check if an event
|
|
|
|
|
// is bound so we'll need to keep track manually...
|
|
|
|
|
if(this.__stop_handler == null){
|
|
|
|
|
var stop = this.__stop_handler = function(){ that.stop() }
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-29 07:28:19 +03:00
|
|
|
// set the runtime...
|
|
|
|
|
var runtime = this.runtime = ImageGridFeatures.runtime
|
2015-12-17 03:34:20 +03:00
|
|
|
|
2015-12-29 07:28:19 +03:00
|
|
|
// nw.js...
|
|
|
|
|
if(runtime == 'nw'){
|
|
|
|
|
// this handles both reload and close...
|
|
|
|
|
$(window).on('beforeunload', stop)
|
2015-12-17 03:34:20 +03:00
|
|
|
|
2015-12-29 07:28:19 +03:00
|
|
|
// NOTE: we are using both events as some of them do not
|
|
|
|
|
// get triggered in specific conditions and some do,
|
|
|
|
|
// for example, this gets triggered when the window's
|
|
|
|
|
// 'X' is clicked while does not on reload...
|
|
|
|
|
this.__nw_stop_handler = function(){
|
|
|
|
|
var w = this
|
|
|
|
|
try{
|
|
|
|
|
that
|
|
|
|
|
// wait till ALL the handlers finish before
|
|
|
|
|
// exiting...
|
|
|
|
|
.on('stop.post', function(){
|
2016-04-09 18:39:01 +03:00
|
|
|
// XXX might be broken in nw13 -- test!!!
|
|
|
|
|
//w.close(true)
|
|
|
|
|
nw.App.quit()
|
2015-12-29 07:28:19 +03:00
|
|
|
})
|
|
|
|
|
.stop()
|
|
|
|
|
|
|
|
|
|
// in case something breaks exit...
|
|
|
|
|
// XXX not sure if this is correct...
|
|
|
|
|
} catch(e){
|
|
|
|
|
this.close(true)
|
|
|
|
|
}
|
2015-12-17 03:34:20 +03:00
|
|
|
}
|
2016-04-09 18:39:01 +03:00
|
|
|
nw.Window.get().on('close', this.__nw_stop_handler)
|
2015-12-17 03:34:20 +03:00
|
|
|
|
2015-12-29 07:28:19 +03:00
|
|
|
// node.js...
|
|
|
|
|
} else if(runtime == 'node'){
|
|
|
|
|
process.on('exit', stop)
|
|
|
|
|
|
|
|
|
|
// browser...
|
|
|
|
|
} else if(runtime == 'browser'){
|
2015-12-17 03:34:20 +03:00
|
|
|
$(window).on('beforeunload', stop)
|
|
|
|
|
|
2015-12-29 07:28:19 +03:00
|
|
|
// other...
|
2015-12-17 03:34:20 +03:00
|
|
|
} else {
|
2015-12-29 07:28:19 +03:00
|
|
|
// XXX
|
2015-12-17 03:34:20 +03:00
|
|
|
}
|
|
|
|
|
}],
|
|
|
|
|
// unbind events...
|
|
|
|
|
stop: ['- System/',
|
|
|
|
|
function(){
|
|
|
|
|
// browser & nw...
|
|
|
|
|
if(this.__stop_handler
|
|
|
|
|
&& (this.runtime == 'browser' || this.runtime == 'nw')){
|
|
|
|
|
$(window).off('beforeunload', this.__stop_handler)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// nw...
|
|
|
|
|
if(this.__nw_stop_handler && this.runtime == 'nw'){
|
2016-04-09 18:39:01 +03:00
|
|
|
//nw.Window.get().off('close', this.__nw_stop_handler)
|
2015-12-17 03:34:20 +03:00
|
|
|
delete this.__nw_stop_handler
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// node...
|
2015-12-31 10:37:21 +03:00
|
|
|
/* XXX there's no process.off(...)
|
2015-12-17 03:34:20 +03:00
|
|
|
if(this.__stop_handler && this.runtime == 'node'){
|
|
|
|
|
process.off('exit', this.__stop_handler)
|
|
|
|
|
}
|
2015-12-31 10:37:21 +03:00
|
|
|
*/
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
delete this.__stop_handler
|
|
|
|
|
|
|
|
|
|
this.logger && this.logger.emit('stop')
|
|
|
|
|
}],
|
2015-12-26 01:12:39 +03:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// XXX need a clear protocol for this...
|
|
|
|
|
// something like:
|
|
|
|
|
// - clear state
|
|
|
|
|
// - load state
|
|
|
|
|
reset: ['System/',
|
|
|
|
|
function(){
|
|
|
|
|
}],
|
|
|
|
|
*/
|
2015-12-17 03:34:20 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var LifeCycle =
|
|
|
|
|
module.LifeCycle = ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
|
|
|
|
tag: 'lifecycle',
|
2016-01-03 04:49:00 +03:00
|
|
|
priority: 'high',
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
actions: LifeCycleActions,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-01 22:41:03 +03:00
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// Introspection...
|
|
|
|
|
|
|
|
|
|
// Indicate that an action is not intended for direct use...
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this will not do anything but mark the action.
|
|
|
|
|
var notUserCallable =
|
|
|
|
|
module.notUserCallable = function(func){
|
|
|
|
|
func.__not_user_callable__ = true
|
|
|
|
|
return func
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var IntrospectionActions = actions.Actions({
|
|
|
|
|
// user-callable actions...
|
|
|
|
|
get useractions(){
|
|
|
|
|
return this.actions.filter(this.isUserCallable.bind(this)) },
|
|
|
|
|
|
|
|
|
|
// check if action is callable by user...
|
|
|
|
|
isUserCallable: ['- System/',
|
|
|
|
|
actions.doWithRootAction(function(action){
|
|
|
|
|
return action.__not_user_callable__ != true })],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var Introspection =
|
|
|
|
|
module.Introspection = ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
|
|
|
|
|
tag: 'introspection',
|
|
|
|
|
|
|
|
|
|
actions: IntrospectionActions,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-03-28 22:07:38 +03:00
|
|
|
//---------------------------------------------------------------------
|
2016-04-27 08:59:13 +03:00
|
|
|
// Workspace...
|
2016-03-28 22:07:38 +03:00
|
|
|
//
|
|
|
|
|
// Basic protocol:
|
|
|
|
|
// A participating feature should:
|
|
|
|
|
// - react to .saveWorkspace(..) by saving it's relevant state data to the
|
|
|
|
|
// object returned by the .saveWorkspace() action.
|
|
|
|
|
// NOTE: it is recommended that a feature save its relevant .config
|
|
|
|
|
// data as-is.
|
2016-03-28 22:12:22 +03:00
|
|
|
// NOTE: no other action or state change should be triggered by this.
|
2016-03-28 22:07:38 +03:00
|
|
|
// - react to .loadWorkspace(..) by loading it's state from the returned
|
|
|
|
|
// object...
|
2016-03-28 22:12:22 +03:00
|
|
|
// NOTE: this can be active, i.e. a feature may call actions when
|
|
|
|
|
// handling this.
|
2016-03-28 22:07:38 +03:00
|
|
|
// - react to .toggleChrome(..) and switch on and off the chrome
|
|
|
|
|
// visibility... (XXX)
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
|
2016-03-29 00:31:50 +03:00
|
|
|
|
|
|
|
|
// Helpers...
|
|
|
|
|
var makeWorkspaceConfigWriter =
|
|
|
|
|
module.makeWorkspaceConfigWriter = function(keys, callback){
|
|
|
|
|
return function(workspace){
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
keys = typeof(keys) == typeof(function(){}) ? keys() : keys
|
|
|
|
|
|
|
|
|
|
// store statusbar data...
|
|
|
|
|
keys.forEach(function(key){
|
|
|
|
|
workspace[key] = JSON.parse(JSON.stringify(that.config[key]))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
callback && callback.call(this, workspace)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX should this delete a prop if it's not in the loading workspace???
|
|
|
|
|
var makeWorkspaceConfigLoader =
|
|
|
|
|
module.makeWorkspaceConfigLoader = function(keys, callback){
|
|
|
|
|
return function(workspace){
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
keys = typeof(keys) == typeof(function(){}) ? keys() : keys
|
|
|
|
|
|
|
|
|
|
// load statusbar data...
|
|
|
|
|
keys.forEach(function(key){
|
|
|
|
|
// the key exists...
|
|
|
|
|
if(key in workspace){
|
|
|
|
|
that.config[key] = JSON.parse(JSON.stringify(workspace[key]))
|
|
|
|
|
|
|
|
|
|
// no key set...
|
|
|
|
|
// XXX is this the right way to go???
|
|
|
|
|
} else {
|
|
|
|
|
delete that.config[key]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
callback && callback.call(this, workspace)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
2016-03-28 22:12:22 +03:00
|
|
|
var WorkspaceActions = actions.Actions({
|
2016-03-28 22:07:38 +03:00
|
|
|
config: {
|
|
|
|
|
'workspace': 'default',
|
2016-03-29 00:31:50 +03:00
|
|
|
'workspaces': {},
|
2016-03-28 22:07:38 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
get workspace(){
|
|
|
|
|
return this.config.workspace
|
|
|
|
|
},
|
|
|
|
|
set workspace(value){
|
|
|
|
|
this.loadWorkspace(value)
|
|
|
|
|
},
|
|
|
|
|
|
2016-03-29 00:31:50 +03:00
|
|
|
get workspaces(){
|
|
|
|
|
return this.config.workspaces
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
2016-03-28 22:07:38 +03:00
|
|
|
getWorkspace: ['- Workspace/',
|
|
|
|
|
function(){ return this.saveWorkspace(null) }],
|
|
|
|
|
|
|
|
|
|
// NOTE: these are mainly triggers for other features to save/load
|
|
|
|
|
// their specific states...
|
|
|
|
|
// NOTE: handlers should only set data on the workspace object passively,
|
|
|
|
|
// no activity is recommended.
|
|
|
|
|
// NOTE: if null is passed this will only get the data, but will
|
|
|
|
|
// save nothing. this us useful for introspection and temporary
|
|
|
|
|
// context storage.
|
|
|
|
|
//
|
2016-03-29 00:58:20 +03:00
|
|
|
// XXX for some reason this does not get saved with .config...
|
2016-03-28 22:07:38 +03:00
|
|
|
saveWorkspace: ['Workspace/Save Workspace',
|
|
|
|
|
function(name){
|
2016-03-29 03:39:23 +03:00
|
|
|
if(!this.config.hasOwnProperty('workspaces')){
|
|
|
|
|
this.config['workspaces'] = JSON.parse(JSON.stringify(this.config['workspaces']))
|
|
|
|
|
}
|
2016-03-28 22:07:38 +03:00
|
|
|
|
|
|
|
|
var res = {}
|
|
|
|
|
|
|
|
|
|
if(name !== null){
|
2016-03-29 00:31:50 +03:00
|
|
|
this.config['workspaces'][name || this.config.workspace] = res
|
2016-03-28 22:07:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
}],
|
|
|
|
|
// NOTE: merging the state data is the responsibility of the feature
|
|
|
|
|
// ...this is done so as not to restrict the feature to one
|
|
|
|
|
// specific way to do stuff...
|
|
|
|
|
loadWorkspace: ['Workspace/Load Workspace',
|
|
|
|
|
function(name){
|
2016-03-29 03:39:23 +03:00
|
|
|
name = name || this.config.workspace
|
|
|
|
|
|
2016-03-29 00:31:50 +03:00
|
|
|
// get a workspace by name and load it...
|
|
|
|
|
if(typeof(name) == typeof('str')){
|
|
|
|
|
this.config.workspace = name
|
2016-03-28 22:07:38 +03:00
|
|
|
|
2016-03-29 05:17:50 +03:00
|
|
|
return this.workspaces[name] || {}
|
2016-03-29 00:31:50 +03:00
|
|
|
|
|
|
|
|
// we got the workspace object...
|
|
|
|
|
} else {
|
|
|
|
|
return name
|
|
|
|
|
}
|
2016-03-28 22:07:38 +03:00
|
|
|
}],
|
|
|
|
|
|
2016-03-29 05:17:50 +03:00
|
|
|
// NOTE: this will not save the current workspace...
|
2016-03-28 22:07:38 +03:00
|
|
|
toggleWorkspace: ['Workspace/Toggle Workspace',
|
|
|
|
|
makeConfigToggler('workspace',
|
2016-03-29 00:31:50 +03:00
|
|
|
function(){ return Object.keys(this.config['workspaces']) },
|
2016-03-28 22:07:38 +03:00
|
|
|
function(state){ this.loadWorkspace(state) })],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var Workspace =
|
|
|
|
|
module.Workspace = ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
|
|
|
|
|
tag: 'workspace',
|
|
|
|
|
|
|
|
|
|
depends: [
|
|
|
|
|
'lifecycle',
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
actions: WorkspaceActions,
|
|
|
|
|
|
|
|
|
|
handlers: [
|
|
|
|
|
['stop',
|
|
|
|
|
function(){ this.saveWorkspace() }],
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-27 08:59:13 +03:00
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
// Tasks...
|
|
|
|
|
// XXX should this be a separate module???
|
|
|
|
|
|
|
|
|
|
var tasks = require('lib/tasks')
|
|
|
|
|
|
|
|
|
|
// XXX see if a protocol can be practical here to:
|
|
|
|
|
// - serialize/restore jobs
|
|
|
|
|
// - ...
|
|
|
|
|
var TaskActions = actions.Actions({
|
|
|
|
|
config: {
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
get jobs(){
|
|
|
|
|
return this.__jobs
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getJob: ['- Jobs/',
|
|
|
|
|
function(name){
|
|
|
|
|
name = name || this.data.newGid()
|
|
|
|
|
|
|
|
|
|
// get/init task dict...
|
|
|
|
|
var t = this.__jobs = this.__jobs || {}
|
|
|
|
|
// get/init task...
|
|
|
|
|
var job = t[name] = t[name] || tasks.Queue()
|
|
|
|
|
job.name = name
|
|
|
|
|
|
|
|
|
|
return job
|
|
|
|
|
}],
|
|
|
|
|
|
|
|
|
|
// XXX stop
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var Tasks =
|
|
|
|
|
module.Tasks = ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
|
|
|
|
|
tag: 'tasks',
|
|
|
|
|
|
|
|
|
|
depends: [ ],
|
|
|
|
|
|
|
|
|
|
actions: TaskActions,
|
|
|
|
|
|
|
|
|
|
handlers: [
|
|
|
|
|
['start',
|
|
|
|
|
function(){
|
|
|
|
|
// XXX prepare for recovery and recover...
|
|
|
|
|
}],
|
|
|
|
|
['stop',
|
|
|
|
|
function(){
|
|
|
|
|
// XXX stop tasks and prepare for recovery...
|
|
|
|
|
}],
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */
|
|
|
|
|
return module })
|