/*
 * Copyright (c) 2009 - 2013, javalikescript@free.fr (SPYL). All rights reserved.
 * JLS is licensed under LGPL, see the license.txt file that accompanied this code.
 */
/*
 * Asynchronous Module Definition (AMD) API implementation for JLS.
 * The following code creates a 'require' function to load modules.
 */
(function() {
    /* Miscellaneous functions */
    var warn, log, debug, basename, dirname, concatPath, evalScript, basemodule, submodule;
    log = debug = warn = function(msg) {
        //_native.core.log(4, msg);
    };
    var deferredLoading = false, previousDefine = undefined;
    evalScript = function(path, callback, sync, prefix, suffix) {};
    extension = function(path) {
        var index = path.lastIndexOf('.');
        return index == -1 ? '' : path.substring(index + 1);
    };
    basename = function(path) {
        var index = path.lastIndexOf('/');
        return index == -1 ? path : path.substring(index + 1);
    };
    dirname = function(path) {
        var index = path.lastIndexOf('/');
        return index == -1 ? '' : path.substring(0, index);
    };
    concatPath = function(a, b) {
        var pathItems = b.split('/');
        if ((a != '.') && ((pathItems[0] == '.') || (pathItems[0] == '..'))) {
            pathItems = a.split('/').concat(pathItems);
        }
        for (var i = 0; i < pathItems.length; i++) {
            var pathItem = pathItems[i];
            if ((pathItem == '.') || (pathItem == '')) {
                pathItems.splice(i, 1);
                i--;
            } else if ((i > 0) && (pathItem == '..')) {
                pathItems.splice(i - 1, 2);
                i -= 2;
            }
        }
        return pathItems.join('/');
    };
    basemodule = function(path) {
        var index = path.indexOf('$');
        return index == -1 ? path : path.substring(0, index);
    };
    submodule = function(module, path) {
    	if (typeof path != 'string') {
    		return module;
    	}
        var index = path.indexOf('$');
    	if (index == -1) {
    		return module;
    	}
        var subpath = path.substring(index + 1);
        // TODO handle sub sub...
        return module[subpath];
    };
    var fullyQualifiedRequire, createRequire, fullyQualifiedDefine;
    /* The cache is a map containing the defined module by absolute path (module identifier) */
    var cache = {};
    /* The AMD specific define entry */
    var amd = {
            multiversion: true
    };
    /*  */
    var CacheEntry = function(path, sync, module) {
        this.path = path || null;
        this.module = module || undefined;
        this.exports = null;
        this.sync = sync || false;
        this.paths = null;
        this.callback = null;
        this.defined = false;
        this.loading = false;
        this.dependencies = [];
        this.count = 0;
        this.waiters = [];
        if (path) {
            cache[path] = this;
        }
        log('CacheEntry("' + path + '", ' + sync + ', ' + module + ')');
    };
    CacheEntry.prototype.declare = function(paths, callback) {
        log('declare([' + paths + '], ...) "' + this.path + '"');
        this.paths = paths || null;
        this.callback = callback || null;
    };
    CacheEntry.prototype.onDefined = function(module) {
        log('onDefined(...) "' + this.path + '"');
        this.module = module || null;
        if ((this.exports != null) && (typeof this.exports != 'undefined')) {
            var singleKey = null;
            for (var k in this.exports) {
                if (singleKey == null) {
                    singleKey = k;
                } else {
                    singleKey = null;
                    break;
                }
            }
            if (singleKey == null) {
                this.module = this.exports;
            } else {
                this.module = this.exports[singleKey];
            }
        }
        // Play dependencies
        for (var index = 0; index < this.waiters.length; index++) {
            this.waiters[index].notify(this);
        }
        // TODO Cleanup dependencies...
        this.waiters = [];
    };
    /* Creates a define function suitable for this module */
    CacheEntry.prototype.createDefine = function() {
        debug('createDefine() "' + this.path + '"');
        var self = this;
        var def = function(id, dependencies, factory) {
            // Parse arguments
            switch (arguments.length) {
            case 0:
                return;
            case 1:
                factory = id;
                dependencies = null;
                id = undefined;
                break;
            case 2:
                factory = dependencies;
                dependencies = id;
                id = undefined;
                break;
            case 3:
            default:
                break;
            }
            fullyQualifiedRequire(self.path, dependencies, factory, self.sync);
        };
        def.amd = amd;
        return def;
    };
    CacheEntry.prototype.onLoaded = function(fn, err) {
        debug('onLoaded(..., "' + err + '") "' + this.path + '"');
        if (err) {
            warn('Exception raised while loading "' + this.path + '": ' + err);
        } else if (typeof fn == 'function') {
            try {
                fn(this.createDefine());
                return;
            }
            catch (e) {
                warn('Exception raised while evaluating "' + this.path + '": ' + e);
            }
        } else {
            warn('Invalid argument while loading "' + this.path + '" (' + (typeof fn) + ')');
        }
        this.onDefined(null);
    };
    CacheEntry.prototype.load = function() {
        debug('load() "' + this.path + '"');
        var self = this;
        var path = this.path;
        var ext = extension(path);
        if ((ext != 'js') && (ext != 'ts')) {
            path += '.js';
        }
        this.loading = true;
        evalScript(path, function(fn, e) {
            self.onLoaded.call(self, fn, e);
        }, this.sync, '(function() { return function(define) { ', ' }; })();');
    };
    CacheEntry.prototype.notify = function(entry) {
        debug('notify("' + entry.path + '") "' + this.path + '"');
        for (var index = 0; index < this.paths.length; index++) {
            var path = basemodule(this.paths[index]);
            if (path == entry.path) {
                this.setDependency(index, entry.module);
                break;
            }
        }
    };
    CacheEntry.prototype.isDependent = function(entry) {
        debug('isDependent("' + entry.path + '") "' + this.path + '"');
        if (entry.path == null) {
            return false;
        }
        for (var index = 0; index < this.waiters.length; index++) {
            var waiter = this.waiters[index];
            if ((waiter.path != null) && ((waiter.path === entry.path) || (waiter.isDependent(entry)))) {
                return true;
            }
        }
        return false;
    };
    CacheEntry.prototype.wait = function(entry) {
        debug('wait("' + entry.path + '") "' + this.path + '"');
        if (this.isDependent(entry)) {
            throw 'Cyclic dependency detected between ' + this.path + ' and ' + entry.path;
        }
        entry.waiters.push(this);
    };
    CacheEntry.prototype.isLoading = function() {
        return this.loading;
    };
    CacheEntry.prototype.isLoaded = function() {
        return typeof this.module != 'undefined';
    };
    CacheEntry.prototype.isModule = function() {
        return this.path != null;
    };
    CacheEntry.prototype.isDeclared = function() {
        return (this.callback != null) || this.isLoaded();
    };
    CacheEntry.prototype.setDependency = function(index, value) {
    	var path = this.paths[index];
        this.dependencies[index] = submodule(value, path);
        this.count++;
        debug('setDependency(' + index + ', ...) "' + this.path + '" ' + this.count + '/' + this.paths.length);
        this.wakeup();
    };
    CacheEntry.prototype.wakeup = function() {
        if ((this.callback) && ((this.paths == null) || (this.count == this.paths.length))) {
            debug('wakeup() "' + this.path + '"');
            var fn = this.callback;
            var dep = this.dependencies;
            this.paths = null;
            this.callback = null;
            this.dependencies = null;
            var module = fn.apply(null, dep);
            this.onDefined(this.isModule() ? module : null);
        }
    };
    /* Base require/define function that use a fully qualified module id */
    fullyQualifiedRequire = function(moduleId, ids, callback, sync, dl) {
        if (typeof callback != 'function') {
            throw 'Invalid arguments';
        }
        sync = (typeof sync == 'boolean') ? sync : false;
        dl = (typeof dl == 'boolean') ? dl : deferredLoading;
        var basepath = dirname(moduleId || '');
        var name = basename(moduleId || '');
        var paths = [];
        if ((ids != null) && ('length' in ids)) {
            for (var index = 0; index < ids.length; index++) {
                var id = ids[index];
                if (id == '.') {
                    id = './main';
                }
                paths.push(concatPath(basepath, id));
            }
        }
        if (name == '?') {
            moduleId = null;
        }
        var entry;
        if (moduleId) {
            if (moduleId in cache) {
                // Check sync ?
                entry = cache[moduleId];
            } else {
                entry = new CacheEntry(moduleId, sync, undefined);
            }
            entry.defined = true;
        } else {
            entry = new CacheEntry(null, sync, undefined);
        }
        entry.declare(paths, callback);
        for (var index = 0; index < paths.length; index++) {
            var path = basemodule(paths[index]);
            var depEntry;
            try {
                if (path == 'require') {
                    entry.setDependency(index, createRequire(basepath));
                } else if (path == 'exports') {
                    entry.setDependency(index, entry.exports = {});
                } else if (path in cache) {
                    depEntry = cache[path];
                    if (depEntry.isLoaded()) {
                        entry.setDependency(index, depEntry.module);
                    } else {
                        // TODO Check sync
                        entry.wait(depEntry);
                        if (! (dl || depEntry.isLoading())) {
                        	depEntry.load();
                        }
                    }
                } else {
                    depEntry = new CacheEntry(path, sync);
                    entry.wait(depEntry);
                    if (! dl) {
                    	depEntry.load();
                    }
                }
            }
            catch (e) {
                warn('Exception raised: ' + e);
                //debug(e.name + ': ' + e.message);
                entry.setDependency(index, null);
            }
        }
        entry.wakeup();
    };
    /* Returns a require function suitable for a specific path */
    createRequire = function(path) {
        var req = function(ids, callback) {
            var async = true;
            var rmod = null;
            if (typeof ids == 'string') {
                async = false;
                ids = [ids];
                callback = function(module) {
                    if ((typeof module == 'undefined') || (module == null)) {
                        warn('Fail to require "' + ids[0] + '"');
                    }
                    rmod = module;
                };
            }
            fullyQualifiedRequire(path + '/?', ids, callback, !async);
            return async ? undefined : rmod;
        };
        req.toUrl = function(s) {
            log('toUrl["' + path + '"]("' + s + '")');
            return concatPath(path, s);
        };
        return req;
    };
    /* Define function that use a fully qualified module id */
    fullyQualifiedDefine = function(id, dependencies, factory) {
        if (arguments.length < 3) {
            return;
        }
        log('define(' + id + ')');
        fullyQualifiedRequire(id, dependencies, factory, true, true);
    };
    // Populate default cache values
    new CacheEntry('_AMD', true, {
        cache : cache,
        setLogFunction: function(fn) {
            warn = fn;
            //log = debug = warn;
        },
        enableDeferredLoading: function() {
            log('enableDeferredLoading()');
        	deferredLoading = true;
        },
        disableDeferredLoading: function() {
            log('disableDeferredLoading()');
        	deferredLoading = false;
        	var missedCount = 0;
        	if (! deferredLoading) {
                for (var path in cache) {
                    if (cache[path].module) {
                    	continue;
                    }
                    missedCount++;
                    if (cache[path].defined) {
                    	continue;
                    }
                    warn(' Module "' + path + '" not defined');
                }
        	}
        	if (missedCount > 0) {
        		throw missedCount + ' Module(s) missing';
        	}
        },
        enableDefine: function() {
            log('enableDefine()');
        	previousDefine = (typeof define != 'undefined') ? define : undefined;
            // global define function
        	define = fullyQualifiedDefine;
        },
        disableDefine: function() {
            log('disableDefine()');
        	define = previousDefine;
        },
        setEvalScriptFunction: function(fn) {
            evalScript = fn;
        },
        getModuleId: function(obj) {
            for (var id in cache) {
                if (cache[id].module === obj.constructor) {
                    return id;
                }
            }
            return null;
        },
        status: function() {
            log('AMD Cache status:');
            var lm = [], wm = [];
            for (var path in cache) {
                (cache[path].module ? lm : wm).push(path);
            }
            lm.sort(); wm.sort();
            for (var i = 0; i < lm.length; i++) {
                log(' "' + lm[i] + '" loaded');
            }
            for (var i = 0; i < wm.length; i++) {
                var path = wm[i];
                var ce = cache[path];
                var paths = '';
                if (ce.paths != null) {
                    for (var j = 0; j < ce.paths.length; j++) {
                        paths += (paths == '' ? '' : ', ') + (ce.dependencies[j] != null ? '!' : '') + ce.paths[j];
                    }
                }
                log(' "' + path + '"(' + paths + ') ' + ce.waiters.length + ' waiting callback(s)');
            }
        },
        lazyRequire : function(ids, callback) {
            if (arguments.length < 2) {
                return;
            }
            fullyQualifiedRequire('/?', ids, callback, true, true);
        },
        dirname : dirname,
        basename : basename,
        concatPath : concatPath,
        createRequire : createRequire,
        fullyQualifiedDefine : fullyQualifiedDefine,
        fullyQualifiedRequire : fullyQualifiedRequire
    });
    // global require function
    require = createRequire('');
})();
/*
 * prototype.js light.
 * From: Prototype JavaScript framework, version 1.7 (c) 2005-2010 Sam Stephenson
 * For details, see the Prototype web site: http://www.prototypejs.org/
 */
/*
 * In Edition 5, the following new properties are defined on built-in objects that exist in Edition 3:
 *  Object.getPrototypeOf,
 *  Object.getOwnPropertyDescriptor,
 *  Object.getOwnPropertyNames,
 *  Object.create,
 *  Object.defineProperty,
 *  Object.defineProperties,
 *  Object.seal,
 *  Object.freeze,
 *  Object.preventExtensions,
 *  Object.isSealed,
 *  Object.isFrozen,
 *  Object.isExtensible,
 *  Object.keys,
 *  Function.prototype.bind,
 *  Array.prototype.indexOf,
 *  Array.prototype.lastIndexOf,
 *  Array.prototype.every,
 *  Array.prototype.some,
 *  Array.prototype.forEach,
 *  Array.prototype.map,
 *  Array.prototype.filter,
 *  Array.prototype.reduce,
 *  Array.prototype.reduceRight,
 *  String.prototype.trim,
 *  Date.now,
 *  Date.prototype.toISOString,
 *  Date.prototype.toJSON.
 * See also http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/
 */
Array.prototype.clone = function() {
  return [].concat(this);
};
Array.prototype.toArray = Array.prototype.clone;
// The primary use of Array.from() is to obtain an actual Array object based on anything that could pass as an array.
// the predefined arguments reference within your functions
Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}
// extend Object
Object.extend = function(destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};
Object.extend(Object, {
  toJSON: function(object) {
    var type = typeof object;
    switch (type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }
    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (!Object.isUndefined(value))
        results.push(property.toJSON() + ': ' + value);
    }
    return '{' + results.join(', ') + '}';
  },
  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },
  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },
  isArray: function(object) {
    return object != null && typeof object == "object" &&
      'splice' in object && 'join' in object;
  },
  isFunction: function(object) {
    return typeof object == "function";
  },
  isString: function(object) {
    return typeof object == "string";
  },
  isNumber: function(object) {
    return typeof object == "number";
  },
  isUndefined: function(object) {
    return typeof object == "undefined";
  }
});
// extend Function
Object.extend(Function.prototype, {
  argumentNames: function() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  },
  bind: function() {
    if (arguments.length < 2 && (typeof arguments[0] == "undefined")) return this;
    var __method = this, args = Array.from(arguments), object = args.shift();
    return function() {
      return __method.apply(object, args.concat(Array.from(arguments)));
    }
  },
  wrap: function(wrapper) {
    var __method = this;
    return function() {
      return wrapper.apply(this, [__method.bind(this)].concat(Array.from(arguments)));
    }
  }
});
Object.extend(String.prototype, {
  camelize: function(prefix, suffix) {
    var parts = this.split('-');
    if (prefix) parts.unshift(prefix);
    if (suffix) parts.push(suffix);
    var len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },
  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },
  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },
  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },
  _empty: function() {
    return this == '';
  },
  trim: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },
  toJSON: function() {
    // TODO Fix quotes...
    return '\'' + this.toString().replace(/([\\'])/g, '\\$1') + '\'';
  }
});
Object.extend(Number.prototype, {
  _toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    var pad = '00000';
    while (pad.length + string.length < length) {
        pad += pad;
    }
    return pad.substr(0, length - string.length) + string;
  },
  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});
Object.extend(Array.prototype, {
  indexOf: function(object, from) {
    var len = this.length;
    from = from || 0;
    for (var i = from; i < len; i++) {
      if (this[i] === object) {
        return i;
      }
    }
    return -1;
  },
  _remove: function(object) {
    var index = 0;
    if (typeof object == 'number') {
      index = object;
    } else {
      index = this.indexOf(object);
      if (index < 0) {
        return null;
      }
    }
    return this.splice(index, 1)[0];
  },
  toJSON: function() {
    var results = [];
    for (var i = 0, length = this.length; i < length; i++) {
      var value = Object.toJSON(this[i]);
      if (!Object.isUndefined(value)) results.push(value);
    };
    return '[' + results.join(', ') + ']';
  }
});
Object.extend(Date.prototype, {
  // TODO Fix UTC
  toJSON: function() {
    return '"' + this.getUTCFullYear() + '-' +
      (this.getUTCMonth() + 1)._toPaddedString(2) + '-' +
      this.getUTCDate()._toPaddedString(2) + 'T' +
      this.getUTCHours()._toPaddedString(2) + ':' +
      this.getUTCMinutes()._toPaddedString(2) + ':' +
      this.getUTCSeconds()._toPaddedString(2) + 'Z"';
  }
});

/*!
 * 
 * Copyright (c) 2009 - 2013, javalikescript@free.fr (SPYL). All rights reserved.
 * JLS is licensed under LGPL, see the license.txt file that accompanied this code.
 * 
 */
/**
 * jls Base framework.
 * All the framework objects are created under the jls namespace.
 * The default objects are extended using prototype like behaviors.
 * 
 * @name jls
 * @namespace
 * @see jls.lang
 */

/**
 * @name jls.lang
 * @namespace Provides base classes for the jls language.
 * @see jls.lang.Exception
 * @see jls.lang.Logger
 */

// Add default option variable
if (typeof jlsOptions == 'undefined') {
    jlsOptions = {};
}

// Native namespace
var _native = {};

/*
 * Library boot
 */
_native.boot = {};
_native.boot.emptyFunction = function() {};
_native.boot.unsupportedFunction = function() {
    throw 'Unsupported native operation';
};
_native.boot.unsupportedClass = function() {
    throw 'Unsupported native class';
};
_native.boot.log = _native.boot.emptyFunction;
if ((typeof console != 'undefined') && ('log' in console)) {
    //_native.boot.log = console.log;
	_native.boot.log = function(msg) { // Chrome has a console but needs wrapping...
		console.log(msg);
	};
}
//_native.boot.log('Bootstrapping...');
// Find the default script path
(function() {
    var bootstrap = 'bootstrap.js';
    var path = '.'; // default
    var scriptTags = document.getElementsByTagName('script');
    for (var i = 0; i < scriptTags.length; i++) {
        var src = scriptTags[i].getAttribute('src');
        //_native.boot.log('script[' + i + '].src="' + src + '"');
        if (!src) {
            continue;
        }
        var j = src.lastIndexOf('/' + bootstrap);
        if ((j >= 0) && (j == src.length - bootstrap.length - 1)) {
            path = src.substring(0, src.length - bootstrap.length - 1);
            break;
        } else if (src == bootstrap) {
            path = '.';
            break;
        }
    }
    _native.boot.defaultScriptPath = path;
})();

// TODO use only one callback that take an object as argument that can get the response/throw an exception...
_native.boot.httpRequest = function(url, options) {
	this._url = url;
	this._options = {
	    method : 'post',
	    asynchronous : true,
	    contentType : 'application/x-www-form-urlencoded',
	    encoding : 'UTF-8',
	    parameters : '',
	    user : null,
	    password : null,
	    onComplete : _native.boot.emptyFunction,
        onException : _native.boot.emptyFunction,
        headers : null,
        mimeType : 'auto',
        context : null
	};
	if (options) {
		for (var key in options) {
			this._options[key] = options[key];
		}
	}
	this._xhr = _native.boot.httpRequest.newXHR();
};
_native.boot.httpRequest.newXHR = function() {
	try {
	    return new XMLHttpRequest()
	}
	catch (e) {}
	try {
	    return new ActiveXObject('Msxml2.XMLHTTP')
	}
	catch (e) {}
	try {
	    return new ActiveXObject('Microsoft.XMLHTTP')
	}
	catch (e) {}
	return false;
};
_native.boot.httpRequest.objectToQuery = function(obj) {
    var params = [];
    for (var key in obj) {
        var value = obj[key];
        var key = encodeURIComponent(key);
        if (typeof value == 'undefined') {
            params.push(key);
        } else if (value == null) {
            params.push(key + '=null');
        } else {
            params.push(key + '=' + encodeURIComponent(value));
        }
    }
    return params.join('&');
};
_native.boot.httpRequest.prototype.getStatus = function() {
	return this._xhr.status || 0;
};
_native.boot.httpRequest.prototype.succeed = function() {
    var status = this.getStatus();
    //if (this._xhr.responseText) return true;
    return ((status >= 200) && (status < 300)) || (status == 304);
};
_native.boot.httpRequest.prototype.getResponseText = function() {
    if (! this.succeed()) {
        throw 'Cannot get responseText, the HTTP request has failed (' + this.getStatus() + ')';
    }
    return this._xhr.responseText;
};
_native.boot.httpRequest.prototype.getResponseXML = function() {
    if (! this.succeed()) {
        throw 'Cannot get responseXML, the HTTP request has failed (' + this.getStatus() + ')';
    }
    var responseXML = this._xhr.responseXML;
    if (responseXML) {
        return responseXML;
    }
    throw 'No XML response available';
};
_native.boot.httpRequest.prototype.onStateChange = function() {
    var readyState = this._xhr.readyState;
    //_native.boot.log('_native.boot.xmlHttpRequest.onStateChange(' + readyState + ')');
    if (readyState != 4) { // Not completed
    	return;
    }
    try {
        this._options.onComplete.call(this, this._options.context);
    }
    catch (e) {
    	this._options.onException.call(this, e, this._options.context);
    }
    finally {
        this._options.onComplete = _native.boot.emptyFunction;
        this._xhr.onreadystatechange = _native.boot.emptyFunction;
    }
};
_native.boot.httpRequest.prototype.send = function() {
    //_native.boot.log('_native.boot.xmlHttpRequest.send(), ' + this._options.method + ': "' + this._url + '" ' + this._options.user + '/' + this._options.password);
    try {
        if ((this._options.user != null) && (this._options.password != null)) {
            this._xhr.open(this._options.method.toUpperCase(), this._url,
                    this._options.asynchronous, this._options.user,
                    this._options.password);
        } else {
            this._xhr.open(this._options.method.toUpperCase(), this._url,
                    this._options.asynchronous);
        }
        var self = this;
        this._xhr.onreadystatechange = function () {
            self.onStateChange();
        };
        var accept = 'text/javascript, text/html, application/xml, text/xml, */*';
        if (this._options.mimeType == 'auto') {
        	var extIndex = this._url.lastIndexOf('.');
        	var ext = extIndex > 0 ? this._url.substring(extIndex) : '';
        	switch (ext) {
        	case '.js':
        		accept = 'text/javascript, text/plain';
        		this._xhr.overrideMimeType('text/plain');
        		break;
        	}
        }
        var headers = {
                'Accept': accept
        };
        if (this._options.method == 'post') {
            headers['Content-type'] = this._options.contentType + (this._options.encoding ? '; charset=' + this._options.encoding : '');
        }
        for (var name in headers) {
            this._xhr.setRequestHeader(name, headers[name]);
        }
        var headers = this._options.headers;
        if (headers != null) {
            for (var name in headers) {
                this._xhr.setRequestHeader(name, headers[name]);
            }
        }
        var params = (typeof this._options.parameters == 'string') ? this._options.parameters : _native.boot.httpRequest.objectToQuery(this._options.parameters);
        var body = (this._options.method == 'post') ? (this._options.postBody || params) : null;
        this._xhr.send(body);
        /* Force Firefox to handle ready state 4 for synchronous requests */
        if (!this._options.asynchronous && this._xhr.overrideMimeType) {
            this.onStateChange();
        }
    }
    catch (e) {
        //_native.boot.log('_native.boot.xmlHttpRequest.send() "' + this._url + '" raised: ' + e);
        this._options.onException.call(this, e, this._options.context);
    }
	return this;
};


/*
 * Library core From "jls generateNativeLibraryAPI.js"
 */
_native.core = {};

_native.core.log = function(level, msg) {
    _native.boot.log(msg);
};
_native.core.logLevel = _native.boot.emptyFunction;
_native.core.exceptionHandler = _native.boot.emptyFunction; // alert
_native.core.sleep = _native.boot.emptyFunction;
_native.core._scriptPath = [];
_native.core._getResource = function(path, callback, sync, xml) {
    xml = xml || false;
    var scriptPaths = [].concat(_native.core._scriptPath);
    //_native.core.log(0, 'boot> _native.core._getResource("' + path + '", ' + xml + ') [' + scriptPaths + ']');
    var next;
    next = function() {
        if (scriptPaths.length == 0) {
            callback(null, 'Resource not found "' + path + '"');
            return;
        }
        var url = scriptPaths.shift() + '/' + path;
        //_native.core.log(0, 'boot> trying url "' + url + '"...');
        new _native.boot.httpRequest(url, {
                method :'get',
                asynchronous : ! sync,
                onException : function(e) {
                    callback(null, e);
                },
                onComplete : function() {
                    //_native.core.log(0, 'boot> onComplete() ' + this.getStatus() + ', ' + this.succeed());
                    if (this.succeed()) {
                        //_native.core.log(0, 'boot> Resource found "' + path + '", calling callback...');
                        callback(xml ? this.getResponseXML() : this.getResponseText());
                    } else {
                        if (this.getStatus() != 404) {
                            throw 'Unsupported status ' + this.getStatus() + ' for path "' + path + '"';
                        }
                        next();
                    }
                }
        }).send();
    };
    next();
};
_native.core.getResourceAsString = function(path, xml) {
    var res, err;
    _native.core._getResource(path, function(content, e) {
      res = content;
      err = e;
    }, true, xml);
    if ((res == null) || (err)) {
      throw err;
    }
    return res;
};
_native.core.getResourceAsByteArray = _native.boot.emptyFunction;
_native.core.evalScript = function(path, prefix, suffix) {
    //_native.core.log(0, '_native.core.evalScript("' + path + '")');
    var content = _native.core.getResourceAsString(path);
    if (prefix || suffix) {
        content = (prefix ? prefix : '') + content + (suffix ? suffix : '');
    }
    /* with (object) {
      eval(string);
    }*/
    //_native.core.log(0, 'eval(-->' + content + '<--)');
    var result = eval(content);
    //_native.core.log(0, 'eval() => ' + result);
    return result;
};

_native.core._evalScript = function(path, callback, sync, prefix, suffix) {
    try {
        // TODO Support async eval...
        var res = _native.core.evalScript(path, prefix, suffix);
        callback(res, null);
    } catch (e) {
        callback(null, e);
    }
};
_native.core.requireLibrary = _native.boot.unsupportedFunction;
_native.core.loadLibrary = _native.boot.unsupportedFunction;
_native.core.visitPaths = _native.boot.emptyFunction;
_native.core.gc = _native.boot.unsupportedFunction;
_native.core.dumpHead = _native.boot.unsupportedFunction;
_native.core.exit = _native.boot.unsupportedFunction;
_native.core.halt = _native.boot.unsupportedFunction;
_native.core.system = _native.boot.unsupportedFunction;
_native.core.signal = _native.boot.unsupportedFunction;
_native.core.raise = _native.boot.unsupportedFunction;
_native.core.getSignalCounters = _native.boot.unsupportedFunction;
_native.core.registerSignalMonitor = _native.boot.unsupportedFunction;
_native.core.handleSignal = _native.boot.unsupportedFunction;
_native.core.getEnv = _native.boot.unsupportedFunction;
_native.core.boot = _native.boot.unsupportedFunction;
_native.core.addPath = function(path) {
    // Check for duplicate
    var i = _native.core._scriptPath.length;
    while (--i >= 0) {
        if (_native.core._scriptPath[i] == path) {
            break;
        }
    }
    if (i < 0) {
        _native.core._scriptPath.push(path);
    }
};
_native.core.arguments = null;

_native.core.properties = { // From "jls systemProperties.js json"
  'browser' : navigator.appName,
  'browser.vendor' : navigator.userAgent, // TODO Use Crome, Gecko, IE, Opera, WebKit
  'browser.version' : navigator.appVersion,
  'browser.cookieEnabled' : navigator.cookieEnabled,
  'cpu.endian' : 'little',
  'cpu.pointer.size' : '4',
  'file.encoding' : 'UTF-8',
  'file.separator' : '/',
  'gui.toolkit' : 'html',
  'javascript.engine' : '?',
  'javascript.version' : '180',
  'jls.bootstrap.filename' : 'bootstrap.js',
  'jls.extension.path' : '',
  'jls.home' : '.',
  'jls.library.path' : '.',
  'jls.logger.logLevel' : 'warn',
  'jls.programname' : 'jls',
  'jls.script.path' : _native.boot.defaultScriptPath,
  'jls.vendor' : 'spyl',
  'jls.vendor.url' : 'http://javalikescript.free.fr/',
  'jls.version' : '0.6',
  'line.separator' : '\n',
  'os.architecture' : 'n/a',
  'os.hostname' : 'n/a',
  'os.release' : 'n/a',
  'os.sysname' : navigator.platform,
  'path.separator' : ';',
  'user.dir' : '.',
  'user.home' : '.',
  'user.language' : 'en',
  'user.name' : 'n/a',
  'user.region' : 'FR',
  'user.timezone' : 'n/a'
};
// Add browser detection facility
/*_native.core.properties['browser.id'] = window.opera ? 'Opera' :
	(window.attachEvent ? 'IE' :
		(navigator.userAgent.indexOf('AppleWebKit/') > -1 ? 'WebKit' :
			(navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 ? 'Gecko' : '?')));*/

_native.core.SIGINT = 2;
_native.core.SIGILL = 4;
_native.core.SIGFPE = 8;
_native.core.SIGSEGV = 11;
_native.core.SIGTERM = 15;
_native.core.SIGBREAK = 21;
_native.core.SIGABRT = 22;
_native.core.SIG_ERR = -1;
_native.core.SIG_DFL = 0;
_native.core.SIG_IGN = 1;
_native.core.SIG_USR = 2;
/*
 * Class _native.core.ByteArray
 */
_native.core.ByteArray = function(capacity, adoptable) {
    this._array = null;
    this._readOnly = false;
    if (typeof capacity == 'number') {
        if (typeof adoptable == 'number') {
            throw 'Unsupported native operation (new ByteArray from pointer)';
        }
        this._array = new Array(capacity);
    } else if (typeof capacity == 'string') {
        this._array = new Array(/*capacity.length * 2*/);
    	for (var i = 0; i < capacity.length; i++) {
    		var c = capacity.charCodeAt(i);
            this._array.push(c & 0xff);
            this._array.push((c >>> 8) & 0xff);
    	}
        //_native.core.log(0, 'ByteArray.construct(), this._array.length: ' + this._array.length);
        this._readOnly = ! adoptable;
    } else {
        throw 'Illegal argument type ' + (typeof capacity);
    }
};
_native.core.ByteArray.prototype.free = function() {
    this._array = null;
};
_native.core.ByteArray.prototype.size = function() {
    return this._array.length;
};
_native.core.ByteArray.prototype.put = function(offset, value) {
    this._array[offset] = value & 0xff;
};
_native.core.ByteArray.prototype.get = function(offset) {
    return this._array[offset];
};
_native.core.ByteArray.prototype.putString = _native.boot.unsupportedFunction; // TODO
_native.core.ByteArray.prototype.getString = _native.boot.unsupportedFunction; // TODO
_native.core.ByteArray.prototype.putChars = _native.boot.unsupportedFunction; // TODO
_native.core.ByteArray.prototype.getChars = function(at, length) {
    var s = '';
    for (var i = at; i < length; i++) {
        var c = this._array[i * 2] | (this._array[i * 2 + 1] << 8);
        s += String.fromCharCode(c);
    }
    return s;
};
_native.core.ByteArray.prototype.toNewChars = function(length) {
    return this.getChars(0, length);
};
_native.core.ByteArray.prototype.pointer = _native.boot.unsupportedFunction;
_native.core.ByteArray.prototype.memcpy = function(offset, byteArray, at, length) {
    //_native.core.log(0, 'ByteArray.memcpy(' + offset + ', ?, ' + at + ', ' + length + ')');
    for (var i = 0; i < length; i++) {
        this._array[offset + i] = byteArray._array[at + i];
    }
};
_native.core.ByteArray.prototype.setPointer = _native.boot.unsupportedFunction;
_native.core.ByteArray.prototype.resetPointer = _native.boot.unsupportedFunction;
_native.core.ByteArray.prototype.isReadOnly = function() {
    return this._readOnly;
};
/*
 * Unsupported classes
 */
_native.core.Thread = _native.boot.unsupportedClass;
_native.core.Lock = _native.boot.unsupportedClass;
_native.core.Monitor = _native.boot.unsupportedClass;
_native.core.Process = _native.boot.unsupportedClass;
_native.core.ProcessAttr = _native.boot.unsupportedClass;

// Update script path
if ('arguments' in jlsOptions) {
    _native.core.arguments = jlsOptions.arguments;
}
// Update properties
if ('properties' in jlsOptions) {
	for (var name in jlsOptions.properties) {
		_native.core.properties[name] = jlsOptions.properties[name];
	}
}
// Update script path
_native.core._scriptPath = _native.core.properties['jls.script.path'].split(/[;:]/);

// Load Prototype light
if (! (('from' in Array) && ('extend' in Object))) {
	_native.core.evalScript('plight.js');
}
// Load AMD
if (typeof require != 'function') {
	_native.core.evalScript('amdimpl.js');
}

require(['_AMD'], function(_AMD) {
    _AMD.setLogFunction(function(msg) {
        _native.core.log(4, msg);
    });
    _AMD.setEvalScriptFunction(_native.core._evalScript);
    if ('jls.logger.logLevel' in _native.core.properties) {
    	_AMD.lazyRequire(['jls/lang/Logger'], function(Logger) {
            Logger.getInstance().setLogLevel(_native.core.properties['jls.logger.logLevel']);
        });
    }
});

//_native.boot.log('... Bootstrapping done');

require(['_AMD'], function(_AMD) {
  _AMD.enableDefine();
  _AMD.enableDeferredLoading();
});
define('jls/gui/BorderLayout', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/gui/FlowLayout'
], function (
  Class,
  Exception,
  Logger,
  FlowLayout
) {

var BorderLayout;
/**
 * @name jls.gui.BorderLayout
 * @augments jls.gui.Layout
 * @class This class represents a border layout.
 * Child must define: region, splitter
 */
BorderLayout = Class.create(FlowLayout,
{
    initialize : function($super, element) {
        $super(element);
        this._regions = {};
    	this._splitSize = 0;
        this._borderLeft = 0;
        this._borderRight = 0;
        this._borderTop = 0;
        this._borderBottom = 0;
        this._isResizing = false;
        this._onMouseMove = this.onMouseMove.bind(this);
        this._onMouseOut = this.stopResize.bind(this);
        this._mouseOrigin = 0;
        this._borderOrigin = 0;
        this._resizingRegion = null;
    },
    startResize : function(event) {
    	if ((this._isResizing) || (this._splitSize == 0)) {
    		return;
    	}
        var cSize = this.getElement().getClientSize();
        var cWidth = cSize[0];
        var cHeight = cSize[1];
    	//jls.logger.trace('BorderLayout startResize: ' + cWidth + 'x' + cHeight + ' ' + this._borderLeft + '-' + this._borderRight + ', ' + this._borderTop + '-' + this._borderBottom);

    	if (this.isRegionSplit('top') && (event.clientY >= this._borderTop) && (event.clientY <= this._borderTop + this._splitSize)) {
    		this._resizingRegion = 'top';
            this._borderOrigin = this._borderTop;
    		this._mouseOrigin = event.clientY;
    	} else if (this.isRegionSplit('bottom') && (event.clientY >= cHeight - this._borderBottom - this._splitSize) && (event.clientY <= cHeight - this._borderBottom)) {
    		this._resizingRegion = 'bottom';
            this._borderOrigin = this._borderBottom;
    		this._mouseOrigin = event.clientY;
    	} else if (this.isRegionSplit('left') && (event.clientX >= this._borderLeft) && (event.clientX <= this._borderLeft + this._splitSize)) {
    		this._resizingRegion = 'left';
            this._borderOrigin = this._borderLeft;
    		this._mouseOrigin = event.clientX;
    	} else if (this.isRegionSplit('right') && (event.clientX >= cWidth - this._borderRight - this._splitSize) && (event.clientX <= cWidth - this._borderRight)) {
    		this._resizingRegion = 'right';
            this._borderOrigin = this._borderRight;
    		this._mouseOrigin = event.clientX;
    	} else {
    		return;
    	}
    	this._isResizing = true;
    	this.getElement().observe('mousemove', this._onMouseMove);
        this.getElement().observe('mouseout', this._onMouseOut);
    },
    onMouseMove : function(event) {
    	Logger.getInstance().trace('BorderLayout mousemove: ' + event.clientX + 'x' + event.clientY + ', region: ' + this._resizingRegion);
    	switch (this._resizingRegion) {
    	case 'top':
    		this._regions[this._resizingRegion].getStyle().setProperty('height', this._borderOrigin + event.clientY - this._mouseOrigin);
    		break;
    	case 'bottom':
    		this._regions[this._resizingRegion].getStyle().setProperty('height', this._borderOrigin + this._mouseOrigin - event.clientY);
    		break;
    	case 'left':
    		this._regions[this._resizingRegion].getStyle().setProperty('width', this._borderOrigin + event.clientX - this._mouseOrigin);
    		break;
    	case 'right':
    		this._regions[this._resizingRegion].getStyle().setProperty('width', this._borderOrigin + this._mouseOrigin - event.clientX);
    		break;
    	default:
    		return;
    	}
    	this.updateRegionStyle();
    	this.getElement().update();
    },
    stopResize : function(event) {
    	//jls.logger.trace('BorderLayout stopResize()');
    	if (this._isResizing) {
        	this.getElement().unobserve('mousemove', this._onMouseMove);
            this.getElement().unobserve('mouseout', this._onMouseOut);
            this._isResizing = false;
    	}
    },
    onCreate : function() {
        this.getElement().observe('mousedown', function(event) {
        	//jls.logger.trace('BorderLayout mousedown: ' + event.clientX + 'x' + event.clientY);
        	event.target.getLayout().startResize(event);
        });
        this.getElement().observe('mouseup', function(event) {
        	//jls.logger.trace('BorderLayout mouseup: ' + event.clientX + 'x' + event.clientY);
        	event.target.getLayout().stopResize(event);
        });
    },
    isRegionSplit : function(region) {
    	return (region in this._regions) && (this._regions[region].getStyle().getPropertyValue('splitter') == 'true');
    },
    getRegionStylePropertyValue : function(region, key, defaultValue) {
        if (region in this._regions) {
        	var value = this._regions[region].getStyle().getPropertyValue(key);
            if (value != null) {
            	return value;
            }
        }
        return defaultValue || 0;
    },
    updateRegionStyle : function() {
    	this._splitSize = this.getElement().getStyle().getPropertyValue('splitSize') || 0;
      	this._borderLeft = this.getRegionStylePropertyValue('left', 'width', 0);
      	this._borderRight = this.getRegionStylePropertyValue('right', 'width', 0);
      	this._borderTop = this.getRegionStylePropertyValue('top', 'height', 0);
      	this._borderBottom = this.getRegionStylePropertyValue('bottom', 'height', 0);
        for (var r in this._regions) {
	    	switch (r) {
	    	case 'center':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: null,
	    			left: this._borderLeft + ('left' in this._regions ? this._splitSize : 0),
	    			right: this._borderRight + ('right' in this._regions ? this._splitSize : 0),
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'top':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: this._borderTop,
	    			left: 0,
	    			right: 0,
	    			top: 0,
	    			bottom: null,
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'bottom':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: this._borderBottom,
	    			left: 0,
	    			right: 0,
	    			top: null,
	    			bottom: 0,
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'left':
	    		this._regions[r].getStyle().setProperties({
	    			width: this._borderLeft,
	    			height: null,
	    			left: 0,
	    			right: null,
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'right':
	    		this._regions[r].getStyle().setProperties({
	    			width: this._borderRight,
	    			height: null,
	    			left: null,
	    			right: 0,
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	}
    	}
    },
    onAddChild : function($super, child) {
    	var region = child.getStyle().getPropertyValue('region');
    	// check region
    	if (region == null) {
    		throw new Exception('The region is not defined');
    	}
    	if (region in this._regions) {
    		throw new Exception('The region "' + region + '" is duplicated');
    	}
    	this._regions[region] = child;
    	this.updateRegionStyle();
        $super(child);
    },
    onRemoveChild : function(child) {
    	var region = child.getStyle().getPropertyValue('region');
    	if (region != null) {
        	delete this._regions[region];
        	this.updateRegionStyle();
    	}
        $super(child);
    }
});

return BorderLayout;
});
define('jls/gui/CardLayout', ['jls/lang/Class', 'jls/gui/Layout', 'jls/gui/FlowLayout'], function (Class, Layout, FlowLayout) {

var CardLayout;
/**
 * @name jls.gui.CardLayout
 * @augments jls.gui.Layout
 * @class This class represents a card layout. The children can have the same size and only one is visible.
 */
CardLayout = Class.create(Layout,
{
    initialize : function($super, element) {
    	this._selectedIndex = 0;
        $super(element);
    },
    /*onCreate : function() {
        var childCount = this._element.getChildCount();
        for (var i = 0; i < childCount; i++) {
            var child = this._element.getChild(i);
            child.getStyle().setProperty('visibility', i == this._selectedIndex ? 'visible' : 'hidden');
        }
    },*/
    show : function(index) {
    	//jls.logger.warn('show(' + index + ')');
    	if ((this._selectedIndex >= 0) && (this._selectedIndex < this._element.getChildCount())) {
        	this._element.getChild(this._selectedIndex).getStyle().setProperty('visibility', 'hidden');
    	}
    	this._selectedIndex = index;
    	this._element.getChild(this._selectedIndex).getStyle().setProperty('visibility', 'visible');
    },
    onUpdate : function() {
        var cSize = this._element.getClientSize();
        var cWidth = cSize[0];
        var cHeight = cSize[1];
        var cStyle = this._element.getStyle();
        var hGap = cStyle.getPropertyValue('hGap') || 0;
        var vGap = cStyle.getPropertyValue('vGap') || 0;
        // TODO Only resize the selected child?
        var childCount = this._element.getChildCount();
        for (var i = 0; i < childCount; i++) {
            var child = this._element.getChild(i);
            //child.getStyle().setProperty('visibility', i == this._selectedIndex ? 'visible' : 'hidden');
            FlowLayout.place(child, hGap, vGap, cWidth - hGap * 2, cHeight - vGap * 2);
        }
    },
    /*onRemoveChild : function($super, child) {
        $super(child);
    },*/
    onAddChild : function($super, child) {
        /*if (child.getStyle().getPropertyValue('visibility') == 'visible') {
            this.show(this._element.getChildCount() - 1);
            //this._selectedIndex = this._element.getChildCount() - 1;
        }*/
        child.getStyle().setProperty('visibility', ((this._element.getChildCount() - 1) == this._selectedIndex) ? 'visible' : 'hidden');
        $super(child);
    }
});

return CardLayout;
});
define('jls/gui/Element', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/gui/Style',
  'jls/gui/Layout',
  'jls/util/EventBroker',
  'jls/util/Resource'
], function (
  Class,
  Exception,
  Logger,
  Style,
  Layout,
  EventBroker,
  Resource
) {

var Element;
/**
 * @namespace Provides graphical user interface.
 * @see jls.gui.Element
 * @name jls.gui
 */

Element = Class.create( /** @lends jls.gui.Element.prototype */
{
    /**
     * Creates an element.
     * 
     * @param {Object} [parameters] The element parameters that is the description of the element to create.
     * @param {Object} [parameters.attributes] The element attributes.
     * @param {Object} [parameters.style] The style properties for this element.
     * @param {Array} [parameters.children] The element children.
     * @param {Object} [parameters.events] The event description to observe on this element.
     * @param {jls.util.EventBroker} [parameters.broker] The event broker associated with this element.
     * @param {jls.util.Resource} [parameters.resource] The resource associated with this element.
     * @param {jls.gui.Element} [parent] The parent.
     * @constructs
	 * @class This class represents a graphical element.
     */
    initialize : function(parameters, parent) {
        parameters = parameters || {};
        this._children = [];
        this._parent = parent || null;
        this._eventsHandlers = {};
        this._preAttributes = {};
        this._eventBroker = parameters.broker || null;
        this._resource = parameters.resource || null;
        // Default parameters
        this._title = undefined;
        this._id = undefined;
        // Create style
        this._style = new Style(parameters.style);
        // Register style handler
    	this.getStyle().setHandler(this.onStyleChange.bind(this));
        if (this._parent) {
        	this._style.setParent(this._parent.getStyle());
        }
        // Create default layout
    	this._layout = this.createDefaultLayout();
    	// Set bounds
        this._x = this._y = this._w = this._h = 0;
        if (parameters.style) {
            this._x = parameters.style.left;
            this._y = parameters.style.top;
            this._w = parameters.style.width;
            this._h = parameters.style.height;
        }
        // Preset the attributes
        if (parameters.attributes) {
            this.setAttributes(parameters.attributes);
        }
        // Create the concrete element
        this.onCreate();
        // Add this element to its parent
        if (this._parent != null) {
            this._parent.addChild(this);
        }
        // Set the attributes
        var preAttributes = this._preAttributes;
        this._preAttributes = null;
        this.setAttributes(preAttributes);
        // Activate the style properties
        this._style.activate();
        // Add the children
        if (Object.isArray(parameters.children)) {
            this.addChildren(parameters.children);
        }
        // Add the events
        if (parameters.events) {
            for (var type in parameters.events) {
                this.observe(type, parameters.events[type]);
            }
        }
        if (this._layout != null) {
        	this._layout.onCreate();
        }
    },
    onCreate : Class.emptyFunction,
    getParent : function() {
        return this._parent;
    },
    getEventBroker : function() {
        if (this._eventBroker != null) {
            return this._eventBroker;
        }
        if (this._parent != null) {
            var eb = this._parent.getEventBroker();
            if (eb != null) {
                return eb;
            }
        }
        return Element.DEFAULT_EVENT_BROKER;
    },
    setEventBroker : function(eventBroker) {
        this._eventBroker = eventBroker;
    },
    getResource : function() {
        if (this._resource != null) {
            return this._resource;
        }
        if (this._parent != null) {
            var res = this._parent.getResource();
            if (res != null) {
                return res;
            }
        }
        return Element.DEFAULT_RESOURCE;
    },
    setResource : function(resource) {
        this._resource = resource;
    },
    getResourceLabel : function(text) {
        if ((typeof text != 'string') || (! text.startsWith('#'))) {
            return text;
        }
        return this.getResource().get(text.substring(1));
    },
    /*
     * Attributes
     */
    /**
     * Sets an attribute.
     *
     * @param {String} key The attribute key.
     * @param {String} value The attribute value.
     */
    setAttribute : function(key, value) {
        if (this._preAttributes) {
            //Logger.getInstance().trace('pre-setAttribute(' + key + ', "' + value + '")');
        	if (typeof value != 'undefined') {
        		this._preAttributes[key] = value;
        	} else {
            	delete this._preAttributes[key];
        	}
        	return this;
        }
        //Logger.getInstance().trace('setAttribute(' + key + ', "' + value + '")');
        /* look for a setter method in this */
        var setter = key.camelize('set');
        //Logger.getInstance().trace('setter: "' + setter + '"');
        if (Object.isFunction(this[setter])) {
            this[setter](value);
            return this;
        }
        this.onSetAttribute(key, value);
        return this;
    },
    onSetAttribute : Class.emptyFunction,
    /**
     * Returns an attribute.
     *
     * @param {String} key The attribute key.
     * @returns {String} The attribute value.
     */
    getAttribute : function(key) {
        //Logger.getInstance().trace('getAttribute(' + key + ')');
        if (this._preAttributes) {
        	var value = null;
            if (key in this._preAttributes) {
            	value = this._preAttributes[key];
            	delete this._preAttributes[key];
            }
            return value;
        }
        /* look for a getter method in this */
        var getter = key.camelize('get');
        //Logger.getInstance().trace('getter: "' + getter + '"');
        if (Object.isFunction(this[getter])) {
            return this[getter]();
        }
        return this.onGetAttribute(key);
    },
    onGetAttribute : Class.emptyFunction,
    /**
     * Sets some attributes.
     *
     * @param {Object} attributes The attributes to set.
     */
    setAttributes : function(attributes) {
        for (var k in attributes) {
            this.setAttribute(k, attributes[k]);
        }
        return this;
    },
    /**
     * Returns the element style.
     * 
     * @returns {jls.gui.Style} The element style.
     */
    getStyle : function() {
        return this._style;
    },
    // onStyleChange(key, oldValue, newValue)
    onStyleChange : Class.emptyFunction,
    /**
     * Returns the layout associated with this element.
     * 
     * @returns {jls.gui.Layout} The element layout or null if there is no layout.
     */
    getLayout : function() {
        return this._layout;
    },
    createDefaultLayout : function() {
        return null;
    },
    /**
     * Sets the layout for this element.
     * 
     * @param {jls.gui.Layout} layout The layout to associate to this element.
     */
    setLayout : function(layout) {
    	if (layout != null) {
    		if (typeof layout == 'string') {
    			var layoutClass = require(layout);
    			if (layoutClass == null) {
    			    throw new Exception('Invalid layout (' + layout + ')');
    			}
    			layout = new layoutClass(this);
    		} else if (layout instanceof Layout) {
    			layout.setElement(this);
    		} else {
    			throw new Exception('Invalid layout');
    		}
    	}
        this._layout = layout;
        return this;
    },
    /*
     * Element hierarchy
     * TODO Element should be split in Element/Container
     */
    /**
     * Adds a child.
     *
     * @param {Object} child The child to add.
     */
    addChild : function(child) {
        if (child instanceof Element) {
            //Logger.getInstance().trace('addChild for jls.gui.Element');
            // TODO if the child already have a parent remove it
            child._parent = this;
            this._children.push(child);
        } else if ((typeof child == 'object') && ('classname' in child)) {
            //Logger.getInstance().trace('addChild for object');
            child = Element.create(child, this);
            return child;
        } else {
            throw new Exception('don\'t know how to add "' + (typeof child) + '" child type');
        }
        if (this._layout != null) {
        	this._layout.onAddChild(child);
        }
    	this.onAddChild(child);
        return child;
    },
    onAddChild : Class.emptyFunction,
    /**
     * Adds children.
     *
     * @param {Object} children The children to add.
     */
    addChildren : function(children) {
        for (var i = 0; i < children.length; i++) {
            this.addChild(children[i]);
        }
        return this;
    },
    insertChild : function(index, child) {
        Logger.getInstance().trace('insertChild(' + index + ')');
        if (! (child instanceof Element)) {
            throw new Exception('don\'t know how to insert "' + (typeof child) + '" child type');
        }
        if ((index < 0) || (index > this._children.length)) {
            throw new Exception('index out of bounds');
        }
        if (index == this._children.length) {
            return this.addChild(child);
        }
        child._parent = this;
        this._children.splice(index, 0, child);
        if ((this._layout != null) && ('onInsertChild' in this._layout)) {
            this._layout.onInsertChild(index, child);
        }
        this.onInsertChild(index, child);
        return child;
    },
    onInsertChild : Class.emptyFunction,
    getChildIndex : function(child) {
        var index = this._children.length - 1;
        for (; (index >= 0) && (this._children[index] !== child); index--);
        return index;
    },
    /**
     * Removes a child.
     *
     * @param {Object} child The child to remove.
     */
    removeChild : function(child) {
        var index = 0;
        if (typeof child == 'number') {
            index = child;
            child = this._children[index];
        } else {
            index = this.getChildIndex(child);
            if (index < 0) {
                throw new Exception('Child not found');
            }
        }
        this._children.splice(index, 1);
        //Logger.getInstance().trace('removeChild(' + index + ')');
        if (child instanceof Element) {
        	child._parent = null;
        	child.onDestroy();
        }
        if (this._layout != null) {
        	this._layout.onRemoveChild(child);
        }
        this.onRemoveChild(child);
        return child;
    },
    onRemoveChild : Class.emptyFunction,
    /**
     * Removes all children.
     *
     */
    removeChildren : function() {
        for (var i = this._children.length - 1; i >= 0; i--) {
            this.removeChild(i);
        }
        return this;
    },
    /**
     * Returns all children.
     *
     */
    getChildren : function() {
        return this._children;
    },
    getChildCount : function() {
        return this._children.length;
    },
    /**
     * Gets a child.
     *
     * @param {Number} index The child index.
     * @returns {Object} The child.
     */
    getChild : function(index) {
        return this._children[index];
    },
    /**
     * Destroys this element.
     *
     */
    destroy : function() {
        //Logger.getInstance().trace('destroy()');
        if (this.getParent() != null) {
            this.getParent().removeChild(this);
        } else {
            this.onDestroy();
        }
        return this;
    },
    onDestroy : Class.emptyFunction,
    /*
     * Event.
     * TODO Move this in a specialized event broker class.
     */
    dispatch : function(event) {
        if (event.type in this._eventsHandlers) {
            var handlers = this._eventsHandlers[event.type];
            for (var i = handlers.length - 1; i >= 0; i--) {
                handlers[i](event);
            }
        }
        return this;
    },
    onStartObserving: Class.emptyFunction,
    onStopObserving: Class.emptyFunction,
    /**
     * Register an event handler.
     *
     * @param {String} type The event type to observe.
     * @param {Function} handler The handler to register.
     * @returns {Function} The handler.
     */
    observe: function(type, handler) {
        if (Object.keys(this._eventsHandlers).length == 0) {
            this.onStartObserving();
        }
        if (! (type in this._eventsHandlers)) {
            this._eventsHandlers[type] = [];
        }
        if (typeof handler == 'string') {
            // TODO Use the event broker directly
            //handler = this.getEventBroker().callback(handler);
        	var name = handler;
        	var self = this;
        	handler = function(message) {
        		self.getEventBroker().publish(name, message);
        	};
        }
        this._eventsHandlers[type].push(handler);
        return handler;
    },
    isObserving: function(type) {
        return type && (type in this._eventsHandlers);
    },
    /**
     * Unregister an event handler.
     *
     * @param {String} type The event type to unregister.
     * @param {Function} [handler] The handler to unregister.
     * @returns {Array} The removed handlers.
     */
    unobserve: function(type, handler) {
        var removed = [];
        if (type in this._eventsHandlers) {
            if (handler) {
                var handlers = this._eventsHandlers[type];
                for (var i = handlers.length - 1; i >= 0; i--) {
                    if (handler === handlers[i]) {
                        removed.push(handlers[i]);
                        handlers.splice(i, 1);
                    }
                }
                if (handlers.length == 0) {
                    delete this._eventsHandlers[type];
                }
            } else {
                delete this._eventsHandlers[type];
            }
        }
        if (Object.keys(this._eventsHandlers).length == 0) {
            this.onStopObserving();
        }
        return removed;
    },
    /*
     * Update
     */
    // TODO doLayout ?
    update : function() {
        if (this._layout != null) {
        	this._layout.onUpdate();
        }
    },
    /*
     * Default attributes
     */
    getX : function() {
        return this._x;
    },
    getY : function() {
        return this._y;
    },
    getW : function() {
        return this._w;
    },
    getH : function() {
        return this._h;
    },
    getBounds : function() {
        return [this._x, this._y, this._w, this._h];
    },
    setBounds : function(rect) {
        this._x = rect[0];
        this._y = rect[1];
        this._w = rect[2];
        this._h = rect[3];
        return this;
    },
    getLocation : function() {
        return [this._x, this._y];
    },
    setLocation : function(point) {
        this._x = point[0];
        this._y = point[1];
        return this;
    },
    getSize : function() {
        return [this._w, this._h];
    },
    setSize : function(dim) {
        this._w = dim[0];
        this._h = dim[1];
        return this;
    },
    getClientOffset : function() {
        return [0, 0];
    },
    /*getClientBounds : function() {
        return this.getBounds();
    },*/
    getClientSize : function() {
        return this.getSize();
    },
    getTitle : function() {
        return this._title;
    },
    setTitle : function(title) {
        this._title = title;
        return this;
    },
    getId : function() {
        return this._id;
    },
    setId : function(id) {
        this._id = id;
        return this;
    },
    getById : function(id) {
        var children = this.getChildren();
        for ( var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.getAttribute('id') == id) {
                return child;
            }
        }
        for ( var i = 0; i < children.length; i++) {
            var e = children[i].getById(id);
            if (e != null) {
                return e;
            }
        }
        return null;
    }
});

Object.extend(Element,
{
    DEFAULT_EVENT_BROKER: EventBroker.DEFAULT,
    DEFAULT_RESOURCE: Resource.DEFAULT,
    create : function(parameters, parent) {
        if (!(parameters && parameters.classname)) {
            throw new Exception('Invalid parameters, the classname property is required');
        }
        var classname = parameters.classname;
        var clazz = require(classname);
        if (clazz == null) {
            throw new Exception('Fail to require "' + classname + '"');
        }
        return new clazz(parameters, parent);
    },
    wrap : function(clazz, object) {
        if (object instanceof clazz) {
            return object;
        }
        if ((typeof object == 'object') && ('classname' in object)) {
            object = Element.create(object);
            if (object instanceof clazz) {
                return object;
            }
        }
        throw new Exception('Invalid object, cannot wrap with specified class');
    }
});

return Element;
});
define('jls/gui/Event', ['jls/lang/Class'], function (Class) {

var Event;
Event = Class.create( /** @lends jls.gui.Event.prototype */
{
    //bubbles:  	Returns a Boolean value that indicates whether or not an event is a bubbling event
    //cancelable: 	Returns a Boolean value that indicates whether or not an event can have its default action prevented
    //currentTarget: 	Returns the element whose event listeners triggered the event
    //eventPhase: 	Returns which phase of the event flow is currently being evaluated
    /**
     * Creates an event.
     * 
     * @param {String} type The event type.
     * @constructs
	 * @class This class represents a graphical event.
     */
    initialize : function(type, target) {
        this.type = type;
        this.target = target;
        this.timeStamp = 0;
    },
    //relatedTarget: 	Returns the element related to the element that triggered the event
    setMouse : function(button, clientX, clientY, screenX, screenY) {
        this.button = button;
        this.clientX = clientX;
        this.clientY = clientY;
        this.screenX = screenX;
        this.screenY = screenY;
        return this;
    },
    setKeyModifiers : function(altKey, ctrlKey, metaKey, shiftKey) {
        this.altKey = altKey;
        this.ctrlKey = ctrlKey;
        this.metaKey = metaKey;
        this.shiftKey = shiftKey;
        return this;
    },
    // Internet Explorer uses event.keyCode to retrieve the character that was pressed and Netscape/Firefox/Opera uses event.which
    setKey : function(which) {
        this.which = which;
        return this;
    },
    stopPropagation : function() {
        return this;
    },
    preventDefault : function() {
        return this;
    }
});

Object.extend(Event, /** @lends jls.gui.Event */
{
    MOUSE_BUTTON_LEFT : 0,
    MOUSE_BUTTON_MIDDLE : 1,
    MOUSE_BUTTON_RIGHT : 2,
    createMouseEvent : function(type, target, button, clientX, clientY, screenX, screenY) {
        var event = new Event(type, target);
        event.setMouse(button, clientX, clientY, screenX, screenY);
        return event;
    },
    createKeyEvent : function(type, target, which) {
        var event = new Event(type, target);
        event.setKey(which);
        return event;
    }
});


return Event;
});
define('jls/gui/FlowLayout', ['jls/lang/Class', 'jls/lang/Exception', 'jls/gui/Layout'], function (Class, Exception, Layout) {

var FlowLayout;
/**
 * @name jls.gui.FlowLayout
 * @augments jls.gui.Layout
 * @class This class represents a flow layout. The children can have an absolute or a relative position,
 * these two layouts does not interfer, overlapping must be fix using z-index.
 * <p>Child style position: <b>absolute</b>.
 * The absolute position is defined using a combination of the following style options: left, right, top, bottom, width, height.
 * If some options are conflicting each other then the last ones are ignored,
 * the conflicting options and their priorities are: width, left, right and height, top, bottom.</p>
 * <p>Child style position: <b>relative</b>.
 * Children are positioned in a flow depending on the following style options:
 * direction (ltr, rtl), textAlign (left, right, center, justify), verticalAlign (top, middle, bottom).</p>
 */
FlowLayout = Class.create(Layout,
{
    onUpdate : function() {
    	/*
    	 * update relative children then absolute
    	 */
    	// TODO use several width: px, %, weight
        var cSize = this._element.getClientSize();
        var cWidth = cSize[0];
        var cHeight = cSize[1];
    	//jls.lang.System.out.println('update(): [' + cWidth + ', ' + cHeight + ']');
        var cStyle = this._element.getStyle();
        var hGap = cStyle.getPropertyValue('hGap') || 0;
        var vGap = cStyle.getPropertyValue('vGap') || 0;
        var lines = [];
        var lineWeight = 0;
        var lineHeight = 0;
        var lineWidth = 0;
        var lineElements = [];
        var globalHeight = 0;
        var globalWidth = 0;
        var childCount = this._element.getChildCount();
        // Special case for only one child without layout styles (left, top, width, height)
        if (childCount == 1) {
            var child = this._element.getChild(0);
            var style = child.getStyle();
            if ((style.getPropertyValue('width') == null) && (style.getPropertyValue('height') == null) &&
                (style.getPropertyValue('left') == null) && (style.getPropertyValue('top') == null))
            {
                FlowLayout.place(child, hGap, vGap, cWidth - hGap * 2, cHeight - vGap * 2);
                return;
            }
        }
        for (var i = 0; i < childCount; i++) {
            var child = this._element.getChild(i);
            var style = child.getStyle();
            var position = style.getPropertyValue('position');
            var rawWidth = style.getPropertyValue('width');
            var rawHeight = style.getPropertyValue('height');
            if (position == 'relative') {
                var weight = FlowLayout.getWeight(rawWidth);
                var width = weight > 0 ? 0 : FlowLayout.computeSize(rawWidth, cWidth);
                var height = FlowLayout.computeSize(rawHeight, cHeight, childCount);
            	/*
            	 * TODO Manage display:block styles
            	 */
                if ((style.getPropertyValue('clear') == 'left') ||
                    ((lineElements.length > 0) && (lineElements[lineElements.length - 1].element.getStyle().getPropertyValue('clear') == 'right')) ||
                    (lineWidth + (lineElements.length > 0 ? hGap : 0) + width > cWidth))
                {
                    globalHeight += vGap;
                	// new line
                	lines.push({
                		weight: lineWeight,
                		width: lineWidth,
                		height: lineHeight,
                		elements: lineElements
                	});
                	// compute global
                    if (lineWidth > globalWidth) {
                    	globalWidth = lineWidth;
                    }
                    globalHeight += lineHeight;
                	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
                    // reset
                    lineElements = [];
                    lineWeight = 0;
                	lineWidth = 0;
                    lineHeight = 0;
                }
                lineWidth += hGap;
                lineElements.push({
            		width: width,
            		height: height,
            		rawWidth: rawWidth,
            		rawHeight: rawHeight,
            		element: child
                });
                lineWeight += weight;
                lineWidth += width;
                if (height > lineHeight) {
                	lineHeight = height;
                }
            	//jls.lang.System.out.println('child[' + i + ']: ' + width + 'x' + height + ', ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
            } else if (position == 'absolute') {
                var width = FlowLayout.computeSize(rawWidth, cWidth);
                var height = FlowLayout.computeSize(rawHeight, cHeight);
                var x = 0;
                var y = 0;
                var w = 0;
                var h = 0;
                var left = FlowLayout.computeSize(style.getPropertyValue('left'), cWidth);
                var top = FlowLayout.computeSize(style.getPropertyValue('top'), cHeight);
                var right = FlowLayout.computeSize(style.getPropertyValue('right'), cWidth);
                var bottom = FlowLayout.computeSize(style.getPropertyValue('bottom'), cHeight);
                // compute horizontal
            	if (width != null) {
            		w = width;
            	} else if ((left != null) && (right != null)) {
            		w = cWidth - right - left;
            	} else {
            		w = 10; // TODO auto
            	}
            	if (left != null) {
            		x = left;
            	} else if (right != null) {
            		x = cWidth - right - w;
            	} else {
            		x = 0; // default
            	}
                // compute vertical
            	if (height != null) {
            		h = height;
            	} else if ((top != null) && (bottom != null)) {
            		h = cHeight - bottom - top;
            	} else {
            		h = 10; // TODO auto
            	}
            	if (top != null) {
            		y = top;
            	} else if (right != null) {
            		y = cHeight - bottom - h;
            	} else {
            		y = 0; // default
            	}
            	FlowLayout.place(child, x, y, w, h);
            } else {
            	throw new Exception('Invalid position: "' + position + '"');
            }
        }
        if (lineElements.length > 0) {
            if (lines.length > 0) {
                globalHeight += vGap;
            }
        	// new line
        	lines.push({
                weight: lineWeight,
                width: lineWidth,
        		height: lineHeight,
        		elements: lineElements
        	});
        	// compute global
            if (lineWidth > globalWidth) {
            	globalWidth = lineWidth;
            }
            globalHeight += lineHeight;
        	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
        }
    	//jls.lang.System.out.println('update(): ' + cWidth + 'x' + cHeight + ', ' + globalWidth + 'x' + globalHeight);
        var lineCount = lines.length;
        if (lineCount > 0) {
            var direction = cStyle.getPropertyValue('direction');
            var verticalPosition = cStyle.getPropertyValue('verticalPosition');
            var textAlign = cStyle.getPropertyValue('textAlign');
            var verticalAlign = cStyle.getPropertyValue('verticalAlign');
            var y = vGap;
            if (verticalPosition == 'middle') {
            	y = Math.floor((cHeight - globalHeight) / 2);
            } else if (verticalPosition == 'bottom') {
            	y = cHeight - globalHeight;
            }
            for (var i = 0; i < lineCount; i++) {
            	var line = lines[i];
                var x = hGap;
                var lineWidth = line.weight > 0 ? (cWidth - hGap * 2) : line.width;
                if (textAlign == 'center') {
                	x = Math.floor((cWidth - lineWidth) / 2);
                } else if (textAlign == 'right') {
                	x = cWidth - lineWidth;
                }
            	lineElements = line.elements;
                if (direction == 'rtl') {
                    for (var j = lineElements.length - 1; j >= 0; j--) {
                    	var e = lineElements[j];
                        var w;
                        var h = e.height;
                        if (line.weight > 0) {
                            w = FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
                        } else {
                            w = e.width;
                        }
                    	FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
                    	x += w + hGap;
                    }
                } else {
                    for (var j = 0; j < lineElements.length; j++) {
                    	var e = lineElements[j];
                        var w;
                        var h = e.height;
                        if ((line.weight > 0) && (e.width == 0)) {
                            w = FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
                            //jls.lang.System.out.println('computeSize(' + e.rawWidth + ', ' + cWidth + ', ' + line.weight + ') => ' + w);
                        } else {
                            w = e.width;
                        }
                    	FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
                    	x += w + hGap;
                    }
                }
                y += line.height + vGap;
            }
        }
    }
});

Object.extend(FlowLayout,
{
    isWeight : function(value) {
        return value.charAt(value.length - 1) == 'w';
    },
    getWeight : function(value) {
        if ((typeof value != 'string') || (value.length < 2)) {
            return 0;
        }
        value = value.match(/([0-9]+)(.*)/);
        return value[2] == 'w' ? parseInt(value[1]) : 0;
        /*var w = value[2] == 'w' ? parseInt(value[1]) : 0;
        jls.lang.System.out.println('getWeight(' + value + ') => ' + w);
        return w;*/
    },
    computeSize : function(value, size, totalWeight) {
        if (value == null) {
            return null;
        }
        if (typeof value == 'number') {
            return value;
        }
        if ((typeof value != 'string') || (value.length == 0)) {
            throw new Exception('Illegal type of value "' + (typeof value) + '"');
        }
        value = value.match(/([0-9]+)(.*)/);
        var numberValue = value[1];
        var typeValue = value[2] || 'px';
        switch (typeValue) {
        case 'px':
            return Math.round(numberValue);
        case '%':
            return Math.round(numberValue * size / 100);
        case 'w':
            if (typeof totalWeight == 'undefined') {
                throw new Exception('The total weight is missing');
            }
            //jls.lang.System.out.println('computeSize(' + value + ', ' + size + ', ' + totalWeight + ') => ' + Math.round(numberValue * size / totalWeight));
            return Math.round(numberValue * size / totalWeight);
        default:
            throw new Exception('Illegal size type "' + typeValue + '"');
        }
    },
    placeElement : function(verticalAlign, lineHeight, child, x, y, w, h) {
    	if (verticalAlign == 'middle') {
    		y = y + Math.floor((lineHeight - h) / 2);
    	} else if (verticalAlign == 'bottom') {
    		y = y + lineHeight - h;
    	}
    	FlowLayout.place(child, x, y, w, h);
    },
    place : function(child, x, y, w, h) {
        //jls.lang.System.out.println('[' + x + ', ' + y + ', ' + w + ', ' + h + ']');
        //child.setLocation([x, y]);
        child.setBounds([x, y, w, h]);
        child.update();
    }
});

return FlowLayout;
});
define('jls/gui/Layout', ['jls/lang/Class'], function (Class) {

var Layout;
/*
The WPF layout engine uses a recursive two-phase system.
* First is the measure phase, where every element in the UI tree is queried for its desired size.
* Second is the arrange phase, where each element is instructed as to its actual size and location.
WPF ships with a handful of layout panels (StackPanel, WrapPanel, Canvas, UniformGrid, Grid, DockPanel) with each panel specializing in a particular type of layout.
*/
Layout = Class.create( /** @lends jls.gui.Layout.prototype */
{
    /**
     * Creates an layout.
     * 
     * @param {jls.gui.Panel} element The panel element.
     * @constructs
     * @see jls.gui.BorderLayout
     * @see jls.gui.CardLayout
     * @see jls.gui.FlowLayout
	 * @class Provides basic layout for Panel.
     */
    initialize : function(element) {
    	this._element = null;
    	this.setElement(element);
    },
    getElement : function() {
    	return this._element;
    },
    setElement : function(element) {
    	this._element = element;
    },
    onAddChild : function(child) {
        this._element.update();
    },
    onRemoveChild : function(child) {
        this._element.update();
    },
    // TODO onLayout ?
    onUpdate : Class.emptyFunction,
    onCreate : Class.emptyFunction
});

return Layout;
});
define('jls/gui/Style', ['jls/lang/Class'], function (Class) {

var Style;
Style = Class.create( /** @lends jls.gui.Style.prototype */
{
    /**
     * Creates a style.
     * 
     * @param {Object} [properties] The style properties to activate.
     * @constructs
	 * @class This class provides style for Element.
     */
    initialize : function(properties) {
    	this._properties = properties || {}; // TODO Copy properties?
    	this._activated = false;
    	this._parent = null;
    	this._handler = Class.emptyFunction;
        this._inheritedProperties = Style.defaultInherited;
        this._defaultProperties = Style.defaultAcquired;
    },
    /**
     * Activates this style.
     * 
     * @param {Object} [properties] The style properties to activate.
     */
    activate : function() {
    	if (this._activated) {
    		return;
    	}
        //jls.logger.trace('activate()');
    	this._activated = true;
        this.setProperties(this._properties);
    	this._properties = null;
    },
    /**
     * Sets a handler on this style.
     * 
     * @param {Function} handler The element to link to this style.
     * @returns {Function} The previous handler if any.
     */
    setHandler : function(handler) {
    	var previous = this._handler;
    	this._handler = handler;
        return previous;
    },
    setParent : function(parent) {
        this._parent = parent;
    },
    setInheritedProperties : function(properties) {
        this._inheritedProperties = properties;
    },
    setDefaultProperties : function(properties) {
        this._defaultProperties = properties;
    },
    /**
     * Returns the value of a property.
     * 
     * @param {String} key The property key.
     * @returns {Object} The property value or null.
     */
    getPropertyValue : function(key) {
        /*var getter = key.camelize('get');
        if (Object.isFunction(this[getter])) {
            return this[getter]();
        }*/
        key = key.camelize();
        //jls.logger.trace('getPropertyValue(' + key + ')');
        if (! this._activated) {
            if (key in this._properties) {
            	this[key] = this._properties[key]; // Will not be activated
                return this._properties[key];
            }
        }
        if (key in this) {
            return this[key];
        }
        if (key in this._inheritedProperties) {
            //jls.logger.trace('try to inherite');
            if (this._parent != null) {
                var value = this._parent.getPropertyValue(key);
                if (value != null) {
                    return value;
                }
            }
            return this._inheritedProperties[key];
        }
        if (key in this._defaultProperties) {
            return this._defaultProperties[key];
        }
        return null;
    },
    /**
     * Removes a property.
     * 
     * @param {String} key The property key.
     * @returns {Object} The previous property value if any.
     */
    removeProperty : function(key) {
        key = key.camelize();
        if (! (key in this)) {
            return null;
        }
        var previous = this[key];
        delete this[key];
        this._handler(key, previous, null);
        return previous;
    },
    /**
     * Sets a property.
     * 
     * @param {String} key The property key.
     * @param {String} value The value of the property.
     * @returns {Object} The previous property value if any.
     */
    setProperty : function(key, value) {
        if ((typeof value == 'undefined') || (value == null)) {
            return this.removeProperty(key);
        }
        key = key.camelize();
        var previous = key in this ? this[key] : null;
        //jls.logger.trace('setProperty(' + key + ', "' + value + '") previous: "' + previous + '"');
        if (value == previous) {
        	return previous;
        }
        this[key] = value;
        this._handler(key, previous, value);
        return previous;
    },
    /**
     * Sets properties.
     * 
     * @param {Object} properties The style properties to set.
     * @param {Array} [list] The property to set.
     */
    setProperties : function(properties, list) {
    	if (Object.isArray(list)) {
            for (var i = 0; i < list.length; i++) {
            	var k = list[i];
                if (k in properties) {
                    this.setProperty(k, properties[k]);
                }
            }
    	} else {
            for (var k in properties) {
                this.setProperty(k, properties[k]);
            }
    	}
        return this;
    }
});

Object.extend(Style,
{
    defaultInherited: {
        fontFamily: 'Arial',
        fontSize: 12,
        marginTop: 0,
        marginBottom: 0,
        marginLeft: 0,
        marginRight: 0,
        overflow: 'visible', // visible | hidden | scroll | auto
        direction: 'ltr', // ltr | rtl
        verticalPosition: 'top', // top | middle | bottom
        textAlign: 'left', // left | right | center | justify | leading | trailing
        verticalAlign: 'bottom' // top | middle | bottom
    },
    defaultAcquired: { // noninheritable
    	clear: 'none', // none | left | right | both
    	display: 'inline', // inline | block | none
        position: 'relative', // static | relative | absolute | fixed
        visibility: 'visible', // visible | hidden | collapse
        left: null,
        top: null,
        width: null,
        height: null
    }
});


return Style;
});
define('jls/gui/TemplateContainer', ['jls/lang/Class', 'jls/lang/Exception', 'jls/gui/Element'], function(Class, Exception, Element) {

    var TemplateContainer = Class.create(Element, /** @lends jls.gui.TemplateContainer.prototype */
    {
        /**
         * Creates a template container.
         * 
         * @param {Object} [parameters] The element parameters that is the description of the element to create.
         * @param {jls.gui.Element} [parent] The parent.
         * @constructs
         * @class This class represents a graphical element composed by other elements.
         * @see jls.gui.Element
         */
        initialize : function($super, template, parameters, parent) {
            TemplateContainer.create(this, template, $super, parameters, parent);
        }
    });

    Object.extend(TemplateContainer, { /** @lends jls.gui.TemplateContainer */
        create : function(tc, template, $super, parameters, parent) {
            tc._container = null;
            var p = TemplateContainer.mergeParameters({}, template, parameters);
            TemplateContainer.mergeChildren(p, template);
            $super(p, parent);
            tc.setContainer(tc.getById('container'));
            tc.getContainer().setId(null);
            if (Object.isArray(parameters.children)) {
                tc.addChildren(parameters.children);
            }
        },
        mergeChildren : function(parameters) {
            if (! ('children' in parameters)) {
                parameters.children = [];
            }
            for (var i = 1; i < arguments.length; i++) {
                var p = arguments[i];
                if ('children' in p) {
                    for (var j = 0; j < p.children.length; j++) {
                        parameters.children.push(p.children[j]);
                    }
                }
            }
            return parameters;
        },
        mergeParameters : function(parameters) {
            // attributes style children events broker resource classname
            if (! ('attributes' in parameters)) {
                parameters.attributes = {};
            }
            if (! ('style' in parameters)) {
                parameters.style = {};
            }
            if (! ('events' in parameters)) {
                parameters.events = {};
            }
            for (var i = 1; i < arguments.length; i++) {
                var p = arguments[i];
                if ('attributes' in p) {
                    Object.extend(parameters.attributes, p.attributes);
                }
                if ('style' in p) {
                    Object.extend(parameters.style, p.style);
                }
                if ('events' in p) {
                    Object.extend(parameters.events, p.events);
                }
                if ('broker' in p) {
                    parameters.broker = p.broker;
                }
                if ('resource' in p) {
                    parameters.broker = p.broker;
                }
                if ('classname' in p) {
                    parameters.classname = p.classname;
                }
            }
            return parameters;
        },
        prepareClass : function(elementClass) {
            var ancestor = elementClass.superclass && elementClass.superclass.prototype;
            elementClass.addMethods({ /** @lends jls.gui.TemplateContainer.prototype */
                addChild : function($super, child) {
                    if (this._container != null) {
                        return this._container.addChild(child);
                    }
                    return $super(child);
                },
                addChildren : function($super, children) {
                    if (this._container != null) {
                        this._container.addChildren(children);
                        return this;
                    }
                    return $super(children);
                },
                removeChild : function($super, child) {
                    if (this._container != null) {
                        return this._container.removeChild(child);
                    }
                    return $super(child);
                },
                removeChildren : function($super) {
                    if (this._container != null) {
                        this._container.removeChildren();
                        return this;
                    }
                    return $super();
                },
                getChildren : function($super) {
                    if (this._container != null) {
                        return this._container.getChildren();
                    }
                    return $super();
                },
                getChildCount : function($super) {
                    if (this._container != null) {
                        return this._container.getChildCount();
                    }
                    return $super();
                },
                getChild : function($super, index) {
                    if (this._container != null) {
                        return this._container.getChild(index);
                    }
                    return $super(index);
                },
                getContainer : function() {
                    return this._container == null ? this : this._container;
                },
                setContainer : function(container) {
                    this._container = container === this ? null : container;
                }
            });
            return elementClass;
        }
    });

    return TemplateContainer.prepareClass(TemplateContainer);
});
define('jls/io/BufferChannel', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/ByteBuffer'], function (Class, Exception, ByteBuffer) {

var BufferChannel;
/**
 * @namespace Provides for system input and output through data streams, serialization and the file system.
 * @name jls.io
 */

BufferChannel = Class.create({
    initialize : function(buffer) {
        if (buffer) {
            if (! (buffer instanceof ByteBuffer)) {
                throw new Exception('Invalid Buffer argument type (' + (typeof buffer) + ')');
            }
            this._buffer = buffer; //buffer.slice();
            this._append = false;
        } else {
            this._buffer = ByteBuffer.allocate(1024);
            // TODO Use append
            this._append = true;
        }
    },
    buffer : function() {
        return this._buffer;
    },
    close : function() {
        this._buffer.free(); // ?
        return this;
    },
    flush : function() {
        return this;
    },
    readByte : function() {
        if (this._buffer.remaining() < 1) {
            return -1;
        }
        return this._buffer.getByte();
    },
    writeByte : function(b) {
        if (this._buffer.remaining() < 1) {
            return false;
        }
        this._buffer.putByte(b);
        return true;
    },
    read : function(buffer) {
        var count = buffer.remaining();
		if (count > this._buffer.remaining()) {
			count = this._buffer.remaining();
		}
        //jls.logger.trace('BufferChannel.read(' + this._buffer.remaining() + '), count: ' + count);
		if (count > 0) {
			buffer.putBuffer(this._buffer, count);
		}
        return count;
    },
    write : function(buffer) {
        var count = this._buffer.remaining();
		if (count > buffer.remaining()) {
			count = buffer.remaining();
		}
        //jls.logger.trace('BufferChannel.write(' + this._buffer.remaining() + '), count: ' + count);
		if (count > 0) {
			this._buffer.putBuffer(buffer, count);
		}
        return count;
    },
    toString : function(csn) {
        var l = this._buffer.limit();
        var p = this._buffer.position();
        this._buffer.flip();
        var s = this._buffer.getString(csn);
        this._buffer.setLimit(l);
        this._buffer.setPosition(p);
        return s;
    }
});

return BufferChannel;
});
define('jls/io/BufferedInputStream', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/ByteBuffer',
  'jls/lang/BufferOverflowException'
], function (
  Class,
  Exception,
  ByteBuffer,
  BufferOverflowException
) {

var BufferedInputStream;
BufferedInputStream = Class.create( /** @lends jls.io.BufferedInputStream.prototype */
{
    /**
     * Creates a BufferedInputStream.
     * 
     * @param {jls.io.InputStream} input The underlying byte input stream.
     * @param {Number} size The buffer size.
     * @constructs
     * @class A character reader for byte input stream.
     */
    initialize : function(input, size) {
        this._in = input;
    	this._buffer = ByteBuffer.allocate(size || 1024);
        this._buffer.setLimit(0);
        this._mark = -1;
    },
    /**
     * Closes this stream.
     *
     */
    close : function() {
        return this._in.close();
    },
    /**
     * Flushs this stream.
     *
     */
    flush : function() {
        return this._in.flush();
    },
    mark : function(limit) {
        if (this._buffer.remaining() == 0) {
            this._buffer.clear();
            this._buffer.setLimit(0);
        }
        if (limit > this._buffer.capacity() - this._buffer.position()) {
            throw new BufferOverflowException();
        }
        this._mark = this._buffer.position();
    },
    /**
     * Tells if this stream supports the mark and reset methods.
     * 
     * @returns {Boolean} if this stream instance supports the mark and reset methods; false otherwise.
     */
    markSupported : function() {
        return true;
    },
    reset : function() {
        if (this._mark < 0) {
            throw new Exception('Invalid mark');
        }
        this._buffer.setPosition(this._mark);
    },
    _fill : function() {
        if (this._buffer.remaining() > 0) {
            return;
        }
        this._buffer.clear();
        this._in.read(this._buffer);
        this._mark = -1;
    },
    /**
     * Reads a byte.
     * 
     * @returns {Number} The unsigned byte or -1.
     */
    readByte : function() {
        this._fill();
        return this._buffer.getByte();
    },
    /**
     * Reads bytes into the specified byte array, starting at the given offset.
     * 
     * @param {ByteArray} barray The destination byte array.
     * @param {Number} offset The offset at which to start storing bytes.
     * @param {Number} length The maximum number of bytes to read.
     * @returns {Number} The total number of bytes read.
     */
    readByteArray : function(barray, offset, length) {
    	offset = offset || 0;
    	length = length || barray.size() - offset;
        var count = 0;
        while (count < length) {
            this._fill();
            if (this._buffer.remaining() == 0) {
                break;
            }
            var l = this._buffer.remaining();
            if (l > length - count) {
                l = length - count;
            }
            barray.memcpy(offset + count, this._buffer.byteArray(), this._buffer.position(), l);
            buffer.incrementPosition(l);
            count += l;
        }
        return count;
    },
    /**
     * Reads this file into a buffer.
     *
     * @param {jls.lang.Buffer} buffer The buffer to read.
     * @returns {Number} the read byte count.
     */
    read : function(buffer) {
        var start = buffer.position();
        while (buffer.remaining() > 0) {
            this._fill();
            if (this._buffer.remaining() == 0) {
                break;
            }
            buffer.putBuffer(this._buffer);
        }
        return buffer.position() - start;
    }
});


return BufferedInputStream;
});
define('jls/io/BufferedReader', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/CharBuffer',
  'jls/lang/BufferOverflowException'
], function (
  Class,
  Exception,
  CharBuffer,
  BufferOverflowException
) {

var BufferedReader;
BufferedReader = Class.create( /** @lends jls.io.BufferedReader.prototype */
{
    /**
     * Creates a BufferedReader.
     * 
     * @param {jls.io.Reader} reader The underlying character reader.
     * @param {Number} size The buffer size.
     * @constructs
     * @class Provides a buffered reader for character reader.
     */
    initialize : function(reader, size) {
        this._reader = reader;
    	this._buffer = CharBuffer.allocate(size || 1024);
        this._buffer.setLimit(0);
        this._mark = -1;
    },
    /**
     * Closes this stream.
     *
     */
    close : function() {
        return this._reader.close();
    },
    /**
     * Flushs this stream.
     *
     */
    flush : function() {
        return this._reader.flush();
    },
    mark : function(limit) {
        if (this._buffer.remaining() == 0) {
            this._buffer.clear();
            this._buffer.setLimit(0);
        }
        if (limit > this._buffer.capacity() - this._buffer.position()) {
            throw new BufferOverflowException();
        }
        this._mark = this._buffer.position();
    },
    /**
     * Tells if this stream supports the mark and reset methods.
     * 
     * @returns {Boolean} if this stream instance supports the mark and reset methods; false otherwise.
     */
    markSupported : function() {
        return true;
    },
    reset : function() {
        if (this._mark < 0) {
            throw new Exception('Invalid mark');
        }
        this._buffer.setPosition(this._mark);
    },
    _fill : function() {
        if (this._buffer.remaining() > 0) {
            return this._buffer.remaining();
        }
        this._buffer.clear();
        var count = this._reader.readCharBuffer(this._buffer);
        this._buffer.flip();
        this._mark = -1;
        return count;
    },
    /**
     * Reads a byte.
     * 
     * @returns {Number} The unsigned byte or -1.
     */
    readChar : function() {
        this._fill();
        return this._buffer.getChar();
    },
    /**
     * Reads this file into a buffer.
     *
     * @param {jls.lang.Buffer} buffer The buffer to read.
     * @returns {Number} the read byte count.
     */
    readCharBuffer : function(buffer) {
        var start = buffer.position();
        while (buffer.remaining() > 0) {
            this._fill();
            if (this._buffer.remaining() == 0) {
                break;
            }
            buffer.putBuffer(this._buffer);
        }
        return buffer.position() - start;
    },
    /**
     * Reads a line and returns the string.
     *
     * @returns {String} The line.
     */
    readLine : function() {
    	var line = '';
        while (true) {
            if (this._fill() == 0) {
                return null;
            }
            if (this._buffer.remaining() == 0) {
                break;
            }
            var p = this._buffer.position();
            var s = this._buffer.getString();
            var i = s.indexOf(BufferedReader.separator);
        	//jls.logger.warn('readLine() ->' + s + '<- ' + s.length + ', ' + i);
            if (i >= 0) {
            	this._buffer.setPosition(p + i + BufferedReader.separator.length);
                line += s.substr(0, i);
                break;
            }
            line += s;
        }
        //jls.logger.warn('readLine() ->' + line + '<-');
        return line;
    }
});

Object.extend(BufferedReader,
{
    separator : _native.core.properties['line.separator']
});


return BufferedReader;
});
define('jls/io/InputStreamReader', [
  'jls/lang/Class',
  'jls/io/cs/Charset',
  'jls/lang/ByteBuffer',
  'jls/lang/CharBuffer'
], function (
  Class,
  Charset,
  ByteBuffer,
  CharBuffer
) {

var InputStreamReader;
//jls.loader.require('jls.io.BufferedInputStream');
InputStreamReader = Class.create( /** @lends jls.io.InputStreamReader.prototype */
{
    /**
     * Creates a writer.
     * 
     * @param {jls.io.InputStream} input The underlying byte input stream.
     * @param {String} csn The name of the character set to use.
     * @constructs
     * @class A character reader for byte input stream.
     */
    initialize : function(input, csn) {
        /*if (! input.markSupported()) {
            input = new jls.io.BufferedInputStream(input);
        }*/
        this._in = input;
        var charset = csn ? Charset.forName(csn) : Charset.defaultCharset();
        this._decoder = charset.newDecoder();
    	this._bbuffer = ByteBuffer.allocate(1024);
    	this._bbuffer.setLimit(0);
    	this._cbuffer = CharBuffer.allocate(1); // used for the readChar method
    },
    /**
     * Closes this stream.
     *
     */
    close : function() {
        return this._in.close();
    },
    /**
     * Flushs this stream.
     *
     */
    flush : function() {
        return this._in.flush();
    },
    /**
     * Tells if this stream supports the mark and reset methods.
     * 
     * @returns {Boolean} if this stream instance supports the mark and reset methods; false otherwise.
     */
    markSupported : function() {
        return ('mark' in this) && ('reset' in this);
    },
    readChar : function() {
    	var cb = this._cbuffer;
    	cb.clear();
    	cb.setLimit(1);
		this.readCharBuffer(cb);
    	if (cb.remaining() != 0) {
    		return -1;
    	}
    	cb.flip();
    	return cb.getChar();
    },
    /**
     * Reads the underlying stream into a character buffer.
     *
     * @param {jls.lang.CharBuffer} cb The character buffer to read into.
     * @returns {Number} the read byte count.
     */
    readCharBuffer : function(cb) {
        var start = cb.position();
    	// TODO adjust buffer
    	var bb = this._bbuffer;
    	while (cb.remaining() > 0) {
    		if (bb.remaining() == 0) {
        		bb.clear();
            	this._in.read(bb);
            	bb.flip();
            	//jls.logger.warn(bb.remaining() + ' byte(s) read');
    		}
        	//jls.logger.warn('bb.remaining(): ' + bb.remaining());
        	//jls.logger.warn('cb.remaining(): ' + cb.remaining());
    		if (bb.remaining() > 0) {
                this._decoder.decode(bb, cb);
    		}
            if (bb.limit() != bb.capacity()) {
            	break;
            }
    	}
        return cb.position() - start;
    }
});

return InputStreamReader;
});
define('jls/io/OutputStreamWriter', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/io/cs/Charset',
  'jls/lang/CharBuffer'
], function (
  Class,
  Exception,
  Charset,
  CharBuffer
) {

var OutputStreamWriter;
OutputStreamWriter = Class.create( /** @lends jls.io.OutputStreamWriter.prototype */
{
    /**
     * Creates a writer.
     * 
     * @param {jls.io.OutputStream} out The underlying byte output stream.
     * @param {String} csn The name of the character set to use.
     * @constructs
     * @class A character writer for byte output stream.
     */
    initialize : function(out, csn) {
        // TODO Check output stream
        this._out = out;
        var charset = csn ? Charset.forName(csn) : Charset.defaultCharset();
        this._encoder = charset.newEncoder();
    },
    getOutputStream : function() {
        return this._out;
    },
    close : function() {
        return this._out.close();
    },
    flush : function() {
        return this._out.flush();
    },
    writeChar : function(c) {
    	// TODO Change this
        return this.write(String.fromCharCode(c));
    },
    writeCharBuffer : function(cb) {
        var bb = this._encoder.encode(cb);
        bb.flip();
        return this._out.write(bb);
    },
    /**
     * Writes a string.
     *
     * @param {String} s The string to write.
     * @returns {Number} the write byte count.
     */
    write : function(s) {
        if (typeof s != 'string') {
            throw new Exception('Invalid argument');
        }
        var cb = CharBuffer.wrap(s);
        return this.writeCharBuffer(cb);
    },
    /**
     * Writes a string.
     *
     * @param {String} s The string to write.
     * @returns {Number} the write byte count.
     */
    writeLine : function(s) {
        if (s) {
            return this.write(s + OutputStreamWriter.separator);
        } else {
            return this.write(OutputStreamWriter.separator);
        }
    }
});

Object.extend(OutputStreamWriter,
{
    separator : _native.core.properties['line.separator']
});


return OutputStreamWriter;
});
define('jls/io/cs/CharDecoder', ['jls/lang/Class', 'jls/lang/CharBuffer'], function (Class, CharBuffer) {

var CharDecoder;
CharDecoder = Class.create( /** @lends jls.io.cs.CharDecoder.prototype */
{
    /**
     * Creates a character decoder.
     * 
     * @constructs
     * @class This class represents a character decoder.
     */
    initialize : function(charset) {
        this._charset = charset;
        this._averBytes = 1.0;
        this._replacement = '?'.charCodeAt(0);
    },
    /**
     * Decodes byte buffer and returns the character buffer.
     *
     * @param {jls.lang.Buffer} input The buffer to decode.
     * @returns {jls.lang.CharBuffer} The decoded character buffer.
     */
    decode : function(input, buffer) {
    	var length = Math.round(input.remaining() / this._averBytes);
    	var output = buffer || CharBuffer.allocate(length + 1, true);
    	while ((input.remaining() > 0) && (output.remaining() > 0)) {
    		var b = input.getByte();
    		if (b > 127) {
    			b = this._replacement;
    		}
    		output.putChar(b);
    	}
        return output;
    }
});


return CharDecoder;
});
define('jls/io/cs/CharEncoder', ['jls/lang/Class', 'jls/lang/Logger', 'jls/lang/ByteBuffer'], function (Class, Logger, ByteBuffer) {

var CharEncoder;
CharEncoder = Class.create( /** @lends jls.io.cs.CharEncoder.prototype */
{
    /**
     * Creates a character encoder.
     * 
     * @constructs
     * @param {jls.io.cs.Charset} charset The related charset.
     * @class This class represents a character encoder.
     */
    initialize : function(charset) {
        this._charset = charset;
        this._averBytes = 1.0;
        this._replacement = '?'.charCodeAt(0);
    },
    /**
     * Encodes a string and returns a buffer.
     *
     * @param {jls.lang.CharBuffer} input The character buffer to encode.
     * @returns {jls.lang.Buffer} The encoded buffer.
     */
    encode : function(input, buffer) {
    	var length = Math.round(input.remaining() * this._averBytes);
    	var output = buffer || ByteBuffer.allocate(length + 1);
        Logger.getInstance().debug('CharEncoder.encode(), length: ' + length + ', output.remaining(): ' + output.remaining());
    	while (input.remaining() > 0) {
    		var c = input.getChar();
    		if (c > 127) {
    			c = this._replacement;
    		}
    		output.putByte(c);
    	}
        return output;
    }
});


return CharEncoder;
});
define('jls/io/cs/Charset', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/io/cs/CharDecoder',
  'jls/io/cs/CharEncoder'
], function (
  Class,
  Exception,
  CharDecoder,
  CharEncoder
) {

var Charset;
/**
 * @namespace Provides character sets.
 * @see jls.io.cs.Charset
 * @name jls.io.cs
 */

/**
 * @class This class represents a character set and the associated codec.
 * The default charsets are Cp1252, Cp850, ISO-8859-1, UTF-8 and ASCII.
 * @name jls.io.cs.Charset
 */
Charset = Class.create( /** @lends jls.io.cs.Charset.prototype */
{
    /**
     * Creates a charset.
     * 
     * @private
     */
    initialize : function(name) {
        this._name = name;
    },
    /**
     * Returns the charset name.
     *
     * @returns {String} The charset name.
     */
    getName : function() {
        return this._name;
    },
    /**
     * Decodes byte buffer and returns the string.
     *
     * @param {jls.lang.Buffer} buf The buffer to decode.
     * @returns {String} The decoded string.
     */
    decode : function(buf) {
        return '';
    },
    /**
     * Encodes a string and returns a buffer.
     *
     * @param {String} str The string to encode.
     * @returns {jls.lang.Buffer} The buffer.
     */
    encode : function(str) {
        return null;
    },
    /**
     * Creates a new decoder for this charset.
     *
     * @returns {jls.io.cs.CharDecoder} The buffer.
     */
    newDecoder : function() {
        return new CharDecoder(this);
    },
    /**
     * Creates a new encoder for this charset.
     *
     * @returns {jls.io.cs.CharEncoder} The buffer.
     */
    newEncoder : function() {
        return new CharEncoder(this);
    }
});


Object.extend(Charset, /** @lends jls.io.cs.Charset */
{
	_defaultCharset : null,
	_charsetMapping : {
		'Cp1252' : 'jls/io/cs/Cp1252',
		'Cp850' : 'jls/io/cs/Cp850',
		'ISO-8859-1' : 'jls/io/cs/ISO_8859_1',
		'UTF-8' : 'jls/io/cs/UTF_8',
		'ASCII' : 'jls/io/cs/Charset'
	},
	_availableCharsets : {},
    /**
     * Returns available charsets.
     * 
     * @returns {Array} The available charsets.
     */
	availableCharsets : function() {
        return Object.values(Charset._availableCharsets);
    },
	addCharset : function(cs) {
		Charset._availableCharsets[cs.getName()] = cs;
    },
    /**
     * Returns the default charset.
     * 
     * @returns {jls.io.cs.Charset} The default charset.
     */
    defaultCharset : function() {
    	if (Charset._defaultCharset == null) {
            var csn = _native.core.properties['file.encoding'];
    		if (csn && Charset.isSupported(csn)) {
    			Charset._defaultCharset = Charset.forName(csn);
    		} else {
        		Charset._defaultCharset = Charset.forName('ASCII');
    		}
    	}
    	return Charset._defaultCharset;
    },
    /**
     * Tells if the specified charset is supported.
     * 
     * @param {String} name The charset name.
     * @returns {Boolean} true if the specified charset is supported.
     */
    isSupported : function(name) {
    	if (typeof name != 'string') {
			throw new Exception('Invalid charset name');
    	}
    	if (name in Charset._availableCharsets) {
			return true;
    	}
    	if (name in Charset._charsetMapping) {
            var cs = require(Charset._charsetMapping[name]);
			return name in Charset._availableCharsets;
    	}
		return false;
    },
    /**
     * Returns the specified charset.
     * 
     * @param {String} name The charset name.
     * @returns {jls.io.cs.Charset} The charset.
     */
	forName : function(name) {
		if (! Charset.isSupported(name)) {
			throw new Exception('Unsupported charset "' + name + '"');
		}
        return Charset._availableCharsets[name];
    }
});

// static
Charset.addCharset(new Charset('ASCII'));



return Charset;
});
define('jls/io/cs/Cp1252', [
  'jls/lang/Class',
  'jls/io/cs/Charset',
  'jls/io/cs/SingleByteDecoder',
  'jls/io/cs/SingleByteEncoder'
], function (
  Class,
  Charset,
  SingleByteDecoder,
  SingleByteEncoder
) {

var Cp1252;
Cp1252 = Class.create(Charset,
{
    initialize : function($super) {
    	$super('Cp1252');
    },
    newDecoder : function() {
        return new SingleByteDecoder(this, Cp1252.byteToCharCode);
    },
    newEncoder : function() {
        return new SingleByteEncoder(this, Cp1252.charCodeToByte);
    }
});


Object.extend(Cp1252,
{
	byteToCharCode : [
		0x0000,
		0x0001,
		0x0002,
		0x0003,
		0x0004,
		0x0005,
		0x0006,
		0x0007,
		0x0008,
		0x0009,
		0x000A,
		0x000B,
		0x000C,
		0x000D,
		0x000E,
		0x000F,
		0x0010,
		0x0011,
		0x0012,
		0x0013,
		0x0014,
		0x0015,
		0x0016,
		0x0017,
		0x0018,
		0x0019,
		0x001A,
		0x001B,
		0x001C,
		0x001D,
		0x001E,
		0x001F,
		0x0020,
		0x0021,
		0x0022,
		0x0023,
		0x0024,
		0x0025,
		0x0026,
		0x0027,
		0x0028,
		0x0029,
		0x002A,
		0x002B,
		0x002C,
		0x002D,
		0x002E,
		0x002F,
		0x0030,
		0x0031,
		0x0032,
		0x0033,
		0x0034,
		0x0035,
		0x0036,
		0x0037,
		0x0038,
		0x0039,
		0x003A,
		0x003B,
		0x003C,
		0x003D,
		0x003E,
		0x003F,
		0x0040,
		0x0041,
		0x0042,
		0x0043,
		0x0044,
		0x0045,
		0x0046,
		0x0047,
		0x0048,
		0x0049,
		0x004A,
		0x004B,
		0x004C,
		0x004D,
		0x004E,
		0x004F,
		0x0050,
		0x0051,
		0x0052,
		0x0053,
		0x0054,
		0x0055,
		0x0056,
		0x0057,
		0x0058,
		0x0059,
		0x005A,
		0x005B,
		0x005C,
		0x005D,
		0x005E,
		0x005F,
		0x0060,
		0x0061,
		0x0062,
		0x0063,
		0x0064,
		0x0065,
		0x0066,
		0x0067,
		0x0068,
		0x0069,
		0x006A,
		0x006B,
		0x006C,
		0x006D,
		0x006E,
		0x006F,
		0x0070,
		0x0071,
		0x0072,
		0x0073,
		0x0074,
		0x0075,
		0x0076,
		0x0077,
		0x0078,
		0x0079,
		0x007A,
		0x007B,
		0x007C,
		0x007D,
		0x007E,
		0x007F,
		0x20AC,
		null,
		0x201A,
		0x0192,
		0x201E,
		0x2026,
		0x2020,
		0x2021,
		0x02C6,
		0x2030,
		0x0160,
		0x2039,
		0x0152,
		null,
		0x017D,
		null,
		null,
		0x2018,
		0x2019,
		0x201C,
		0x201D,
		0x2022,
		0x2013,
		0x2014,
		0x02DC,
		0x2122,
		0x0161,
		0x203A,
		0x0153,
		null,
		0x017E,
		0x0178,
		0x00A0,
		0x00A1,
		0x00A2,
		0x00A3,
		0x00A4,
		0x00A5,
		0x00A6,
		0x00A7,
		0x00A8,
		0x00A9,
		0x00AA,
		0x00AB,
		0x00AC,
		0x00AD,
		0x00AE,
		0x00AF,
		0x00B0,
		0x00B1,
		0x00B2,
		0x00B3,
		0x00B4,
		0x00B5,
		0x00B6,
		0x00B7,
		0x00B8,
		0x00B9,
		0x00BA,
		0x00BB,
		0x00BC,
		0x00BD,
		0x00BE,
		0x00BF,
		0x00C0,
		0x00C1,
		0x00C2,
		0x00C3,
		0x00C4,
		0x00C5,
		0x00C6,
		0x00C7,
		0x00C8,
		0x00C9,
		0x00CA,
		0x00CB,
		0x00CC,
		0x00CD,
		0x00CE,
		0x00CF,
		0x00D0,
		0x00D1,
		0x00D2,
		0x00D3,
		0x00D4,
		0x00D5,
		0x00D6,
		0x00D7,
		0x00D8,
		0x00D9,
		0x00DA,
		0x00DB,
		0x00DC,
		0x00DD,
		0x00DE,
		0x00DF,
		0x00E0,
		0x00E1,
		0x00E2,
		0x00E3,
		0x00E4,
		0x00E5,
		0x00E6,
		0x00E7,
		0x00E8,
		0x00E9,
		0x00EA,
		0x00EB,
		0x00EC,
		0x00ED,
		0x00EE,
		0x00EF,
		0x00F0,
		0x00F1,
		0x00F2,
		0x00F3,
		0x00F4,
		0x00F5,
		0x00F6,
		0x00F7,
		0x00F8,
		0x00F9,
		0x00FA,
		0x00FB,
		0x00FC,
		0x00FD,
		0x00FE,
		0x00FF
	],
	charCodeToByte : []
});

// static
Cp1252.charCodeToByte = SingleByteEncoder.reverseMapping(Cp1252.byteToCharCode);
Charset.addCharset(new Cp1252());


return Cp1252;
});
define('jls/io/cs/Cp850', [
  'jls/lang/Class',
  'jls/io/cs/Charset',
  'jls/io/cs/SingleByteDecoder',
  'jls/io/cs/SingleByteEncoder'
], function (
  Class,
  Charset,
  SingleByteDecoder,
  SingleByteEncoder
) {

var Cp850;
Cp850 = Class.create(Charset,
{
    initialize : function($super) {
    	$super('Cp850');
    },
    newDecoder : function() {
        return new SingleByteDecoder(this, Cp850.byteToCharCode);
    },
    newEncoder : function() {
        return new SingleByteEncoder(this, Cp850.charCodeToByte);
    }
});


Object.extend(Cp850,
{
	byteToCharCode : [
		0x0000,
		0x0001,
		0x0002,
		0x0003,
		0x0004,
		0x0005,
		0x0006,
		0x0007,
		0x0008,
		0x0009,
		0x000A,
		0x000B,
		0x000C,
		0x000D,
		0x000E,
		0x000F,
		0x0010,
		0x0011,
		0x0012,
		0x0013,
		0x0014,
		0x0015,
		0x0016,
		0x0017,
		0x0018,
		0x0019,
		0x001A,
		0x001B,
		0x001C,
		0x001D,
		0x001E,
		0x001F,
		0x0020,
		0x0021,
		0x0022,
		0x0023,
		0x0024,
		0x0025,
		0x0026,
		0x0027,
		0x0028,
		0x0029,
		0x002A,
		0x002B,
		0x002C,
		0x002D,
		0x002E,
		0x002F,
		0x0030,
		0x0031,
		0x0032,
		0x0033,
		0x0034,
		0x0035,
		0x0036,
		0x0037,
		0x0038,
		0x0039,
		0x003A,
		0x003B,
		0x003C,
		0x003D,
		0x003E,
		0x003F,
		0x0040,
		0x0041,
		0x0042,
		0x0043,
		0x0044,
		0x0045,
		0x0046,
		0x0047,
		0x0048,
		0x0049,
		0x004A,
		0x004B,
		0x004C,
		0x004D,
		0x004E,
		0x004F,
		0x0050,
		0x0051,
		0x0052,
		0x0053,
		0x0054,
		0x0055,
		0x0056,
		0x0057,
		0x0058,
		0x0059,
		0x005A,
		0x005B,
		0x005C,
		0x005D,
		0x005E,
		0x005F,
		0x0060,
		0x0061,
		0x0062,
		0x0063,
		0x0064,
		0x0065,
		0x0066,
		0x0067,
		0x0068,
		0x0069,
		0x006A,
		0x006B,
		0x006C,
		0x006D,
		0x006E,
		0x006F,
		0x0070,
		0x0071,
		0x0072,
		0x0073,
		0x0074,
		0x0075,
		0x0076,
		0x0077,
		0x0078,
		0x0079,
		0x007A,
		0x007B,
		0x007C,
		0x007D,
		0x007E,
		0x007F,
		0x00C7,
		0x00FC,
		0x00E9,
		0x00E2,
		0x00E4,
		0x00E0,
		0x00E5,
		0x00E7,
		0x00EA,
		0x00EB,
		0x00E8,
		0x00EF,
		0x00EE,
		0x00EC,
		0x00C4,
		0x00C5,
		0x00C9,
		0x00E6,
		0x00C6,
		0x00F4,
		0x00F6,
		0x00F2,
		0x00FB,
		0x00F9,
		0x00FF,
		0x00D6,
		0x00DC,
		0x00F8,
		0x00A3,
		0x00D8,
		0x00D7,
		0x0192,
		0x00E1,
		0x00ED,
		0x00F3,
		0x00FA,
		0x00F1,
		0x00D1,
		0x00AA,
		0x00BA,
		0x00BF,
		0x00AE,
		0x00AC,
		0x00BD,
		0x00BC,
		0x00A1,
		0x00AB,
		0x00BB,
		0x2591,
		0x2592,
		0x2593,
		0x2502,
		0x2524,
		0x00C1,
		0x00C2,
		0x00C0,
		0x00A9,
		0x2563,
		0x2551,
		0x2557,
		0x255D,
		0x00A2,
		0x00A5,
		0x2510,
		0x2514,
		0x2534,
		0x252C,
		0x251C,
		0x2500,
		0x253C,
		0x00E3,
		0x00C3,
		0x255A,
		0x2554,
		0x2569,
		0x2566,
		0x2560,
		0x2550,
		0x256C,
		0x00A4,
		0x00F0,
		0x00D0,
		0x00CA,
		0x00CB,
		0x00C8,
		0x0131,
		0x00CD,
		0x00CE,
		0x00CF,
		0x2518,
		0x250C,
		0x2588,
		0x2584,
		0x00A6,
		0x00CC,
		0x2580,
		0x00D3,
		0x00DF,
		0x00D4,
		0x00D2,
		0x00F5,
		0x00D5,
		0x00B5,
		0x00FE,
		0x00DE,
		0x00DA,
		0x00DB,
		0x00D9,
		0x00FD,
		0x00DD,
		0x00AF,
		0x00B4,
		0x00AD,
		0x00B1,
		0x2017,
		0x00BE,
		0x00B6,
		0x00A7,
		0x00F7,
		0x00B8,
		0x00B0,
		0x00A8,
		0x00B7,
		0x00B9,
		0x00B3,
		0x00B2,
		0x25A0,
		0x00A0
	],
	charCodeToByte : []
});

// static
Cp850.charCodeToByte = SingleByteEncoder.reverseMapping(Cp850.byteToCharCode);
Charset.addCharset(new Cp850());


return Cp850;
});
define('jls/io/cs/ISO_8859_1', [
  'jls/lang/Class',
  'jls/io/cs/Charset',
  'jls/io/cs/SingleByteDecoder',
  'jls/io/cs/SingleByteEncoder'
], function (
  Class,
  Charset,
  SingleByteDecoder,
  SingleByteEncoder
) {

var ISO_8859_1;
ISO_8859_1 = Class.create(Charset,
{
    initialize : function($super) {
    	$super('ISO-8859-1');
    },
    newDecoder : function() {
        return new SingleByteDecoder(this, ISO_8859_1.byteToCharCode);
    },
    newEncoder : function() {
        return new SingleByteEncoder(this, ISO_8859_1.charCodeToByte);
    }
});


Object.extend(ISO_8859_1,
{
	byteToCharCode : [
		0x0000, // NULL
		0x0001, // START OF HEADING
		0x0002, // START OF TEXT
		0x0003, // END OF TEXT
		0x0004, // END OF TRANSMISSION
		0x0005, // ENQUIRY
		0x0006, // ACKNOWLEDGE
		0x0007, // BELL
		0x0008, // BACKSPACE
		0x0009, // HORIZONTAL TABULATION
		0x000A, // LINE FEED
		0x000B, // VERTICAL TABULATION
		0x000C, // FORM FEED
		0x000D, // CARRIAGE RETURN
		0x000E, // SHIFT OUT
		0x000F, // SHIFT IN
		0x0010, // DATA LINK ESCAPE
		0x0011, // DEVICE CONTROL ONE
		0x0012, // DEVICE CONTROL TWO
		0x0013, // DEVICE CONTROL THREE
		0x0014, // DEVICE CONTROL FOUR
		0x0015, // NEGATIVE ACKNOWLEDGE
		0x0016, // SYNCHRONOUS IDLE
		0x0017, // END OF TRANSMISSION BLOCK
		0x0018, // CANCEL
		0x0019, // END OF MEDIUM
		0x001A, // SUBSTITUTE
		0x001B, // ESCAPE
		0x001C, // FILE SEPARATOR
		0x001D, // GROUP SEPARATOR
		0x001E, // RECORD SEPARATOR
		0x001F, // UNIT SEPARATOR
		0x0020, // SPACE
		0x0021, // EXCLAMATION MARK
		0x0022, // QUOTATION MARK
		0x0023, // NUMBER SIGN
		0x0024, // DOLLAR SIGN
		0x0025, // PERCENT SIGN
		0x0026, // AMPERSAND
		0x0027, // APOSTROPHE
		0x0028, // LEFT PARENTHESIS
		0x0029, // RIGHT PARENTHESIS
		0x002A, // ASTERISK
		0x002B, // PLUS SIGN
		0x002C, // COMMA
		0x002D, // HYPHEN-MINUS
		0x002E, // FULL STOP
		0x002F, // SOLIDUS
		0x0030, // DIGIT ZERO
		0x0031, // DIGIT ONE
		0x0032, // DIGIT TWO
		0x0033, // DIGIT THREE
		0x0034, // DIGIT FOUR
		0x0035, // DIGIT FIVE
		0x0036, // DIGIT SIX
		0x0037, // DIGIT SEVEN
		0x0038, // DIGIT EIGHT
		0x0039, // DIGIT NINE
		0x003A, // COLON
		0x003B, // SEMICOLON
		0x003C, // LESS-THAN SIGN
		0x003D, // EQUALS SIGN
		0x003E, // GREATER-THAN SIGN
		0x003F, // QUESTION MARK
		0x0040, // COMMERCIAL AT
		0x0041, // LATIN CAPITAL LETTER A
		0x0042, // LATIN CAPITAL LETTER B
		0x0043, // LATIN CAPITAL LETTER C
		0x0044, // LATIN CAPITAL LETTER D
		0x0045, // LATIN CAPITAL LETTER E
		0x0046, // LATIN CAPITAL LETTER F
		0x0047, // LATIN CAPITAL LETTER G
		0x0048, // LATIN CAPITAL LETTER H
		0x0049, // LATIN CAPITAL LETTER I
		0x004A, // LATIN CAPITAL LETTER J
		0x004B, // LATIN CAPITAL LETTER K
		0x004C, // LATIN CAPITAL LETTER L
		0x004D, // LATIN CAPITAL LETTER M
		0x004E, // LATIN CAPITAL LETTER N
		0x004F, // LATIN CAPITAL LETTER O
		0x0050, // LATIN CAPITAL LETTER P
		0x0051, // LATIN CAPITAL LETTER Q
		0x0052, // LATIN CAPITAL LETTER R
		0x0053, // LATIN CAPITAL LETTER S
		0x0054, // LATIN CAPITAL LETTER T
		0x0055, // LATIN CAPITAL LETTER U
		0x0056, // LATIN CAPITAL LETTER V
		0x0057, // LATIN CAPITAL LETTER W
		0x0058, // LATIN CAPITAL LETTER X
		0x0059, // LATIN CAPITAL LETTER Y
		0x005A, // LATIN CAPITAL LETTER Z
		0x005B, // LEFT SQUARE BRACKET
		0x005C, // REVERSE SOLIDUS
		0x005D, // RIGHT SQUARE BRACKET
		0x005E, // CIRCUMFLEX ACCENT
		0x005F, // LOW LINE
		0x0060, // GRAVE ACCENT
		0x0061, // LATIN SMALL LETTER A
		0x0062, // LATIN SMALL LETTER B
		0x0063, // LATIN SMALL LETTER C
		0x0064, // LATIN SMALL LETTER D
		0x0065, // LATIN SMALL LETTER E
		0x0066, // LATIN SMALL LETTER F
		0x0067, // LATIN SMALL LETTER G
		0x0068, // LATIN SMALL LETTER H
		0x0069, // LATIN SMALL LETTER I
		0x006A, // LATIN SMALL LETTER J
		0x006B, // LATIN SMALL LETTER K
		0x006C, // LATIN SMALL LETTER L
		0x006D, // LATIN SMALL LETTER M
		0x006E, // LATIN SMALL LETTER N
		0x006F, // LATIN SMALL LETTER O
		0x0070, // LATIN SMALL LETTER P
		0x0071, // LATIN SMALL LETTER Q
		0x0072, // LATIN SMALL LETTER R
		0x0073, // LATIN SMALL LETTER S
		0x0074, // LATIN SMALL LETTER T
		0x0075, // LATIN SMALL LETTER U
		0x0076, // LATIN SMALL LETTER V
		0x0077, // LATIN SMALL LETTER W
		0x0078, // LATIN SMALL LETTER X
		0x0079, // LATIN SMALL LETTER Y
		0x007A, // LATIN SMALL LETTER Z
		0x007B, // LEFT CURLY BRACKET
		0x007C, // VERTICAL LINE
		0x007D, // RIGHT CURLY BRACKET
		0x007E, // TILDE
		0x007F, // DELETE
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		null,
		0x00A0, // NO-BREAK SPACE
		0x00A1, // INVERTED EXCLAMATION MARK
		0x00A2, // CENT SIGN
		0x00A3, // POUND SIGN
		0x00A4, // CURRENCY SIGN
		0x00A5, // YEN SIGN
		0x00A6, // BROKEN BAR
		0x00A7, // SECTION SIGN
		0x00A8, // DIAERESIS
		0x00A9, // COPYRIGHT SIGN
		0x00AA, // FEMININE ORDINAL INDICATOR
		0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
		0x00AC, // NOT SIGN
		0x00AD, // SOFT HYPHEN
		0x00AE, // REGISTERED SIGN
		0x00AF, // MACRON
		0x00B0, // DEGREE SIGN
		0x00B1, // PLUS-MINUS SIGN
		0x00B2, // SUPERSCRIPT TWO
		0x00B3, // SUPERSCRIPT THREE
		0x00B4, // ACUTE ACCENT
		0x00B5, // MICRO SIGN
		0x00B6, // PILCROW SIGN
		0x00B7, // MIDDLE DOT
		0x00B8, // CEDILLA
		0x00B9, // SUPERSCRIPT ONE
		0x00BA, // MASCULINE ORDINAL INDICATOR
		0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
		0x00BC, // VULGAR FRACTION ONE QUARTER
		0x00BD, // VULGAR FRACTION ONE HALF
		0x00BE, // VULGAR FRACTION THREE QUARTERS
		0x00BF, // INVERTED QUESTION MARK
		0x00C0, // LATIN CAPITAL LETTER A WITH GRAVE
		0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE
		0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
		0x00C3, // LATIN CAPITAL LETTER A WITH TILDE
		0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS
		0x00C5, // LATIN CAPITAL LETTER A WITH RING ABOVE
		0x00C6, // LATIN CAPITAL LETTER AE
		0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA
		0x00C8, // LATIN CAPITAL LETTER E WITH GRAVE
		0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE
		0x00CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
		0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS
		0x00CC, // LATIN CAPITAL LETTER I WITH GRAVE
		0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE
		0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
		0x00CF, // LATIN CAPITAL LETTER I WITH DIAERESIS
		0x00D0, // LATIN CAPITAL LETTER ETH
		0x00D1, // LATIN CAPITAL LETTER N WITH TILDE
		0x00D2, // LATIN CAPITAL LETTER O WITH GRAVE
		0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE
		0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
		0x00D5, // LATIN CAPITAL LETTER O WITH TILDE
		0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS
		0x00D7, // MULTIPLICATION SIGN
		0x00D8, // LATIN CAPITAL LETTER O WITH STROKE
		0x00D9, // LATIN CAPITAL LETTER U WITH GRAVE
		0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE
		0x00DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
		0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS
		0x00DD, // LATIN CAPITAL LETTER Y WITH ACUTE
		0x00DE, // LATIN CAPITAL LETTER THORN
		0x00DF, // LATIN SMALL LETTER SHARP S
		0x00E0, // LATIN SMALL LETTER A WITH GRAVE
		0x00E1, // LATIN SMALL LETTER A WITH ACUTE
		0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX
		0x00E3, // LATIN SMALL LETTER A WITH TILDE
		0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS
		0x00E5, // LATIN SMALL LETTER A WITH RING ABOVE
		0x00E6, // LATIN SMALL LETTER AE
		0x00E7, // LATIN SMALL LETTER C WITH CEDILLA
		0x00E8, // LATIN SMALL LETTER E WITH GRAVE
		0x00E9, // LATIN SMALL LETTER E WITH ACUTE
		0x00EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX
		0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS
		0x00EC, // LATIN SMALL LETTER I WITH GRAVE
		0x00ED, // LATIN SMALL LETTER I WITH ACUTE
		0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX
		0x00EF, // LATIN SMALL LETTER I WITH DIAERESIS
		0x00F0, // LATIN SMALL LETTER ETH
		0x00F1, // LATIN SMALL LETTER N WITH TILDE
		0x00F2, // LATIN SMALL LETTER O WITH GRAVE
		0x00F3, // LATIN SMALL LETTER O WITH ACUTE
		0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX
		0x00F5, // LATIN SMALL LETTER O WITH TILDE
		0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS
		0x00F7, // DIVISION SIGN
		0x00F8, // LATIN SMALL LETTER O WITH STROKE
		0x00F9, // LATIN SMALL LETTER U WITH GRAVE
		0x00FA, // LATIN SMALL LETTER U WITH ACUTE
		0x00FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX
		0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS
		0x00FD, // LATIN SMALL LETTER Y WITH ACUTE
		0x00FE, // LATIN SMALL LETTER THORN
		0x00FF  // LATIN SMALL LETTER Y WITH DIAERESIS
	],
	charCodeToByte : []
});

// static
ISO_8859_1.charCodeToByte = SingleByteEncoder.reverseMapping(ISO_8859_1.byteToCharCode);
Charset.addCharset(new ISO_8859_1());


return ISO_8859_1;
});
define('jls/io/cs/SingleByteDecoder', ['jls/lang/Class', 'jls/lang/CharBuffer'], function (Class, CharBuffer) {

var SingleByteDecoder;
SingleByteDecoder = Class.create( /** @lends jls.io.cs.SingleByteDecoder.prototype */
{
    /**
     * Creates a character decoder.
     * 
     * @constructs
     * @class This class represents a single byte character set decoder.
     */
    initialize : function(charset, mapping) {
        this._charset = charset;
        this._mapping = mapping;
        this._replacement = '?'.charCodeAt(0);
    },
    /**
     * Decodes byte buffer and returns the character buffer.
     *
     * @param {jls.lang.ByteBuffer} input The buffer to decode.
     * @param {jls.lang.CharBuffer} [buffer] The buffer to use.
     * @returns {jls.lang.CharBuffer} The decoded character buffer.
     */
    decode : function(input, buffer) {
    	var output = buffer || CharBuffer.allocate(input.remaining() + 1, true);
    	while ((input.remaining() > 0) && (output.remaining() > 0)) {
    		var b = input.getByte();
    		var c;
    		if (b in this._mapping) {
    			c = this._mapping[b];
    		} else {
    			c = this._replacement;
    		}
    		output.putChar(c);
    	}
        return output;
    }
});


return SingleByteDecoder;
});
define('jls/io/cs/SingleByteEncoder', ['jls/lang/Class', 'jls/lang/ByteBuffer'], function (Class, ByteBuffer) {

var SingleByteEncoder;
SingleByteEncoder = Class.create( /** @lends jls.io.cs.SingleByteEncoder.prototype */
{
    /**
     * Creates a character encoder.
     * 
     * @constructs
     * @class This class represents a single byte character set encoder.
     */
    initialize : function(charset, mapping) {
        this._charset = charset;
        this._mapping = mapping;
        this._replacement = '?'.charCodeAt(0);
    },
    /**
     * Encodes a string and returns a buffer.
     *
     * @param {jls.lang.CharBuffer} input The character buffer to encode.
     * @param {jls.lang.ByteBuffer} [buffer] The buffer to use.
     * @returns {jls.lang.ByteBuffer} The encoded buffer.
     */
    encode : function(input, buffer) {
    	var output = buffer || ByteBuffer.allocate(input.remaining() + 1);
    	while ((input.remaining() > 0) && (output.remaining() > 0)) {
    		var c = input.getChar();
    		var b;
    		if (c in this._mapping) {
    			b = this._mapping[c];
    		} else {
    			b = this._replacement;
    		}
    		output.putByte(b);
    	}
        return output;
    }
});

Object.extend(SingleByteEncoder, /** @lends jls.io.cs.SingleByteEncoder */
{
    reverseMapping : function(byteToCharCode) {
    	var charCodeToByte = [];
    	for (var i = 0; i < 256; i++) {
    		var cc = byteToCharCode[i];
    		if (cc != null) {
    			charCodeToByte[cc] = i;
    		} else {
    			delete byteToCharCode[i];
    		}
    	}
    	return charCodeToByte;
    }
});
return SingleByteEncoder;
});
define('jls/io/cs/UTF_8', [
  'jls/lang/Class',
  'jls/lang/Logger',
  'jls/lang/ByteBuffer',
  'jls/lang/CharBuffer',
  'jls/io/cs/Charset'
], function (
  Class,
  Logger,
  ByteBuffer,
  CharBuffer,
  Charset
) {

var UTF_8;
UTF_8 = Class.create(Charset,
{
    initialize : function($super) {
    	$super('UTF-8');
    },
    newDecoder : function() {
        return new UTF_8.Decoder(this);
    },
    newEncoder : function() {
        return new UTF_8.Encoder(this);
    }
});

// static
Charset.addCharset(new UTF_8());

UTF_8.Decoder = Class.create(
{
    initialize : function(charset) {
        this._charset = charset;
        this._averBytes = 2.0;
        this._replacement = '?'.charCodeAt(0);
    },
    decode : function(input, buffer) {
    	var output = buffer || CharBuffer.allocate(input.remaining() + 1, true);
        //jls.logger.info('UTF_8.Decoder.decode(), input.remaining(): ' + input.remaining() + ', output.remaining(): ' + output.remaining());
    	while (input.remaining() > 0) {
    		var b = input.getByte();
            if (b <= 0x7f) {
                // nothing to do
            } else if (b <= 0xdf) {
                // TODO Check that b2 starts with 10
                b2 = input.getByte() & 0x3f;
                b = ((b & 0x1f) << 6) | b2;
            } else if (b <= 0xef) {
                b2 = input.getByte() & 0x3f;
                b3 = input.getByte() & 0x3f;
                b = ((b & 0x0f) << 12) | (b2 << 6) | b3;
            } else if (b <= 0xf7) {
                b2 = input.getByte() & 0x3f;
                b3 = input.getByte() & 0x3f;
                b4 = input.getByte() & 0x3f;
                b = ((b & 0x07) << 18) | (b2 << 12) | (b3 << 6) | b4;
            } else {
                b = this._replacement;
            }
            output.putChar(b);
    	}
        return output;
    }
});

UTF_8.Encoder = Class.create(
{
    initialize : function(charset) {
        this._charset = charset;
        this._averBytes = 2.0;
        this._replacement = '?'.charCodeAt(0);
    },
    encode : function(input, buffer) {
    	var length = Math.round(input.remaining() * this._averBytes);
    	var output = buffer || ByteBuffer.allocate(length + 1);
        Logger.getInstance().debug('UTF_8.Encoder.encode(), input.remaining(): ' + input.remaining() + ', length: ' + length + ', output.remaining(): ' + output.remaining());
    	while (input.remaining() > 0) {
    		var c = input.getChar();
            if (c <= 0x007f) {
                output.putByte(c);
            } else if (c <= 0x07ff) {
                output.putByte(0xc0 | ((c >>> 6) & 0x1f));
                output.putByte(0x80 | (c & 0x3f));
            } else if (c <= 0xffff) {
                output.putByte(0xe0 | ((c >>> 12) & 0x0f));
                output.putByte(0x80 | ((c >>> 6) & 0x3f));
                output.putByte(0x80 | (c & 0x3f));
            } else if (c <= 0x1fffff) {
                output.putByte(0xf0 | ((c >>> 18) & 0x07));
                output.putByte(0x80 | ((c >>> 12) & 0x3f));
                output.putByte(0x80 | ((c >>> 6) & 0x3f));
                output.putByte(0x80 | (c & 0x3f));
    		} else {
                output.putByte(this._replacement);
    		}
    	}
        return output;
    }
});


return UTF_8;
});
define('jls/jsunit/Assert', ['jls/lang/Class', 'jls/lang/AssertionError'], function (Class, AssertionError) {

var Assert;
/**
 * @class A set of assert methods. Messages are only displayed when an assert fails.
 * @name jls.jsunit.Assert
 */
Assert = Class.create({});

Object.extend(Assert, /** @lends jls.jsunit.Assert */
{
    /**
     * Fails a test with the given message.
     * 
     * @param {String} [message] The message associated with the failure.
     */
    fail : function(message) {
        throw new AssertionError(message);
    },
    failNotEquals : function(expected, actual, message) {
        var msg = (typeof message == 'string') ? (message + ' ') : '';
        Assert.fail(msg + 'expected:<' + expected + '> but was:<' + actual + '>');
    },
    failNotSame : function(expected, actual, message) {
        var msg = (typeof message == 'string') ? (message + ' ') : '';
        Assert.fail(msg + 'expected same:<' + expected + '> was not:<' + actual + '>');
    },
    failSame : function(message) {
        var msg = (typeof message == 'string') ? (message + ' ') : '';
        Assert.fail(msg + 'expected not same');
    },
    /**
     * Asserts that a condition is true.
     * 
     * @param {Boolean} condition The condition to verify.
     * @param {String} [message] The message associated with the assertion.
     */
    assertTrue : function(condition, message) {
        if (! condition) {
            Assert.fail(message);
        }
    },
    /**
     * Asserts that a condition is false.
     * 
     * @param {Boolean} condition The condition to verify.
     * @param {String} [message] The message associated with the assertion.
     */
    assertFalse : function(condition, message) {
        if (condition) {
            Assert.fail(message);
        }
    },
    /**
     * Asserts that a value is not null.
     * 
     * @param {Object} value The value to verify.
     * @param {String} [message] The message associated with the assertion.
     */
    assertNotNull : function(value, message) {
        if (value == null) {
            Assert.fail(message);
        }
    },
    /**
     * Asserts that two values differ.
     * 
     * @param {Object} expected The expected value.
     * @param {Object} actual The actual value.
     * @param {String} [message] The message associated with the assertion.
     */
    assertNotSame : function(expected, actual, message) {
        if (expected === actual) {
            Assert.failSame(message);
        }
    },
    /**
     * Asserts that a value is null.
     * 
     * @param {Object} value The value to verify.
     * @param {String} [message] The message associated with the assertion.
     */
    assertNull : function(value, message) {
        if (value != null) {
            Assert.fail(message);
        }
    },
    /**
     * Asserts that two values are the same.
     * 
     * @param {Object} expected The expected value.
     * @param {Object} actual The actual value.
     * @param {String} [message] The message associated with the assertion.
     */
    assertSame : function(expected, actual, message) {
        if (expected !== actual) {
            Assert.failNotSame(expected, actual, message);
        }
    },
    /**
     * Asserts that two values are equal.
     * 
     * @param {Object} expected The expected value.
     * @param {Object} actual The actual value.
     * @param {String} [message] The message associated with the assertion.
     */
    assertEquals : function(expected, actual, message) {
        if (expected != actual) {
            Assert.failNotEquals(expected, actual, message);
        }
    }
});

return Assert;
});
define('jls/jsunit/TestCase', [
  'jls/lang/Class',
  'jls/lang/AssertionError',
  'jls/jsunit/TestResult',
  'jls/jsunit/Assert'
], function (
  Class,
  AssertionError,
  TestResult,
  Assert
) {

var TestCase;
/**
 * @namespace Provides JSUnit core classes.
 * @see jls.jsunit.TestCase
 * @name jls.jsunit
 */

TestCase = Class.create( /** @lends jls.jsunit.TestCase.prototype */
{
    /**
     * Constructs a test case with the given name.
     *
     * @param {String} name The name of the test case.
     * @class A test case defines the fixture to run multiple tests.
     * The test cases can be launched by using the jls.jsunit.TestRunner class.
     * @constructs
     */
    initialize : function(name) {
        this.setName(name);
    },
    /**
     * Sets this test case name.
     * 
     * @param {String} name The name of the test case.
     * @returns {jls.jsunit.TestCase} This test case.
     */
    setName : function(name) {
        this._name = name || '';
    },
    /**
     * Returns this test case name.
     * 
     * @returns {String} The name of the test case.
     */
    getName : function() {
        return this._name;
    },
    /**
     * Sets up the fixture. This method is called before a test is executed.
     * 
     */
    setUp : function() {
    },
    /**
     * Tears down the fixture. This method is called after a test is executed.
     * 
     */
    tearDown : function() {
    },
    /**
     * Returns the test case count.
     * 
     * @returns {Number} The test case count.
     */
    countTestCases : function() {
        return 1;
    },
    runBare : function() {
        var exception = null;
		this.setUp();
        try {
            this.runTest();
        }
        catch (e) {
			exception = e;
        }
        try {
            this.tearDown();
        }
        catch (e) {
            if (exception == null) {
                exception = e;
            }
        }
        if (exception != null) {
            throw exception;
        }
    },
    /**
     * Override to run the test and assert its state.
     */
    runTest : function() {
        Assert.assertNotNull(this.getName(), 'TestCase.name cannot be null');
        Assert.assertTrue((this.getName() in this) && (typeof this[this.getName()] == 'function'), 'Function "' + this.getName() + '" not found');
        this[this.getName()]();
    }
});


return TestCase;
});
define('jls/jsunit/TestFailure', ['jls/lang/Class'], function (Class) {

var TestFailure;
TestFailure = Class.create(
{
    initialize : function(failedTest, thrownException) {
        this._failedTest = failedTest;
        this._thrownException = thrownException;
    },
    failedTest : function() {
        return this._failedTest;
    },
    thrownException : function() {
        return this._thrownException;
    }
});


return TestFailure;
});
define('jls/jsunit/TestResult', ['jls/lang/Class', 'jls/lang/AssertionError', 'jls/jsunit/TestFailure'], function (Class, AssertionError, TestFailure) {

var TestResult;
TestResult = Class.create(
{
    initialize : function() {
		this._errors = [];
        this._failures = [];
        this._runTests = 0;
    },
    run : function(test) {
        this.startTest(test);
        try {
            test.runBare();
        }
        catch (e) {
            if (e instanceof AssertionError) {
                this.addFailure(test, e);
            } else {
                this.addError(test, e);
            }
        }
        this.endTest(test);
    },
    startTest : function(test) {
        this._runTests += test.countTestCases();
    },
    endTest : function(test) {
    },
    addFailure : function(test, e) {
        this._failures.push(new TestFailure(test, e));
    },
    addError : function(test, e) {
        this._errors.push(new TestFailure(test, e));
    },
    errorCount : function() {
		return this._errors.length;
    },
    failureCount : function() {
		return this._failures.length;
    },
    runCount : function() {
		return this._runTests;
    },
    wasSuccessful : function() {
		return this.errorCount() == 0 && this.failureCount() == 0;
    },
    toString : function() {
		return '' + this.runCount() + ' test(s): ' + this.errorCount() + ' error(s) and ' + this.failureCount() + ' failure(s)';
    },
    getErrors : function() {
		return this._errors;
    },
    getFailures : function() {
		return this._failures;
    }
});

return TestResult;
});
define('jls/jsunit/TestSuite', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/AssertionError',
  'jls/jsunit/TestCase',
  'jls/jsunit/TestResult'
], function (
  Class,
  Exception,
  AssertionError,
  TestCase,
  TestResult
) {

var TestSuite;
TestSuite = Class.create(
{
    initialize : function() {
        this._testCases = [];
    },
    addTest : function(test) {
        this._testCases.push(test);
        return this;
    },
    testCount : function() {
        return this._testCases.length;
    },
    addTestSuite : function(tcClass) {
        if (typeof tcClass == 'string') {
            tcClass = require(tcClass);
        }
        if (typeof tcClass != 'function') {
            throw new Exception('Invalid test case class');
        }
        for (var name in tcClass.prototype) {
            if (! (name.startsWith('test') && (typeof tcClass.prototype[name] == 'function'))) {
                continue;
            }
            this.addTest(new tcClass(name));
        }
        return this;
    },
    run : function(tr) {
        for (var i = 0; i < this._testCases.length; i++) {
            //jls.logger.info('running: ' + jls.loader.getClassname(this._testCases[i]) + '(' + this._testCases[i].getName() + ')');
            tr.run(this._testCases[i]);
        }
    }
});


return TestSuite;
});
define('jls/lang/AssertionError', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var AssertionError;
/**
 * @augments jls.lang.Exception
 * @class Thrown to indicate that an assertion has failed.
 * @name jls.lang.AssertionError
 */
AssertionError = Class.create(Exception, /** @lends jls.lang.AssertionError.prototype */
{
    initialize : function($super, message, cause) {
        $super(message, cause);
    }
});

return AssertionError;
});
define('jls/lang/Bean', ['jls/lang/Class'], function(Class) {

    var Bean = Class.create({
        clone : function() {
            var clazz = this.constructor;
            var instance = new clazz();
            for (var key in this) {
                if (typeof this[key] != 'function') {
                    instance[key] = this[key];
                }
            }
            return instance;
        },
        equals : function(b) {
            if (b === this) {
                return true;
            }
            for (var key in this) {
                if ((typeof this[key] != 'function') && (b[key] != this[key])) {
                    return false;
                }
            }
            return true;
        }
    });

    return Bean;
});
define('jls/lang/Buffer', [
  'jls/lang/Class',
  'jls/lang/IllegalArgumentException',
  'jls/lang/BufferOverflowException',
  'jls/lang/BufferUnderflowException'
], function (
  Class,
  IllegalArgumentException,
  BufferOverflowException,
  BufferUnderflowException
) {

var Buffer;
/**
 * @class A container for data of a specific primitive type. 
 * @see jls.lang.ByteBuffer
 * @see jls.lang.CharBuffer
 * @name jls.lang.Buffer
 */
Buffer = Class.create(/** @lends jls.lang.Buffer.prototype */
{
    initialize : function(capacity, limit, position, offset) {
        this._capacity = (typeof capacity != 'undefined') ? capacity : 0;
        this._limit = (typeof limit != 'undefined') ? limit : this._capacity;
        this._position = position || 0;
        this._offset = offset || 0;
    },
    /**
     * Returns this buffer's offset into the native byte array.
     * 
     * @returns {Number} The offset of this buffer.
     */
    getOffset : function() {
        return this._offset;
    },
    /**
     * Returns the byte array position, considering the offset.
     * 
     * @returns {Number} The position of the byte array.
     */
    offset : function() {
        return this._offset + this._position;
    },
    /**
     * Clears this buffer, setting the position to zero and the limit to the capacity.
     * 
     * @returns {jls.lang.Buffer} This buffer.
     */
    clear : function() {
        this._position = 0;
        this._limit = this._capacity;
        return this;
    },
    /**
     * Flips this buffer, setting the limit to the position and the position to zero.
     * 
     * @returns {jls.lang.Buffer} This buffer.
     */
    flip : function() {
        this._limit = this._position;
        this._position = 0;
        return this;
    },
    /**
     * Returns this buffer's position.
     * 
     * @returns {Number} The position of this buffer.
     */
    position : function() {
        return this._position;
    },
    /**
     * Returns this buffer's capacity.
     * 
     * @returns {Number} The capacity of this buffer.
     */
    capacity : function() {
        return this._capacity;
    },
    /**
     * Returns this buffer's limit.
     * 
     * @returns {Number} The limit of this buffer.
     */
    limit : function() {
        return this._limit;
    },
    /**
     * Returns this buffer's remaining.
     * 
     * @returns {Number} The remaining of this buffer.
     */
    remaining : function() {
        return this._limit - this._position;
    },
    /**
     * Increments this buffer's position and then returns the resulting position.
     * 
     * @param {Number} d The delta to increment.
     * @returns {Number} The position of this buffer.
     */
    incrementPosition : function(d) {
        if (this._position + d > this._limit) {
            throw new IllegalArgumentException();
        }
        this._position += d;
        return this._position;
    },
    /**
     * Sets this buffer's position.
     * 
     * @param {Number} position The position to set.
     * @returns {jls.lang.Buffer} This buffer.
     */
    setPosition : function(position) {
        if (position > this._limit) {
            throw new IllegalArgumentException();
        }
        this._position = position;
        return this;
    },
    /**
     * Sets this buffer's limit.
     * 
     * @param {Number} limit The limit to set.
     * @returns {jls.lang.Buffer} This buffer.
     */
    setLimit : function(limit) {
        if (limit > this._capacity) {
            throw new IllegalArgumentException();
        }
        this._limit = limit;
        return this;
    }
});

Object.extend(Buffer, /** @lends jls.lang.Buffer */
{
    // Byte order constants.
    /*
     * The bytes are ordered from most significant to least significant. 
     */
    BIG_ENDIAN : 1,
    /*
     * The bytes are ordered from least significant to most significant.
     */
    LITTLE_ENDIAN : 2
});

return Buffer;
});
define('jls/lang/BufferOverflowException', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var BufferOverflowException;
/**
 * @name jls.lang.BufferOverflowException
 * @augments jls.lang.Exception
 * @class Thrown to indicate that the target buffer's limit is reached.
 */
BufferOverflowException = Class.create(Exception, /** @lends jls.lang.BufferOverflowException.prototype */
{
    initialize : function($super, message, cause) {
        $super(message, cause);
    }
});

return BufferOverflowException;
});
define('jls/lang/BufferUnderflowException', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var BufferUnderflowException;
/**
 * @name jls.lang.BufferUnderflowException
 * @augments jls.lang.Exception
 * @class Thrown to indicate that the target buffer's limit is reached.
 */
BufferUnderflowException = Class.create(Exception, /** @lends jls.lang.BufferUnderflowException.prototype */
{
    initialize : function($super, message, cause) {
        $super(message, cause);
    }
});

return BufferUnderflowException;
});
define('jls/lang/ByteBuffer', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Buffer',
  'jls/lang/IllegalArgumentException',
  'jls/lang/BufferOverflowException',
  'jls/lang/BufferUnderflowException'
], function (
  Class,
  Exception,
  Buffer,
  IllegalArgumentException,
  BufferOverflowException,
  BufferUnderflowException
) {

var ByteBuffer;
// Late binding
var Charset, CharBuffer;
require(['jls/io/cs/Charset', 'jls/lang/CharBuffer'], function(cs, cb) {
    Charset = cs;
    CharBuffer = cb;
});

/**
 * @augments jls.lang.Buffer
 * @class The buffer class provides facilities to get and put datas from/to a native byte array.
 * @name jls.lang.ByteBuffer
 */
ByteBuffer = Class.create(Buffer, /** @lends jls.lang.ByteBuffer.prototype */
{
    initialize : function($super, barray, offset, length, limit, position, byteOrder) {
        if (! (barray instanceof _native.core.ByteArray)) {
            throw new Exception('Invalid barray argument (' + (typeof barray) + ')');
        }
        this._barray = barray;
        offset = offset || 0;
        var capacity = (typeof length != 'undefined') ? length : this._barray.size() - offset;
        $super(capacity, limit, position, offset);
        this._byteOrder = (typeof byteOrder != 'undefined') ? byteOrder : ByteBuffer.DEFAULT_BYTE_ORDER;
    },
    /**
     * Returns the native byte array of this buffer.
     * 
     * @returns {_native.core.ByteArray} The native byte array.
     */
    byteArray : function() {
        return this._barray;
    },
    /**
     * Free the associated byte array.
     * 
     * @returns {jls.lang.Buffer} This buffer.
     */
    free : function() {
        this._barray.free();
        return this;
    },
    /**
     * Creates a new buffer sharing the native byte array.
     * 
     * @returns {jls.lang.Buffer} The new buffer.
     */
    duplicate : function() {
        return new ByteBuffer(this._barray, this._offset, this._capacity, this._limit, this._position, this._byteOrder);
    },
    /**
     * Creates a new buffer starting at the current position and with the remaining bytes.
     * 
     * @returns {jls.lang.Buffer} The new buffer.
     */
    slice : function() {
        return new ByteBuffer(this._barray, this.position(), this.remaining(), this.remaining(), 0, this._byteOrder);
    },
    /**
     * Puts a byte into this buffer at the current position, and then increments the position.
     * 
     * @param {Number} b The byte to put.
     * @returns {jls.lang.Buffer} This buffer.
     */
    putByte : function(b) {
        if (this.remaining() < 1) {
            throw new BufferOverflowException();
        }
        this._barray.put(this.offset(), b);
        this._position++;
        return this;
    },
    /**
     * Gets a byte from this buffer at the current position, and then increments the position.
     * 
     * @param {Boolean} signed Whether the byte to get is signed.
     * @returns {Number} The byte.
     */
    getByte : function(signed) {
        if (this.remaining() < 1) {
            throw new BufferUnderflowException();
        }
        var b = this._barray.get(this.offset());
        this._position++;
        return (signed && (b >= 0x80)) ? b - 0x100 : b;
    },
    putString : function(s, csn) {
        if (this.remaining() < s.length) {
            throw new BufferOverflowException();
        }
        // TODO Use cache
    	var cs = csn ? Charset.forName(csn) : Charset.defaultCharset();
    	var encoder = cs.newEncoder();
        var cb = CharBuffer.wrap(s);
        encoder.encode(cb, this);
        return this;
    },
    getString : function(csn) {
        // TODO Use cache
    	var cs = csn ? Charset.forName(csn) : Charset.defaultCharset();
    	var decoder = cs.newDecoder();
        var cb = decoder.decode(this);
    	cb.flip();
    	return cb.toNewString();
    },
    putBuffer : function(buffer, length) {
		length = length || buffer.remaining();
        //jls.logger.info('ByteBuffer.putBuffer(' + length + ')');
        if (this.remaining() < length) {
            throw new BufferOverflowException();
        }
        this._barray.memcpy(this.offset(), buffer.byteArray(), buffer.position(), length);
        this._position += length;
        buffer.incrementPosition(length);
        return this;
    },
    putByteArray : function(ba) {
        if (this.remaining() < ba.length) {
            throw new BufferOverflowException();
        }
        for (var i = 0; i < ba.length; i++) {
            this._barray.put(this.offset() + i, ba[i]);
        }
        this._position += ba.length;
        return this;
    },
    getByteArray : function(length) {
        if (length) {
            if (this.remaining() < length) {
                throw new BufferUnderflowException();
            }
        } else {
            length = this.remaining();
        }
        var ba = [];
        for (var i = 0; i < length; i++) {
            ba.push(this._barray.get(this.offset() + i));
        }
        this._position += length;
        return ba;
    },
    getByteOrder : function() {
        return this._byteOrder;
    },
    setByteOrder : function(byteOrder) {
        this._byteOrder = byteOrder;
    },
    putShort : function(value) {
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            this.putByte((value >> 8) & 0xff);
            this.putByte(value & 0xff);
        } else {
            this.putByte(value & 0xff);
            this.putByte((value >> 8) & 0xff);
        }
    },
    getShort : function(signed) {
        var value;
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            value = this.getByte() << 8;
            value |= this.getByte();
        } else {
            value = this.getByte();
            value |= this.getByte() << 8;
        }
        return (signed && (value >= 0x8000)) ? value - 0x10000 : value;
    },
    putInt : function(value) {
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            this.putByte((value >> 24) & 0xff);
            this.putByte((value >> 16) & 0xff);
            this.putByte((value >> 8) & 0xff);
            this.putByte(value & 0xff);
        } else {
            this.putByte(value & 0xff);
            this.putByte((value >> 8) & 0xff);
            this.putByte((value >> 16) & 0xff);
            this.putByte((value >> 24) & 0xff);
        }
    },
    getInt : function(signed) {
        var value;
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            value = this.getByte() << 24;
            value |= this.getByte() << 16;
            value |= this.getByte() << 8;
            value |= this.getByte();
        } else {
            value = this.getByte();
            value |= this.getByte() << 8;
            value |= this.getByte() << 16;
            value |= this.getByte() << 24;
        }
        return (signed && (value >= 0x80000000)) ? value - 0x100000000 : value;
    },
    /*
     * Bitwise operators treat their operands as a set of 32 bits (zeros and ones), rather than as decimal,
     * hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001.
     * Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values. 
     */
    putLong : function(value) {
        // var hi = (value - (value % 0x100000000)) / 0x100000000;
        var hi = value / 0x100000000;
        if (value >= 0) {
            hi = Math.floor(hi);
        } else {
            hi = Math.ceil(hi);
            if (hi == 0) {
                hi = -1; // -0 !
            }
        }
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            this.putByte((hi >> 24) & 0xff);
            this.putByte((hi >> 16) & 0xff);
            this.putByte((hi >> 8) & 0xff);
            this.putByte(hi & 0xff);
            this.putByte((value >> 24) & 0xff);
            this.putByte((value >> 16) & 0xff);
            this.putByte((value >> 8) & 0xff);
            this.putByte(value & 0xff);
        } else {
            this.putByte(value & 0xff);
            this.putByte((value >> 8) & 0xff);
            this.putByte((value >> 16) & 0xff);
            this.putByte((value >> 24) & 0xff);
            this.putByte(hi & 0xff);
            this.putByte((hi >> 8) & 0xff);
            this.putByte((hi >> 16) & 0xff);
            this.putByte((hi >> 24) & 0xff);
        }
    },
    getLong : function(signed) {
        var value;
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            value = this.getByte() * 0x100000000000000;
            value |= this.getByte() * 0x1000000000000;
            value |= this.getByte() * 0x10000000000;
            value |= this.getByte() * 0x100000000;
            value |= this.getByte() << 24;
            value |= this.getByte() << 16;
            value |= this.getByte() << 8;
            value |= this.getByte();
        } else {
            value = this.getByte();
            value |= this.getByte() << 8;
            value |= this.getByte() << 16;
            value |= this.getByte() << 24;
            value |= this.getByte() * 0x100000000;
            value |= this.getByte() * 0x10000000000;
            value |= this.getByte() * 0x1000000000000;
            value |= this.getByte() * 0x100000000000000;
        }
        return (signed && (value >= 0x8000000000000000)) ? value - 0x10000000000000000 : value;
    },
    putPointer : function(value) {
        switch (ByteBuffer.POINTER_SIZE) {
        case 4:
            this.putInt(value);
            break;
        case 8:
            this.putLong(value);
            break;
        default:
            throw new Exception('Unimplemented pointer size (' + ByteBuffer.POINTER_SIZE + ')');
        }
    },
    getPointer : function() {
        switch (ByteBuffer.POINTER_SIZE) {
        case 4:
            return this.getInt(false);
        case 8:
            return this.getLong(false);
        default:
            throw new Exception('Unimplemented pointer size (' + ByteBuffer.POINTER_SIZE + ')');
        }
    }
});

Object.extend(ByteBuffer, /** @lends jls.lang.ByteBuffer */
{
    /**
     * Allocates a new buffer.
     * 
     * @param {Number} capacity The capacity of the byte array.
     * @returns {jls.lang.Buffer} The new buffer.
     */
    allocate : function(capacity) {
        return ByteBuffer.wrap(new _native.core.ByteArray(capacity));
    },
    /**
     * Wraps an existing native byte array into a new buffer.
     * 
     * @param {ByteArray} barray The native byte array to wrap.
     * @param {Number} offset The offset of the byte array to use for this buffer.
     * @param {Number} length The length of the buffer.
     * @returns {jls.lang.Buffer} The new buffer.
     */
    wrap : function(barray, offset, length) {
        offset = offset || 0;
        length = length || (barray.size() - offset);
        return new ByteBuffer(barray, offset, length);
    },
    /**
     * TODO Remove
     * @deprecated
     */
    fromString : function(s, csn) {
        var buffer = ByteBuffer.allocate(s.length * 2);
        buffer.putString(s, csn);
        buffer.flip();
        return buffer;
    },
    DEFAULT_BYTE_ORDER : (_native.core.properties['cpu.endian'] == 'big' ? Buffer.BIG_ENDIAN : Buffer.LITTLE_ENDIAN),
    POINTER_SIZE : parseInt(_native.core.properties['cpu.pointer.size'])
});


return ByteBuffer;
});
define('jls/lang/CharBuffer', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Buffer',
  'jls/lang/ByteBuffer',
  'jls/lang/IllegalArgumentException',
  'jls/lang/BufferOverflowException',
  'jls/lang/BufferUnderflowException'
], function (
  Class,
  Exception,
  Buffer,
  ByteBuffer,
  IllegalArgumentException,
  BufferOverflowException,
  BufferUnderflowException
) {

var CharBuffer;
/**
 * @augments jls.lang.Buffer
 * @class The buffer class provides facilities to get and put datas from/to a native string.
 * @name jls.lang.CharBuffer
 */
CharBuffer = Class.create(Buffer, /** @lends jls.lang.CharBuffer.prototype */
{
    initialize : function($super, barray, offset, length, limit, position) {
        if (! (barray instanceof _native.core.ByteArray)) {
            throw new Exception('Invalid barray argument (' + (typeof barray) + ')');
        }
        this._barray = barray;
        offset = offset || 0;
        var capacity = (typeof length != 'undefined') ? length : (this._barray.size() >>> 1) - offset;
        $super(capacity, limit, position, offset);
        this._byteOrder = CharBuffer.DEFAULT_BYTE_ORDER;
    },
    /**
     * Returns the native byte array of this buffer.
     * 
     * @returns {_native.core.ByteArray} The native byte array.
     */
    byteArray : function() {
        return this._barray;
    },
    /**
     * Free the associated byte array.
     * 
     * @returns {jls.lang.Buffer} This buffer.
     */
    free : function() {
        this._barray.free();
        return this;
    },
    /**
     * Creates a new buffer sharing the native string.
     * 
     * @returns {jls.lang.Buffer} The new buffer.
     */
    duplicate : function() {
        return new CharBuffer(this._barray, this._offset, this._capacity, this._limit, this._position);
    },
    /**
     * Creates a new buffer starting at the current position and with the remaining character.
     * 
     * @returns {jls.lang.Buffer} The new buffer.
     */
    slice : function() {
        return new CharBuffer(this._barray, this.position(), this.remaining());
    },
    /**
     * Puts a character into this buffer at the current position, and then increments the position.
     * 
     * @param {Number} c The character code to put.
     * @returns {jls.lang.Buffer} This buffer.
     */
    putChar : function(c) {
        if (this.remaining() < 1) {
            throw new BufferOverflowException();
        }
        if (typeof c == 'string') {
        	if (c.length != 1) {
                throw new Exception('Invalid character argument');
        	}
        	c = c.charCodeAt(0);
        }
        var os = this.offset() * 2;
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            this._barray.put(os, (c >>> 8) & 0xff);
            this._barray.put(os + 1, c & 0xff);
        } else {
            this._barray.put(os, c & 0xff);
            this._barray.put(os + 1, (c >>> 8) & 0xff);
        }
        this._position++;
        return this;
    },
    /**
     * Gets a character from this buffer at a specified position.
     * 
     * @param {Number} index The position of the character to read.
     * @returns {Number} The character code.
     */
    getCharAt : function(index) {
        if (index > this.limit()) {
            throw new Exception('Index out of bound');
        }
        var value;
        var os = (this.getOffset() + index) * 2;
        if (this._byteOrder == Buffer.BIG_ENDIAN) {
            value = this._barray.get(os) << 8;
            value |= this._barray.get(os + 1);
        } else {
            value = this._barray.get(os);
            value |= this._barray.get(os + 1) << 8;
        }
        return value;
    },
    /**
     * Gets a character from this buffer at the current position, and then increments the position.
     * 
     * @returns {Number} The character code.
     */
    getChar : function() {
        if (this.remaining() < 1) {
            throw new BufferUnderflowException();
        }
        var value = this.getCharAt(this.position());
        this._position++;
        return value;
    },
    putString : function(s) {
        if (this.remaining() < s.length) {
            throw new BufferOverflowException();
        }
        // TODO wrap + memcpy?
    	for (var i = 0; i < s.length; i++) {
    		this.putChar(s.charCodeAt(i));
    	}
        return this;
    },
    getString : function(length) {
        if (length) {
            if (this.remaining() < length) {
                throw new BufferUnderflowException();
            }
        } else {
            length = this.remaining();
        }
        /*var value = '';
    	while (--length >= 0) {
    		value += String.fromCharCode(this.getChar());
    	}*/
        //jls.logger.warn('getString() p: ' + this.position() + ', l: ' + length);
        var value = this._barray.getChars(this.position() * 2, length);
        this._position += length;
        return value;
    },
    putBuffer : function(buffer, length) {
		length = length || buffer.remaining();
        if (this.remaining() < length) {
            throw new BufferOverflowException();
        }
        this._barray.memcpy(this.offset() * 2, buffer.byteArray(), buffer.position() * 2, length * 2);
        this._position += length;
        buffer.incrementPosition(length);
        return this;
    },
    toNewString : function(length) {
		length = length || this.limit();
    	if (this.getOffset() != 0) {
            throw new Exception('Invalid CharBuffer (offset != 0)');
    	}
        return this._barray.toNewChars(length);
    },
    toString : function() {
        return this.getString();
    }
});

Object.extend(CharBuffer, /** @lends jls.lang.CharBuffer */
{
    /**
     * Allocates a new buffer.
     * 
     * @param {Number} capacity The capacity of the character buffer.
     * @returns {jls.lang.Buffer} The new buffer.
     */
    allocate : function(capacity, adoptable) {
        return CharBuffer.wrap(new _native.core.ByteArray((capacity + 1) * 2, adoptable));
    },
    /**
     * Wraps an existing native byte array into a new character buffer.
     * 
     * @param {_native.core.ByteArray} barray The native byte array to wrap.
     * @param {Number} offset The offset of the byte array to use for this buffer.
     * @param {Number} length The length of the buffer.
     * @returns {jls.lang.Buffer} The new buffer.
     */
    wrap : function(barray, offset, length) {
        if (typeof barray == 'string') {
            length = length || barray.length;
            //jls.logger.trace('CharBuffer.wrap("' + barray + '")');
        	barray = new _native.core.ByteArray(barray);
            //jls.logger.trace('CharBuffer.wrap(), barray.size(): ' + barray.size());
            var buffer = new CharBuffer(barray, offset, length);
            //jls.logger.trace('CharBuffer.wrap(), buffer.remaining(): ' + buffer.remaining() + ', buffer.capacity(): ' + buffer.capacity());
            return buffer;
        }
        return new CharBuffer(barray, offset, length);
    },
    // Byte order constants.
    DEFAULT_BYTE_ORDER : Buffer.LITTLE_ENDIAN
});


return CharBuffer;
});
define('jls/lang/Class', null, function() {
    /*
     * Based on Alex Arnell's inheritance implementation.
     * From: Prototype JavaScript framework, version 1.7 (c) 2005-2010 Sam Stephenson
     * For details, see the Prototype web site: http://www.prototypejs.org/
     */

    // Late binding
    var Exception;
    require([ 'jls/lang/Exception' ], function(e) {
        Exception = e;
    });

    var IS_DONTENUM_BUGGY = (function() {
        for ( var p in {
            toString : 1
        }) {
            if (p === 'toString')
                return false;
        }
        return true;
    })();

    function subclass() {
    }
    /**
     * @class Provides Class management.
     * @name jls.lang.Class
     */
    var Class = { /** @lends jls.lang.CharBuffer */
        /**
         * Returns the created class.
         * @param {Object} desc The class description.
         * @returns {Object} The created class.
         */
        create : function() {
            var parent = null, properties = Array.from(arguments);
            if (Object.isFunction(properties[0]))
                parent = properties.shift();

            function klass() {
                this.initialize.apply(this, arguments);
            }

            Object.extend(klass, Class.Methods);
            klass.superclass = parent;
            klass.subclasses = [];

            if (parent) {
                subclass.prototype = parent.prototype;
                klass.prototype = new subclass;
                parent.subclasses.push(klass);
            }

            for ( var i = 0, length = properties.length; i < length; i++)
                klass.addMethods(properties[i]);

            if (!klass.prototype.initialize)
                klass.prototype.initialize = Class.emptyFunction;

            klass.prototype.constructor = klass;
            return klass;
        },
        Methods : {
            addMethods : function(source) {
                var ancestor = this.superclass && this.superclass.prototype, properties = Object.keys(source);

                if (IS_DONTENUM_BUGGY) {
                    if (source.toString != Object.prototype.toString)
                        properties.push("toString");
                    if (source.valueOf != Object.prototype.valueOf)
                        properties.push("valueOf");
                }

                for ( var i = 0, length = properties.length; i < length; i++) {
                    var property = properties[i], value = source[property];
                    if (ancestor && Object.isFunction(value) && value.argumentNames()[0] == "$super") {
                        var method = value;
                        value = (function(m) {
                            return function() {
                                return ancestor[m].apply(this, arguments);
                            };
                        })(property).wrap(method);

                        value.valueOf = method.valueOf.bind(method);
                        value.toString = method.toString.bind(method);
                    }
                    this.prototype[property] = value;
                }

                return this;
            }
        },
        // jls specific
        emptyFunction : function() {
        },
        notAvailableFunction : function() {
            throw new Exception('Function not available');
        },
        abstractMethod : function() {
            throw new Exception('Abstract method');
        }
    };

    return Class;
});define('jls/lang/IllegalArgumentException', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var IllegalArgumentException;
/**
 * @name jls.lang.IllegalArgumentException
 * @augments jls.lang.Exception
 * @class Thrown to indicate that a method has been passed an illegal or inappropriate argument.
 */
IllegalArgumentException = Class.create(Exception, /** @lends jls.lang.IllegalArgumentException.prototype */
{
    initialize : function($super, message, cause) {
        $super(message, cause);
    }
});

return IllegalArgumentException;
});
define('jls/lang/Logger', ['jls/lang/Class'], function (Class) {

var Logger;
/**
 * @class Default logger implementation.
 * A Logger object is used to log messages for a specific system or application component.
 * @name jls.lang.Logger
 */
Logger = Class.create(/** @lends jls.lang.Logger.prototype */
{
    initialize : function(name, level) {
        this._name = name || '';
        this._level = level || Logger.INFO;
    },
    getLogLevel : function() {
        return this._level;
    },
    setLogLevel : function(level) {
        if (typeof level == 'number') {
            this._level = level;
        } else if (typeof level == 'string') {
            level = level.toUpperCase();
            if (level in Logger) {
                this._level = Logger[level];
            }
        }
    },
    /**
     * Tells if the log level trace is enabled.
     * 
     * @returns {Boolean} true if the log level trace is enabled; false otherwise.
     */
    isTraceEnabled : function() {
        return this.isEnabledFor(Logger.TRACE);
    },
    /**
     * Tells if the log level debug is enabled.
     * 
     * @returns {Boolean} true if the log level debug is enabled; false otherwise.
     */
    isDebugEnabled : function() {
        return this.isEnabledFor(Logger.DEBUG);
    },
    isEnabledFor : function(level) {
        return this._level <= level;
    },
    /**
     * Logs a specified message using the trace level.
     * 
     * @param {String} msg The message to log.
     */
    trace : function(msg) {
        this.log(Logger.TRACE, msg);
    },
    /**
     * Logs a specified message using the debug level.
     * 
     * @param {String} msg The message to log.
     */
    debug : function(msg) {
        this.log(Logger.DEBUG, msg);
    },
    /**
     * Logs a specified message using the info level.
     * 
     * @param {String} msg The message to log.
     */
    info : function(msg) {
        this.log(Logger.INFO, msg);
    },
    /**
     * Logs a specified message using the warn level.
     * 
     * @param {String} msg The message to log.
     */
    warn : function(msg) {
        this.log(Logger.WARN, msg);
    },
    /**
     * Logs a specified message using the error level.
     * 
     * @param {String} msg The message to log.
     */
    error : function(msg) {
        this.log(Logger.ERROR, msg);
    },
    logObject : function(level, msg, o) {
        if (this._level > level) {
            return;
        }
        this.log(level, msg + ': ' + o);
        for (var k in o) {
            if (typeof (o[k]) == 'function') {
                this.log(level, ' ' + k + '()');
            } else {
                this.log(level, ' ' + k + ': ' + o[k]);
            }
        }
    },
    logBuffer : function(level, buffer, message) {
        if (this._level > level) {
            return;
        }
        var buffer = buffer.slice();
        this.log(level, (message ? message : 'buffer') + ' (' + buffer.remaining() + '):');
        var w = 16;
        var hex = '0123456789abcdef';
        for (var l = 0; buffer.remaining() > 0; l += w) {
            var lineHex = '';
            var lineAsc = '';
            for (var c = 0; c < w; c++) {
                if (buffer.remaining() == 0) {
                    lineHex += '   ';
                    lineAsc += ' ';
                    continue;
                }
                var b = buffer.getByte();
                lineHex += hex.charAt(b >> 4) + hex.charAt(b & 0x0f) + ' ';
                lineAsc += b > 31 && b < 128 ? String.fromCharCode(b) : ' ';
            }
            this.log(level, lineHex + lineAsc);
        }
    },
    log : function(level, msg) {
        if (this._level > level) {
            return;
        }
        /*if ((level < jls.lang.Logger.FINEST) || (level > jls.lang.Logger.ERROR)) {
            throw new jls.lang.Exception("Invalid log level " + level);
        }*/
        _native.core.log(level, msg);
    }
});

/*
 * Could be used as the following:
 * new jls.lang.Exception().printStackTrace(new jls.lang.Logger.PrintStream(jls.logger, jls.lang.Logger.WARN));
 */
Logger.PrintStream = Class.create({
    initialize : function(logger, level) {
        this._logger = logger;
        this._level = level || Logger.DEBUG;
        this._buffer = null;
    },
    flush : function() {
        if (this._buffer != null) {
            this._logger.log(this._level, this._buffer);
            this._buffer = null;
        }
        return this;
    },
    print : function(s) {
        if (this._buffer == null) {
            this._buffer = s;
        } else {
            this._buffer += s;
        }
        if (s.indexOf('\n') >= 0) {
            this.flush();
        }
        return s.length;
    },
    println : function(s) {
        if (s) {
            return this.print(s + Logger.PrintStream.separator);
        } else {
            return this.print(Logger.PrintStream.separator);
        }
    }
});

Object.extend(Logger.PrintStream,
{
    separator : _native.core.properties['line.separator']
});

Object.extend(Logger, /** @lends jls.lang.Logger */
{
    _instance : null,
    _cache : {},
    getInstance : function() {
        if (Logger._instance == null) {
            Logger._instance = Logger.getLogger('default');
            Logger._instance.setLogLevel(Logger.WARN);
        }
        return Logger._instance;
    },
    /**
     * Returns a logger for the specified name.
     * 
     * @param {String} name the name for the logger.
     * @returns {jls.lang.Logger} a logger.
     */
    getLogger : function(name) {
        if (name in Logger._cache) {
            return Logger._cache[name];
        }
        return Logger._cache[name] = new Logger(name);
    },
    /**
     * The finest log level.
     * @type Number
     */
    FINEST: 1,
    /**
     * The fine log level.
     * @type Number
     */
    FINE:   2,
    /**
     * The trace log level.
     * @type Number
     */
    TRACE:  3,
    /**
     * The debug log level.
     * @type Number
     */
    DEBUG:  4,
    /**
     * The info log level.
     * @type Number
     */
    INFO:   5,
    /**
     * The warn log level.
     * @type Number
     */
    WARN:   6,
    /**
     * The error log level.
     * @type Number
     */
    ERROR:  7
});


return Logger;
});
define('jls/lang/Struct', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/ByteBuffer'], function (Class, Exception, ByteBuffer) {

var Struct;
/*
 * TODO Struct of Struct
 */
Struct = Class.create( /** @lends jls.lang.Struct.prototype */
{
    /**
     * Creates a structure.
     * 
     * @param {Array} structDef The structure definition.
     * @param {jls.lang.ByteBuffer} [buffer] The buffer to use for this structure.
     * @constructs
     * @class This class represents a structure. A structure specifies the format of a record,
     * including the names and types of its members, and the order in which they are stored.
     */
    initialize : function(structDef, buffer) {
        structDef = structDef || [];
        this._struct = {};
        var position = 0;
        for (var i = 0; i < structDef.length; i++) {
            var def = structDef[i];
            if (! (def.type in Struct.TYPE_SIZE)) {
                throw new Exception('Invalid type ' + def.type);
            }
            var size = Struct.TYPE_SIZE[def.type];
            var length = ('length' in def) ? def.length : 1;
            this._struct[def.name] = {
                position: position,
                type: def.type,
                length: length
            };
            position += size * length;
            //jls.logger.warn('Struct() ' + def.name + ', ' + def.type + ', ' + size + ', ' + position);
        }
        this._size = position;
        if (buffer) {
            if (buffer.remaining() < this._size) {
                throw new Exception('Remaining buffer size too small (' + buffer.remaining() + '<' + this._size + ')');
            }
            this._buffer = buffer.slice();
        } else {
            this._buffer = ByteBuffer.allocate(this._size);
        }
    },
    /**
     * Returns the buffer.
     *
     * @returns {jls.lang.ByteBuffer} The buffer.
     */
    buffer : function() {
        return this._buffer;
    },
    clear : function() {
        this._buffer.clear();
        this._buffer.setLimit(this._size);
    },
    /**
     * Returns the size of the struct.
     *
     * @returns {Number} The size.
     */
    size : function() {
        return this._size;
    },
    has : function(name) {
        return (typeof name == 'string') && (name in this._struct);
    },
    getFieldPosition : function(name) {
        if (! (name in this._struct)) {
            throw new Exception('Invalid name ' + name);
        }
        return this._struct[name].position;
    },
    getFieldSize : function(name) {
        if (! (name in this._struct)) {
            throw new Exception('Invalid name ' + name);
        }
        var d = this._struct[name];
        return d.length * Struct.TYPE_SIZE[d.type];
    },
    /**
     * Gets a field in this structure.
     *
     * @param {String} name The field name.
     * @param {Number} [index] The index of the value to get.
     * @returns {Number|String} The field value.
     */
    get : function(name, index) {
        if (! (name in this._struct)) {
            throw new Exception('Invalid name ' + name);
        }
        var d = this._struct[name];
        this._buffer.setPosition(d.position);
        switch (d.type) {
        case 'SignedByte':
            return this._buffer.getByte(true);
        case 'UnsignedByte':
            return this._buffer.getByte(false);
        case 'SignedShort':
            return this._buffer.getShort(true);
        case 'UnsignedShort':
            return this._buffer.getShort(false);
        case 'SignedInt':
            return this._buffer.getInt(true);
        case 'UnsignedInt':
            return this._buffer.getInt(false);
        case 'SignedLong':
            return this._buffer.getLong(true);
        case 'UnsignedLong':
            return this._buffer.getLong(false);
        case 'Pointer':
            return this._buffer.getPointer();
        }
    },
    /**
     * Puts a field in this structure.
     *
     * @param {String} name The field name.
     * @param {Number|String} value The field value to set.
     * @param {Number} [index] The index of the value to get.
     * @returns {jls.lang.Struct} This structure.
     */
    put : function(name, value, index) {
        if (! (name in this._struct)) {
            throw new Exception('Invalid name ' + name);
        }
        //jls.logger.warn('Struct.put("' + name + '", ' + value + ')');
        var d = this._struct[name]
        this._buffer.setPosition(d.position);
        switch (d.type) {
        case 'SignedByte':
        case 'UnsignedByte':
            this._buffer.putByte(value);
            break;
        case 'SignedShort':
        case 'UnsignedShort':
            this._buffer.putShort(value);
            break;
        case 'SignedInt':
        case 'UnsignedInt':
            this._buffer.putInt(value);
            break;
        case 'SignedLong':
        case 'UnsignedLong':
            this._buffer.putLong(value);
            break;
        case 'Pointer':
            this._buffer.putPointer(value);
            break;
        }
        return this;
    }
});

Object.extend(Struct, /** @lends jls.lang.Struct */
{
    TYPE_SIZE : {
        'SignedByte': 1,
        'UnsignedByte': 1,
        'SignedShort': 2,
        'UnsignedShort': 2,
        'SignedInt': 4,
        'UnsignedInt': 4,
        'SignedLong': 8,
        'UnsignedLong': 8,
        'Pointer': ByteBuffer.POINTER_SIZE
    }
});


return Struct;
});
define('jls/security/MessageDigest', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/ByteBuffer',
  'jls/io/BufferChannel'
], function (
  Class,
  Exception,
  ByteBuffer,
  BufferChannel
) {

/**
 * @namespace Provides security classes for the jls language.
 * @see jls.security.MessageDigest
 * @name jls.security
 */

var MessageDigest;
/**
 * @class This class represents a cryptographic hash function.
 * The message digests are MD5(not implemented) and SHA1.
 * @name jls.security.MessageDigest
 */
MessageDigest = Class.create( /** @lends jls.security.MessageDigest.prototype */
{
    /**
     * Creates a MessageDigest.
     * 
     * @private
     */
    initialize : function(algorithm) {
        this._algorithm = algorithm;
        this._buffer = ByteBuffer.allocate(1024);
    },
    /**
     * Returns the algorithm name.
     *
     * @returns {String} The algorithm name.
     */
    getAlgorithm : function() {
        return this._algorithm;
    },
    /**
     * Completes the digest and returns a buffer.
     *
     * @returns {jls.lang.ByteBuffer} The digested buffer.
     */
    digest : function() {
        throw new Exception('Not implemented');
    },
    /**
     * Resets the digest.
     *
     */
    reset : function() {
        this._buffer.clear();
    },
    _checkRemaining : function(length) {
        if (this._buffer.remaining() >= length) {
            return;
        }
        var capacity = this._buffer.capacity() * 2;
        for (; length > capacity - this._buffer.capacity(); capacity = capacity * 2);
        var tmp = ByteBuffer.allocate(capacity);
        this._buffer.flip();
        tmp.putBuffer(this._buffer);
        this._buffer = tmp;
    },
    /**
     * Updates the digest with a specified buffer.
     *
     * @param {jls.lang.ByteBuffer} buffer The buffer to update.
     */
    update : function(buffer) {
        this._checkRemaining(buffer.remaining());
        this._buffer.putBuffer(buffer, buffer.remaining());
    },
    /**
     * Updates the digest with a specified byte.
     *
     * @param {Number} b The byte to update.
     */
    updateByte : function(b) {
        this._checkRemaining(1);
        this._buffer.putByte(b);
    },
    /**
     * Updates the digest with a specified string.
     *
     * @param {String} buffer The string to update.
     */
    updateString : function(s, csn) {
        this._checkRemaining(s.length * 2);
        this._buffer.putString(s, csn ? csn : 'UTF-8');
    }
});

Object.extend(MessageDigest, /** @lends jls.security.MessageDigest */
{
	_algorithmMapping : {
		'SHA1' : 'jls/security/Sha1'
	},
	_availableMessageDigests : {},
    /**
     * Returns available algorithms.
     * 
     * @returns {Array} The available algorithms.
     */
	availableAlgorithms : function() {
        return Object.keys(MessageDigest._availableMessageDigests);
    },
	addMessageDigest : function(mdc) {
    	if ((typeof mdc == 'undefined') || (mdc == null)) {
			throw new Exception('Invalid message digest argument');
    	}
        var md = new mdc();
    	if (! (md instanceof MessageDigest)) {
			throw new Exception('Invalid message digest argument (not an instance of MessageDigest)');
    	}
		MessageDigest._availableMessageDigests[md.getAlgorithm()] = mdc;
    },
    /**
     * Tells if the specified algorithm is supported.
     * 
     * @param {String} algorithm The algorithm name.
     * @returns {Boolean} true if the specified algorithm is supported.
     */
    isSupported : function(algorithm) {
    	if (typeof algorithm != 'string') {
			throw new Exception('Invalid algorithm name');
    	}
    	if (algorithm in MessageDigest._availableMessageDigests) {
			return true;
    	}
    	if (algorithm in MessageDigest._algorithmMapping) {
            var a = require(MessageDigest._algorithmMapping[algorithm]);
			return algorithm in MessageDigest._availableMessageDigests;
    	}
		return false;
    },
    /**
     * Returns the specified message digest.
     * 
     * @param {String} algorithm The message digest algorithm name.
     * @returns {jls.security.MessageDigest} The message digest.
     */
	getInstance : function(algorithm) {
		if (! MessageDigest.isSupported(algorithm)) {
			throw new Exception('Unsupported algorithm "' + algorithm + '"');
		}
        return new MessageDigest._availableMessageDigests[algorithm]();
    }
});

return MessageDigest;
});
define('jls/security/Sha1', ['jls/lang/Class', 'jls/security/MessageDigest'], function (Class, MessageDigest) {

var Sha1;
(function () {

/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS 180-1
 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Perform the appropriate triplet combination function for the current iteration
 */
var sha1_ft = function(t, b, c, d) {
  if(t < 20) return (b & c) | ((~b) & d);
  if(t < 40) return b ^ c ^ d;
  if(t < 60) return (b & c) | (b & d) | (c & d);
  return b ^ c ^ d;
};

/*
 * Determine the appropriate additive constant for the current iteration
 */
var sha1_kt = function(t) {
  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
         (t < 60) ? -1894007588 : -899497514;
};

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally to work around bugs in some JS interpreters.
 */
var safe_add = function(x, y) {
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
};

/*
 * Bitwise rotate a 32-bit number to the left.
 */
var bit_rol = function(num, cnt) {
  return (num << cnt) | (num >>> (32 - cnt));
};

/*
 * Calculate the SHA-1 of an array of big-endian 32-bits words, and a bit length
 */
var computeArray = function(x, len) {
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32);
  x[((len + 64 >> 9) << 4) + 15] = len;

  var w = Array(80);
  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;
  var e = -1009589776;

  for(var i = 0; i < x.length; i += 16) {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    var olde = e;
    for(var j = 0; j < 80; j++) {
      if(j < 16) w[j] = x[i + j];
      else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
      var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
      e = d;
      d = c;
      c = bit_rol(b, 30);
      b = a;
      a = t;
    }
    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    e = safe_add(e, olde);
  }
  return Array(a, b, c, d, e);
};


/*
 * Message digest implementation for SHA1 algorithm.
 */
Sha1 = Class.create(MessageDigest,
{
    initialize : function($super) {
    	$super('SHA1');
    },
    digest : function() {
        this._buffer.flip();
        var length = this._buffer.remaining();
        var wa = [];
        for (var i = 0; this._buffer.remaining() > 0; i++) {
            var b = this._buffer.getByte();
            var m = i % 4
            var d = i >>> 2;
            if (m == 0) {
                wa[d] = 0;
            }
            wa[d] |= b << (24 - (m * 8));
        }
        wa = computeArray(wa, length * 8);
        this._buffer.clear();
        for (var i = 0; i < wa.length; i++) {
            var w = wa[i];
            this._buffer.putByte((w >>> 24) & 0xff);
            this._buffer.putByte((w >>> 16) & 0xff);
            this._buffer.putByte((w >>> 8) & 0xff);
            this._buffer.putByte(w & 0xff);
        }
        this._buffer.flip();
        return this._buffer;
    }
});

// static
MessageDigest.addMessageDigest(Sha1);

})();

return Sha1;
});
define('jls/util/EventBroker', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/Logger'], function (Class, Exception, Logger) {

var EventBroker;
EventBroker = Class.create( /** @lends jls.util.EventBroker.prototype */
{
    /**
     * Creates an event broker.
     * 
     * @constructs
     * @class This class represents an event broker.
     */
    initialize : function() {
        this._dispatchers = {};
    },
    /**
     * Subscribe to topic.
     * 
     * @param {String} name The event name.
     * @param {Function} callback The function to associate to this event name.
     * @param {Object} [thisArg] If defined, the this object to use when calling the callback function.
     * @returns {Object} the handle representing the subscription in order to be used with unsubscribe.
     */
    subscribe : function(name, callback, thisArg) {
        Logger.getInstance().trace('subscribe(' + name + ')');
        if ((typeof callback == 'object') && (name in callback)) {
            callback = callback[name];
        }
        if (typeof callback != 'function') {
            throw new Exception('Invalid callback');
        }
        if (typeof thisArg != 'undefined') {
            callback = callback.bind(thisArg);
        }
        var ed = null;
        if (name in this._dispatchers) {
        	ed = this._dispatchers[name];
        } else {
            this._dispatchers[name] = ed = new EventBroker.Dispatcher();
        }
        ed.addHandler(callback);
        return callback;
    },
    /**
     * Subscribe to multiple topics.
     * 
     * @param {Array} names The event names.
     * @param {Function} callback The function to associate to this event name.
     * @param {Object} [thisArg] If defined, the this object to use when calling the callback function.
     * @returns {Object} the handle representing the subscription in order to be used with unsubscribe.
     */
    subscribeAll : function(names, callback, thisArg) {
        Logger.getInstance().trace('subscribe(' + names.length + ')');
        for (var i = 0; i < names.length; i++) {
            this.subscribe(names[i], callback, thisArg);
        }
    },
    /**
     * Checks that an event exists.
     * 
     * @param {String} name The event name to look for.
     * @returns {Boolean} True if a subscription exists for this event name.
     */
    hasSubscription : function(name) {
        return name in this._dispatchers;
    },
    /**
     * Unsubscribe to a topic.
     * 
     * @param {String} name The event name to unsubscribe to.
     * @param {Object} [handle] The handle associated to the subscription.
     * @returns {jls.util.EventBroker} this event broker.
     */
    unsubscribe : function(name, handle) {
        Logger.getInstance().trace('unsubscribe(' + name + ')');
        if (! name in this._dispatchers) {
            throw new Exception('The event ' + name + ' does not exists');
        }
        var ed = this._dispatchers[name];
        if (handle) {
            ed.removeHandler(handle);
        } else {
            ed.removeAll();
        }
        if (ed.getCount() == 0) {
            delete this._dispatchers[name];
        }
        return this;
    },
    /**
     * Publish a custom event.
     * 
     * @param {String} name The name of the event to publish.
     * @param {Object} [message] An optional message object associated to the publication.
     * @returns {jls.util.EventBroker} this event broker.
     */
    publish : function(name, message) {
        Logger.getInstance().trace('publish(' + name + ')');
        if (name in this._dispatchers) {
        	this._dispatchers[name].dispatch(new EventBroker.Event(name, message))
        }
        return this;
    },
    /**
     * Creates a callback for a specified event name.
     * 
     * @param {String} name The name of the event.
     * @returns {Function} the callback.
     */
    callback : function(name) {
        if ((name == null) || (typeof name == 'undefined')) {
            return name; // Just act as a wrapper
        } else if (typeof name == 'function') {
    		return name; // Just act as a wrapper
    	} else if (typeof name != 'string') {
    		throw new Exception('Invalid event name');
    	}
    	var broker = this;
    	return function(message) {
    		broker.publish(name, message);
    	};
    },
    /**
     * Closes this event broker.
     */
    close : function() {
        Logger.getInstance().trace('close()');
        this._dispatchers = [];
    }
});

Object.extend(EventBroker,
{
    /**
     * The default event broker.
     * @type jls.util.EventBroker
     */
    DEFAULT: new EventBroker(),
    /**
     * Creates and returns a callback that calls the specified function when the specified count is reached.
     * @param {Number} count The count.
     * @param {Function} fn The function to call.
     * @returns {Function} the callback.
     */
    countDownCallback : function(count, fn) {
        if (typeof fn != 'function') {
            throw new Exception('Invalid function');
        }
        var n = 0;
        return function() {
            if (++n == count) {
                fn();
            }
        };
    }
});

EventBroker.Event = Class.create(
{
    initialize : function(name, message) {
        this.name = name;
        this.message = message;
    }
});

EventBroker.Dispatcher = Class.create(
{
    initialize : function() {
        this._callbacks = [];
    },
    addHandler : function(callback) {
        this._callbacks.push(callback);
        return this;
    },
    removeHandler : function(callback) {
        for (var i = 0; i < this._callbacks.length; i++) {
            if (callback === this._callbacks[i]) {
                this._callbacks.splice(i, 1);
                break;
            }
        }
        return this;
    },
    getCount : function() {
        return this._callbacks.length;
    },
    onException : function(e) {
        Logger.getInstance().warn('Uncaught exception during dispatching "' + e + '"');
        throw e;
    },
    dispatch : function(event) {
        Logger.getInstance().trace('dispatch() on ' + this._callbacks.length + ' callback(s)');
        for (var i = 0; i < this._callbacks.length; i++) {
            try {
                this._callbacks[i](event);
            } catch (e) {
            	this.onException(e);
            }
        }
        return this;
    },
    removeAll : function() {
        Logger.getInstance().trace('removeAll()');
        this._callbacks = [];
        return this;
    }
});

return EventBroker;
});
define('jls/util/Formatter', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/util/Locale'
], function (
  Class,
  Exception,
  Logger,
  Locale
) {

var Formatter;
//Late binding
var Resource;
require(['jls/util/Resource'], function(m) {
    Resource = m;
});

/**
 * @class This class provides a printf like String formatter.
 * @name jls.util.Formatter
 */
Formatter = Class.create({});

/*
 * %[argument_index$][flags][width][.precision]conversion
 */
Object.extend(Formatter, /** @lends jls.util.Formatter */
{
    _lineSeparator : _native.core.properties['line.separator'],
    _resources : {},
    getResource : function(language) {
        if (language in Formatter._resources) {
            return Formatter._resources[language];
        }
        var res = Resource.load('jls/util/formatter', language);
        var resource = {
                dayFullNames: res.get('dayFullNames').split(','),
                monthFullNames: res.get('monthFullNames').split(',')
        };
        return Formatter._resources[language] = resource;
    },
    /**
     * Returns a padded string.
     *
     * @param {String} s The string to pad.
     * @param {String} l The padding length.
     * @param {String} c The padding character.
     * @param {String} d The direction, true for left padding.
     * @returns {String} The padded string.
     */
    pad : function(s, l, c, d) {
        if ((! l) || (l < 1)) {
            return '';
        }
        s = s.toString();
        if (s.length >= l) {
            return s;
        }
        c = c || ' ';
        d = d || false;
        var p = '';
        for (var i = s.length; i < l; i++) {
            p += c;
        }
        if (d) {
            s = p + s;
        } else {
            s += p;
        }
        return s;
    },
    /**
     * Returns a formatted string.
     *
     * @param {String} [locale] The locale to use to format.
     * @param {String} format The format string.
     * @returns {String} The formatted string.
     */
    format : function() {
        var args = Array.from(arguments);
        var locale;
        if (args[0] instanceof Locale) {
            locale = args.shift();
        } else {
            locale = Locale.getDefault();
        }
        var format = args.shift();
        if (Logger.getInstance().isTraceEnabled()) {
            Logger.getInstance().trace('format(' + locale + ', "' + format + '", ' + args.toJSON() + ')');
        }
        var argi = 0;
        return format.replace(/%(<|[0-9]+\$){0,1}([+\- 0#]+){0,1}([0-9]+){0,1}(?:\.([0-9]+)){0,1}([dinsuxb%]|[tT][yYmedHIklMSLAB])/g,
        function(str, index, flags, width, precision, specifier) {
            switch (specifier) {
            case 'n': return Formatter._lineSeparator;
            case '%': return specifier;
            }
            var padLeft = true;
            var padChar = ' ';
            var ai = index == '<' ? argi : (index ? parseInt(index, 10) : ++argi);
            if ((ai < 1) || (ai > args.length)) {
                throw new Exception('Missing argument ' + ai);
            }
            for (var i = 0; flags && (i < flags.length); i++) {
                var flag = flags.charAt(i);
                switch (flag) {
                case '+':
                    padLeft = true;
                    break;
                case '-':
                    padLeft = false;
                    break;
                case '0':
                    padChar = flag;
                    break;
                }
            }
            width = width ? parseInt(width, 10) : 0;
            precision = precision ? parseInt(precision, 10) : 0;
            var arg = args[ai - 1];
            switch (specifier.charAt(0)) {
            case 'b':
                arg = (typeof arg == 'boolean' ? arg : (arg ? true : false));
                break;
            }
            if ((typeof arg == 'undefined') || (arg == null)) {
                throw new Exception('Missing argument ' + ai);
            }
            // format argument
            switch (specifier.charAt(0)) {
            case 'd':
            case 'i':
            case 's':
            case 'u':
            case 'b':
                break;
            case 'x':
                arg = arg.toString(16);
                break;
            case 't':
            case 'T':
                var p = 2;
                switch (specifier.charAt(1)) {
                case 'y':
                    arg = arg.getYear();
                    break;
                case 'Y':
                    p = 0;
                    arg = arg.getFullYear();
                    break;
                case 'm':
                    arg = arg.getMonth() + 1;
                    break;
                case 'e':
                    p = 0;
                case 'd':
                    arg = arg.getDate();
                    break;
                case 'k':
                    p = 0;
                case 'H':
                    arg = arg.getHours();
                    break;
                case 'l':
                    p = 0;
                case 'I':
                    arg = ((arg.getHours() + 11) % 12 + 1);
                    break;
                case 'M':
                    arg = arg.getMinutes();
                    break;
                case 'S':
                    arg = arg.getSeconds();
                    break;
                case 'L':
                    p = 3;
                    arg = arg.getMilliseconds();
                    break;
                case 'A':
                    p = 0;
                    arg = Formatter.getResource(locale.language).dayFullNames[arg.getDay()];
                    break;
                case 'B':
                    p = 0;
                    arg = Formatter.getResource(locale.language).monthFullNames[arg.getMonth()];
                    break;
                default:
                    throw new Exception('Invalid date specifier: ' + specifier.charAt(1));
                }
                if (p > 0) {
                    arg = Formatter.pad(arg, p, '0', true);
                }
                break;
            default:
                throw new Exception('Invalid specifier: ' + specifier.charAt(0));
            }
            arg = arg.toString();
            if (width && (arg.length < width)) {
                arg = Formatter.pad(arg, width, padChar, padLeft);
            }
            if (precision && (arg.length > precision)) {
                if (padLeft) {
                    arg = arg.substr(-precision, precision);
                } else {
                    arg = arg.substr(0, precision);
                }
            }
            return arg;
        });
    }
});

return Formatter;
});
define('jls/util/Locale', ['jls/lang/Class'], function (Class) {

var Locale;
Locale = Class.create( /** @lends jls.util.Locale.prototype */
{
    /**
     * Creates an Locale instance.
     * 
     * @param {String} language The language code.
     * @param {String} country The country code.
     * @constructs
     * @class This class provides locale information.
     */
    initialize : function(language, country) {
        this.language = language;
        this.country = country;
    },
    getCountry : function() {
        return this.country;
    },
    getLanguage : function() {
        return this.language;
    },
    toString : function() {
        return this.language + '_' + this.country;
    }
});

Object.extend(Locale, /** @lends jls.util.Locale */
{
    DEFAULT: new Locale(_native.core.properties['user.language'], _native.core.properties['user.region']),
    /**
     * Returns the default Locale instance.
     *
     * @returns {jls.util.Locale} The default Locale instance.
     */
    getDefault : function() {
        return Locale.DEFAULT;
    }
});

return Locale;
});
define('jls/util/Resource', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/util/XmlElement'
], function (
  Class,
  Exception,
  Logger,
  XmlElement
) {

var Resource;
//Late binding
var Formatter;
require(['jls/util/Formatter'], function(m) {
    Formatter = m;
});

Resource = Class.create( /** @lends jls.util.Resource.prototype */
{
    /**
     * Creates a Resource.
     * 
     * @constructs
     * @class This class provides resource labels.
     */
    initialize : function() {
        this._bundle = {};
    },
    set : function(key, value) {
        if (typeof value == 'undefined') {
            delete this._bundle[key];
        } else {
            this._bundle[key] = value;
        }
        return this;
    },
    /**
     * Returns a label.
     *
     * @param {String} key The label key.
     * @returns {String} The label string.
     */
    get : function(key) {
        if (typeof key != 'string') {
            throw new Exception('Missing key argument');
        }
        if (key in this._bundle) {
            return this._bundle[key];
        }
        return key;
    },
    /**
     * Returns a formatted label.
     *
     * @param {String} key The formatted label key.
     * @returns {String} The formatted label string.
     */
    getf : function(key) {
        var args = Array.from(arguments);
        var key = args.shift();
        var format = this.get(key);
        if (arguments.length < 2) {
            return format;
        }
        args.unshift(format);
        return Formatter.format.apply(Formatter, args);
    }
});

Object.extend(Resource, /** @lends jls.util.Resource */
{
    /**
     * The default resource.
     * @type jls.util.Resource
     */
    DEFAULT: new Resource(),
    loadFromXML : function(xml) {
        if (Logger.getInstance().isTraceEnabled()) {
            Logger.getInstance().trace('loadFromXML("' + xml.toString() + '")');
        }
        var res = new Resource();
        var entries = xml.getChildren();
        for (var i = 0; i < entries.length; i++) {
            var entry = entries[i];
            var key = entry.getAttribute('key');
            if ((entry.getName() == 'entry') && (key != null)) {
                res.set(key, entry.getText());
            }
        }
        return res;
    },
    getPath : function(path, language) {
        if (typeof language == 'undefined') {
            language = _native.core.properties['user.language'];
        }
        return path + '.' + language + '.xml';
    },
    _getResourceAsXML : function(path) {
        if ('boot' in _native) {
            var xml = _native.core.getResourceAsString(path, true);
            return XmlElement.createFromDOM(xml);
        } else {
            var xml = new XML(_native.core.getResourceAsString(path));
            return XmlElement.createFromE4X(xml);
        }
    },
    getResourceAsString : function(path) {
        return _native.core.getResourceAsString(path);
    },
    getResourceAsJSON : function(path) {
    	var s = Resource.getResourceAsString(path);
    	return eval('(' + s + ')');
    },
    /**
     * Loads a resource from an XML path.
     *
     * @param {String} path The path of the XML resource to load.
     * @param {String} [language] The language to use.
     * @returns {jls.util.Resource} The resource.
     */
    load : function(path, language) {
        /*
         * TODO also try to load without language?
         */
        var xml = Resource._getResourceAsXML(Resource.getPath(path, language));
        return Resource.loadFromXML(xml);
    }
});

return Resource;
});
define('jls/util/StringCodec', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/ByteBuffer'], function (Class, Exception, ByteBuffer) {

var StringCodec;
/**
 * @namespace Provides utility classes for the jls language.
 * @name jls.util
 */

/**
 * @class This class provides various String related codecs.
 * @name jls.util.StringCodec
 */
StringCodec = Class.create({});

Object.extend(StringCodec, /** @lends jls.util.StringCodec */
{
    /**
     * Encodes a specified buffer and returns the encoded base64 string.
     *
     * @param {jls.lang.ByteBuffer} buffer The buffer to encode.
     * @param {String} [b64pad] The padding character to use.
     * @returns {String} The encoded string.
     */
    base64Encode : function(buffer, b64pad) {
        // 64 = 2^6, 6*4 = 24, 24 = 8*3
        b64pad = b64pad || '=';
        var map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
        var s = '';
        while (buffer.remaining() > 0) {
            var r = buffer.remaining();
            var b1 = buffer.getByte();
            var b2 = buffer.remaining() > 0 ? buffer.getByte() : 0;
            var b3 = buffer.remaining() > 0 ? buffer.getByte() : 0;
            //logByte(b1, b2, b3);
            var i1 = b1 >>> 2;
            var i2 =  ((b1 & 0x03) << 4) | (b2 >>> 4);
            var i3 =  ((b2 & 0x0f) << 2) | (b3 >>> 6);
            var i4 =  b3 & 0x3f;
            //logByte(i1, i2, i3, i4);
            s += map.charAt(i1) + map.charAt(i2) + (r > 1 ? map.charAt(i3) : b64pad) + (r > 2 ? map.charAt(i4) : b64pad);
        }
        return s;
    },
    base64DecodeCharCode : function(c) {
        if ((c >= 0x41) && (c <= 0x5a)) { // A to Z
            return c - 0x41;
        } else if ((c >= 0x61) && (c <= 0x7a)) { // a to a
            return c - 0x61 + 26;
        } else if ((c >= 0x30) && (c <= 0x39)) { // 0 to 9
            return c - 0x30 + 52;
        } else if (c == 0x2b) { // +
            return 62;
        } else if (c == 0x2f) { // slash
            return 63;
        } else if (c == 0x3d) { // =
            return 0;
        } else {
            throw new Exception('Illegal base64 character code (' + c + ', 0x' + c.toString(16) + ')');
        }
    },
    /**
     * Decodes a specified base64 string and returns the decoded buffer.
     *
     * @param {String} s The string to decode.
     * @param {jls.lang.ByteBuffer} [buffer] The buffer to use.
     * @returns {jls.lang.ByteBuffer} The decoded buffer.
     */
    base64Decode : function(s, buffer) {
        var length = s.length;
        if ((length == 0) || (length % 4 != 0)) {
            throw new Exception('Invalid string length (' + length + ')');
        }
        buffer = buffer || ByteBuffer.allocate(length / 4 * 3);
        for (var i = 0; i < length; i += 4) {
            var c1 = s.charCodeAt(i);
            var c2 = s.charCodeAt(i + 1);
            var c3 = s.charCodeAt(i + 2);
            var c4 = s.charCodeAt(i + 3);
            var i1 = StringCodec.base64DecodeCharCode(c1);
            var i2 = StringCodec.base64DecodeCharCode(c2);
            var i3 = StringCodec.base64DecodeCharCode(c3);
            var i4 = StringCodec.base64DecodeCharCode(c4);
            var b1 = (i1 << 2) | (i2 >>> 4);
            var b2 = ((i2 & 0x0f) << 4) | (i3 >>> 2);
            var b3 = ((i3 & 0x03) << 6) | i4;
            buffer.putByte(b1);
            if (c3 == 0x3d) {
                break;
            }
            buffer.putByte(b2);
            if (c4 == 0x3d) {
                break;
            }
            buffer.putByte(b3);
        }
        return buffer;
    },
    /**
     * Encodes a specified buffer and returns the encoded hexadecimal string.
     *
     * @param {jls.lang.ByteBuffer} buffer The buffer to encode.
     * @param {String} [b64pad] The padding character to use.
     * @returns {String} The encoded string.
     */
    hexEncode : function(buffer, upperCase) {
        var map = upperCase ? "0123456789ABCDEF" : "0123456789abcdef";
        var s = '';
        while (buffer.remaining() > 0) {
            var b = buffer.getByte();
            s += map.charAt((b >>> 4) & 0x0f) + map.charAt(b & 0x0f);
        }
        return s;
    },
    /**
     * Decodes a specified hexadecimal string and returns the decoded buffer.
     *
     * @param {String} s The string to decode.
     * @param {jls.lang.ByteBuffer} [buffer] The buffer to use.
     * @returns {jls.lang.ByteBuffer} The decoded buffer.
     */
    hexDecode : function(s, buffer) {
        var length = s.length;
        if ((length == 0) || (length % 2 != 0)) {
            throw new Exception('Invalid string length (' + length + ')');
        }
        buffer = buffer || ByteBuffer.allocate(length / 2);
        for (var i = 0; i < length; i += 2) {
            buffer.putByte(parseInt(s.substr(i, 2), 16));
        }
        return buffer;
    }
});

return StringCodec;
});
define('jls/util/SxeEnvelope', ['jls/lang/Class', 'jls/util/XmlElement'], function (Class, XmlElement) {

var SxeEnvelope;
SxeEnvelope = Class.create(XmlElement, /** @lends jls.util.SxeEnvelope.prototype */
{
    /**
     * Creates an SXE Envelope.
     * 
     * @param {String} [login] The authentication login.
     * @param {String} [password] The authentication password.
     * @constructs
	 * @class This class represents an SXE Envelope.
     */
    initialize : function($super, login, password) {
    	/*if (typeof login == 'object') {
    		$super(login);
    		return;
    	}*/
		$super({name: 'envelope'});
    	this._header = this.addChild({name: 'header'});
    	this._body = this.addChild({name: 'body'});
    	if (login && password) {
    		this.setAuthentication(login, password);
    	}
    },
    getHeader : function() {
        return this._header;
    },
    getBody : function() {
        return this._body;
    },
    /**
     * Sets the authentication credential for this envelope.
     *
     * @param {String} login The authentication login.
     * @param {String} password The authentication password.
     */
    setAuthentication : function(login, password) {
    	this._header.removeChildren();
    	//this._header.addChild({name: 'authentication', attributes: {login: login, password: password}});
    	this._header.addChild({name: 'authentication',
    		children: [{name: 'login', value: login}, {name: 'password', value: password}]});
    	return this;
    },
    /**
     * Adds a request to this envelope.
     *
     * @param {jls.util.XmlElement} request The request to add.
     */
    addRequest : function(request) {
    	this._body.addChild(request);
    	return this;
    },
    /**
     * Adds a reply to this envelope.
     *
     * @param {jls.util.XmlElement} reply The reply to add.
     */
    reply : function(reply) {
        this._body.addChild(reply);
        return this;
    },
    fail : function(message, id) {
        var reply = {name: 'failure'};
        if (typeof message != 'undefined') {
            reply.message = message;
        }
        if (typeof id != 'undefined') {
            reply.id = id;
        }
        this._body.addChild(reply);
        return this;
    },
    getRequestCount : function() {
        return this._body.getChildCount();
    },
    getRequest : function(index) {
        return this._body.getChild(index);
    },
    getResultCount : function() {
        return this._body.getChildCount();
    },
    getResult : function(index) {
        return this._body.getChild(index);
    }
});

Object.extend(SxeEnvelope, /** @lends jls.util.SxeEnvelope */
{
    /**
     * Creates an SXE envelope base on the specidied DOM node.
     * 
     * @param {Object} domNode The DOM node to parse.
     * @returns {jls.util.SxeEnvelope} The SXE envelope.
     */
    createFromDOM : function(domNode) {
    	var envelope = new SxeEnvelope();
    	envelope.removeChildren();
    	XmlElement.populateFromDOM(envelope, domNode);
    	envelope._header = envelope.getChild(0);
    	envelope._body = envelope.getChild(1);
    	return envelope;
    },
    /**
     * Creates an SXE envelope base on the specidied E4X node.
     * 
     * @param {Object} domNode The E4X node to parse.
     * @returns {jls.util.SxeEnvelope} The SXE envelope.
     */
    createFromE4X : function(xmlNode) {
        var envelope = new SxeEnvelope();
        envelope.removeChildren();
        XmlElement.populateFromE4X(envelope, xmlNode);
        envelope._header = envelope.getChild(0);
        envelope._body = envelope.getChild(1);
        return envelope;
    }
});


return SxeEnvelope;
});
define('jls/util/XmlElement', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var XmlElement;
/*
 * E4X is not supported by google chrome, so could not use it by now.
 */
XmlElement = Class.create( /** @lends jls.util.XmlElement.prototype */
{
    /**
     * Creates an XML.
     * 
     * @param {Object} [parameters] The XML parameters.
     * @constructs
	 * @class This class represents an XML element.
     */
    initialize : function(parameters) {
        parameters = parameters || {};
        this.name = parameters.name || '';
        this.children = [];
        this.attributes = {};
        this.value = parameters.value || '';
        if (parameters.attributes) {
            this.setAttributes(parameters.attributes);
        }
        if (Object.isArray(parameters.children)) {
            this.addChildren(parameters.children);
        }
    },
    /**
     * Returns this XML element name.
     *
     * @returns {String} The XML element name.
     */
    getName : function() {
        return this.name;
    },
    /**
     * Sets this XML element name.
     *
     * @param {String} name The XML element name.
     */
    setName : function(name) {
    	this.name = name;
    	return this;
    },
    /**
     * Sets an attribute.
     *
     * @param {String} key The attribute key.
     * @param {String} [value] The attribute value.
     */
    setAttribute : function(key, value) {
        //jls.logger.trace('setAttribute(' + key + ', ' + value + ')');
    	if (typeof value != 'undefined') {
    		this.attributes[key] = value;
    	} else {
        	delete this.attributes[key];
    	}
    	return this;
    },
    /**
     * Returns an attribute value.
     *
     * @param {String} key The attribute key.
     * @param {String} [defaultValue] The default value to return if the key does not exist.
     * @returns {String} The attribute value.
     */
    getAttribute : function(key, defaultValue) {
        if (key in this.attributes) {
        	return this.attributes[key];
        }
        return typeof defaultValue == 'undefined' ? null : defaultValue;
    },
    /**
     * Sets some attributes.
     *
     * @param {Object} attributes The attributes to set.
     */
    setAttributes : function(attributes) {
        for ( var k in attributes) {
            this.setAttribute(k, attributes[k]);
        }
        return this;
    },
    addCData: Class.emptyFunction,
    addComment: Class.emptyFunction,
    addText : function(value) {
        //jls.logger.trace('addText(' + value + ')');
        this.value += value;
        return this;
    },
    getText : function() {
        return this.value;
    },
    /**
     * Adds a child.
     *
     * @param {Object} child The child to add.
     */
    addChild : function(child) {
        if (typeof child == 'object') {
            child = new XmlElement(child);
        } else if (! child instanceof XmlElement) {
            throw new Exception('don\'t know how to add "' + (typeof child) + '" child type');
        }
        //jls.logger.trace('addChild(' + child.getName() + ')');
        this.children.push(child);
        return child;
    },
    /**
     * Adds children.
     *
     * @param {Array} children The children to add.
     */
    addChildren : function(children) {
        for ( var i = 0; i < children.length; i++) {
            this.addChild(children[i]);
        }
        return this;
    },
    /**
     * Removes a child.
     *
     * @param {Object} child The child to remove.
     */
    removeChild : function(child) {
        var index = 0;
        if (typeof child == 'number') {
            index = child;
            child = this.children[index];
        } else if (child instanceof XmlElement) {
        	for (index = this.children.length - 1; (index >= 0) && (this.children[index] !== child); index--);
        	if (index < 0) {
        		throw new Exception('Child not found');
        	}
        } else {
            throw new Exception('don\'t know how to remove "' + (typeof child) + '" child type');
        }
        this.children.splice(index, 1);
        return child;
    },
    /**
     * Removes all children.
     *
     */
    removeChildren : function() {
        /*for (var i = this.children.length - 1; i >= 0; i--) {
            this.removeChild(i);
        }*/
        this.children = [];
    },
    /**
     * Returns all children.
     *
     */
    getChildren : function() {
        return this.children;
    },
    getChildCount : function() {
        return this.children.length;
    },
    /**
     * Gets a child.
     *
     * @param {Number} index The child index.
     * @returns {jls.util.XmlElement} The child.
     */
    getChild : function(index) {
        return this.children[index];
    },
    toString : function(encoding) {
        var s = '';
        if (encoding) {
            s += '<?xml version="1.0" encoding="' + encoding + '" ?>';
        }
    	s += '<' + this.name;
        for (var key in this.attributes) {
    		s += ' ' + key + '="' + XmlElement.escape(this.attributes[key]) + '"';
        }
    	if ((this.children.length == 0) && (this.value.length == 0)) {
    		s += ' />';
    	} else {
    		s += '>';
            for (var i = 0; i < this.children.length; i++) {
            	s += this.children[i].toString();
            }
            if (this.value.length > 0) {
                s += XmlElement.escape(this.value);
            }
        	s += '</' + this.name + '>';
    	}
        return s;
    }
});

Object.extend(XmlElement, /** @lends jls.util.XmlElement */
{
	ELEMENT_NODE : 1,
	ATTRIBUTE_NODE : 2,
	TEXT_NODE : 3,
	CDATA_SECTION_NODE : 4,
	ENTITY_REFERENCE_NODE : 5,
	ENTITY_NODE : 6,
	PROCESSING_INSTRUCTION_NODE : 7,
	COMMENT_NODE : 8,
	DOCUMENT_NODE : 9,
	DOCUMENT_TYPE_NODE : 10,
	DOCUMENT_FRAGMENT_NODE : 11,
	NOTATION_NODE : 12,
    /**
     * Creates an XML element from a DOM one.
     *
     * @param {Object} domNode The DOM Element.
     * @returns {jls.util.XmlElement} The created XML element.
     */
    createFromDOM : function(domNode) {
        /*
         * TODO do not create an XML: wrap the DOM object
         */
        return XmlElement.populateFromDOM(new XmlElement(), domNode);
    },
    escape : function(s) {
        if (s) {
            return s.toString().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').
                replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/\n/g, '&#x000a;').replace(/\t/g, '&#x0009;');
        }
        return s;
    },
    parseXMLString : function(value) {
        // &#xE9;
        return value.replace(/&#x([0-9A-F]+);/, function(str, u) {
            return String.fromCharCode(parseInt(u, 16));
        });
    },
    populateFromDOM : function(xml, domNode) {
        if ((! domNode) || (! 'nodeType' in domNode)) {
            throw new Exception('Invalid DOM node');
        } else if (domNode.nodeType == XmlElement.DOCUMENT_NODE) {
        	// Look for the first child element
            for (var i = 0; i < domNode.childNodes.length; i++) {
            	if (domNode.childNodes[i].nodeType == XmlElement.ELEMENT_NODE) {
                    return arguments.callee(xml, domNode.childNodes[i]);
            	}
            }
            throw new Exception('Invalid DOM node (no element found)');
        } else if (domNode.nodeType != XmlElement.ELEMENT_NODE) {
            throw new Exception('Invalid DOM node (' + domNode.nodeType + ')');
        }
        xml.setName(domNode.nodeName);
        if (domNode.attributes) {
            for (var i = 0; i < domNode.attributes.length; i++) {
            	var childNode = domNode.attributes[i];
                switch (childNode.nodeType) {
                case XmlElement.ATTRIBUTE_NODE:
                	//xml.setAttribute(childNode.nodeName, jls.util.XmlElement.parseXMLString(childNode.nodeValue));
                    xml.setAttribute(childNode.nodeName, childNode.nodeValue);
                    break;
                }
            }
        }
        if (domNode.childNodes) {
            for (var i = 0; i < domNode.childNodes.length; i++) {
            	var childNode = domNode.childNodes[i];
                switch (childNode.nodeType) {
                case XmlElement.ELEMENT_NODE:
                	xml.addChild(XmlElement.createFromDOM(childNode));
                    break;
                case XmlElement.TEXT_NODE:
                	xml.addText(childNode.nodeValue);
                    break;
                case XmlElement.CDATA_SECTION_NODE:
                	xml.addCData(childNode.nodeValue);
                    break;
                case XmlElement.COMMENT_NODE:
                	xml.addComment(childNode.nodeValue);
                    break;
                }
            }
        }
        if (domNode.nodeValue) {
        	xml.addText(domNode.nodeValue);
        }
        return xml;
    },
    /**
     * Creates an XML element from a E4X one.
     *
     * @param {Object} xmlNode The E4X Element.
     * @returns {jls.util.XmlElement} The created XML element.
     */
    createFromE4X : function(xmlNode) {
        /*
         * TODO do not create an XML: wrap the E4X object
         */
        return XmlElement.populateFromE4X(new XmlElement(), xmlNode);
    },
    populateFromE4X : function(xml, xmlNode) {
        xml.setName(xmlNode.name());
        var i, l;
        l = xmlNode.attributes();
        for (i = 0; i < l.length(); i++) {
            var a = l[i];
            xml.setAttribute(a.name(), a);
        }
        /*l = xmlNode.elements();
        for (i = 0; i < l.length(); i++) {
            xml.addChild(jls.util.XmlElement.createFromE4X(l[i]));
        }
        l = xmlNode.comments();
        for (i = 0; i < l.length(); i++) {
            xml.addComment(l[i]);
        }*/
        l = xmlNode.children();
        for (i = 0; i < l.length(); i++) {
            var n = l[i];
            switch (n.nodeKind()) {
            case 'element':
                xml.addChild(XmlElement.createFromE4X(n));
                break;
            case 'text':
                xml.addText(n);
                break;
            case 'comment':
                xml.addComment(n);
                break;
            }
        }
        return xml;
    }
});


return XmlElement;
});
define('jls/gui/Button', ['jls/html/Button'], function (WrappedElement) {
    /**
     * @name jls.gui.Button
     * @augments jls.gui.Element
     * @class This class represents a button.
     */
	return WrappedElement;
});
define('jls/gui/CheckBox', ['jls/html/CheckBox'], function (WrappedElement) {
    /**
     * @name jls.gui.CheckBox
     * @augments jls.gui.Element
     * @class This class represents a check box.
     */
	return WrappedElement;
});
define('jls/gui/ComboBox', ['jls/html/ComboBox'], function (WrappedElement) {
    /**
     * @name jls.gui.ComboBox
     * @augments jls.gui.Element
     * @class This class represents a combo box.
     */
	return WrappedElement;
});
define('jls/gui/Edit', ['jls/html/Edit'], function (WrappedElement) {
    /**
     * @name jls.gui.Edit
     * @augments jls.gui.Element
     * @class This class represents an edit field.
     */
    return WrappedElement;
});
define('jls/gui/GuiUtilities', ['jls/html/GuiUtilities'], function (WrappedElement) {
	/**
	 * @class A collection of utility methods for the graphical user interface.
	 * @name jls.gui.GuiUtilities
	 */
	/**
	 * Calls a function synchronously in the GUI message thread.
	 *
	 * @param {Function} fn The function to call.
	 * @returns {Object} The function result if any.
	 * @function
	 * @name invokeAndWait
	 * @memberOf jls.gui.GuiUtilities
	 */
	/**
	 * Calls a function asynchronously in the GUI message thread.
	 *
	 * @param {Function} fn The function to call.
	 * @function
	 * @name invokeLater
	 * @memberOf jls.gui.GuiUtilities
	 */
    return WrappedElement;
});
define('jls/gui/Label', ['jls/html/Label'], function (WrappedElement) {
    /**
     * @name jls.gui.Label
     * @augments jls.gui.Element
     * @class This class represents label.
     */
    return WrappedElement;
});
define('jls/html/Button', ['jls/lang/Class', 'jls/html/HtmlElement'], function (Class, HtmlElement) {

var Button;
Button = Class.create(HtmlElement,
{
    onCreate : function($super) {
        this.setAttribute('htmlTagName', 'button');
        $super();
    },
    getText : function() {
        return this.getTextContent();
    },
    setText : function(value) {
    	this.setTextContent(value);
        return this;
    }
});


return Button;
});
define('jls/html/CheckBox', ['jls/lang/Class', 'jls/html/HtmlElement'], function (Class, HtmlElement) {
    // CheckBox
    return Class.create(HtmlElement,
    {
        onCreate : function($super) {
            this.setAttribute('htmlTagName', 'input');
            $super();
            this.getHtmlElement().setAttribute('type', 'checkbox');
        },
        getChecked : function() {
            return this.getHtmlElement().checked;
        },
        isChecked : function() {
            return this.getChecked();
        },
        setChecked : function(value) {
            this.getHtmlElement().checked = value;
            return this;
        }/*,
        getChecked : function() {
            return this.getHtmlElement().getAttribute('checked') == 'checked';
        },
        isChecked : function() {
            return this.getChecked();
        },
        setChecked : function(value) {
            if (value) {
                this.getHtmlElement().setAttribute('checked', 'checked');
            } else {
                this.getHtmlElement().removeAttribute('checked');
            }
            return this;
        }*/,
        getDisabled : function() {
            return this.getHtmlElement().getAttribute('disabled') == 'disabled';
        },
        isDisabled : function() {
            return this.getDisabled();
        },
        setDisabled : function(value) {
            if (value) {
                this.getHtmlElement().setAttribute('disabled', 'disabled');
            } else {
                this.getHtmlElement().removeAttribute('disabled');
            }
            return this;
        },
        getReadonly : function() {
            return this.getHtmlElement().getAttribute('readonly') == 'readonly';
        },
        isReadonly : function() {
            return this.getReadonly();
        },
        setReadonly : function(value) {
            if (value) {
                this.getHtmlElement().setAttribute('readonly', 'readonly');
            } else {
                this.getHtmlElement().removeAttribute('readonly');
            }
            return this;
        }
    });
});
define('jls/html/ComboBox', ['jls/lang/Class', 'jls/lang/Logger', 'jls/html/HtmlElement'], function (Class, Logger, HtmlElement) {
    return Class.create(HtmlElement,
    {
        onCreate : function($super) {
            this.setAttribute('htmlTagName', 'select')
            $super();
        },
        addString : function(value) {
            var option = document.createElement('option');
            option.appendChild(document.createTextNode(this.getResourceLabel(value)));
            this.getHtmlElement().appendChild(option);
            //parseInt( select.options[ select.options.selectedIndex ].value );
        },
        getCurrentSelectionIndex : function() {
            return this.getHtmlElement().options.selectedIndex;
        },
        setCurrentSelectionIndex : function(index) {
            this.getHtmlElement().options.selectedIndex = index;
            return this;
        },
        getCurrentSelectionText : function() {
            var index = this.getCurrentSelectionIndex();
            Logger.getInstance().trace('getCurrentSelectionText() [' + index + ']');
            return this.getHtmlElement().options[index].value;
        },
        getText : function() {
            return '';//this.getTextContent();
        },
        setText : function(value) {
            //this.setTextContent(value);
            return this;
        }
    });
});
define('jls/html/DataGrid', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/Logger', 'jls/gui/Element', 'jls/html/HtmlElement', 'jls/html/Label', 'jls/html/Edit', 'jls/html/CheckBox'],
function (Class, Exception, Logger, Element, HtmlElement, Label, Edit, CheckBox)
{

    var Cell = Class.create(HtmlElement,
    {
        initialize : function($super, parameters) {
            this._selected = false;
            $super(parameters);
        },
        onCreate : function($super) {
            this.setAttribute('htmlTagName', 'td');
            $super();
            this._cellContent = this.createCellContent();
            if (this._cellContent) {
                this.addChild(this._cellContent);
            }
        },
        createCellContent : Class.emptyFunction,
        getCellContent : function() {
            return this._cellContent;
        },
        getValue : function() {
            return this.getTextContent();
        },
        setValue : function(value) {
            this.setTextContent(value);
            return this;
        },
        isSelected : function() {
            return this._selected;
        },
        setSelected : function(value) {
            this._selected = value;
            return this;
        },
        edit : function(editor) {
            while (this.getChildCount() > 1) {
                this.removeChild(this.getChildCount() - 1);
            }
            this._cellContent.getStyle().setProperty('display', editor ? 'none' : '');
            if (editor) {
                this.addChild(editor);
            }
        }
    });
            
    var BooleanCellRenderer = Class.create(Cell,
    {
        createCellContent : function() {
            return new CheckBox({attributes: {disabled: true}});
        },
        getValue : function() {
            return this.getCellContent().getChecked();
        },
        setValue : function(value) {
            this.getCellContent().setChecked(value);
            return this;
        }
    });
                    
    var BooleanCellEditor = Class.create(BooleanCellRenderer,
    {
        createCellContent : function() {
            return new CheckBox();
        }
    });
                            
    var TextCellRenderer = Class.create(Cell,
    {
        createCellContent : function() {
            return new Label();
        },
        getValue : function() {
            return this.getCellContent().getText();
        },
        setValue : function(value) {
            this.getCellContent().setText(value);
            return this;
        }
    });
                            
    var TextEditor = Class.create(Edit,
    {
        getValue : function() {
            return this.getText();
        },
        setValue : function(value) {
            this.setText(value);
            return this;
        }
    });
                            
    var Row = Class.create(HtmlElement,
    {
        initialize : function($super, parameters) {
            this._selected = false;
            $super(parameters);
        },
        onCreate : function($super) {
            this.setAttribute('htmlTagName', 'tr');
            $super();
        },
        onAddChild : function(child) {
            if (child instanceof Cell) {
                this.getHtmlElement().appendChild(child.getHtmlElement());
            }
        },
        isSelected : function() {
            return this._selected;
        },
        setSelected : function(value) {
            this._selected = value;
            return this;
        }
    });
    
    var ModelEvent = Class.create({
        initialize : function(model, firstRow, lastRow, column, type) {
            this.model = model;
            this.firstRow = firstRow;
            this.lastRow = lastRow || firstRow;
            this.column = column || ModelEvent.ALL_COLUMNS;
            this.type = type || ModelEvent.UPDATE;
        },
        toString : function() {
            return '{' + ModelEvent.formatEventType(this.type) + ', ' + this.firstRow + '-' + this.lastRow + ', ' + this.column + '}';
        }
    });
    Object.extend(ModelEvent,
    {
        formatEventType : function(type) {
            switch (type) {
            case ModelEvent.UPDATE:
                return 'UPDATE';
            case ModelEvent.DELETE:
                return 'DELETE';
            case ModelEvent.INSERT:
                return 'INSERT';
            }
        },
        DELETE : 1,
        INSERT : 2,
        UPDATE : 0,
        HEADER_ROW : -1,
        ALL_COLUMNS : -1
    });
    
    var Model = Class.create({
        initialize : function(parameters) {
            parameters = parameters || {};
            this._data = parameters.data || [];
            this._columnNames = parameters.columnNames || [];
            this._isColumnEditable = parameters.isColumnEditable || false;
            this._listeners = [];
            if (typeof this._isColumnEditable == 'boolean') {
                var isEditable = this._isColumnEditable;
                this._isColumnEditable = [];
                for (var i = this.getColumnCount() - 1; i >= 0; i--) {
                    this._isColumnEditable.push(isEditable);
                }
            }
        },
        addModelListener : function(listener) {
            this._listeners.push(listener);
        },
        removeModelListener : function(listener) {
            for (var i = 0; i < this._listeners.length; i++) {
                if (listener === this._listeners[i]) {
                    this._listeners.splice(i, 1);
                    break;
                }
            }
            return this;
        },
        fireModelChanged : function(event) {
            for (var i = 0; i < this._listeners.length; i++) {
                this._listeners[i].modelChanged(event);
            }
        },
        getColumnCount : function() {
            return this._columnNames.length;
        },
        getColumnName : function(column) {
            return this._columnNames[column];
        },
        getRowCount : function() {
            return this._data.length;
        },
        getRow : function(row) {
            return this._data[row];
        },
        addRow : function(rowData) {
            Logger.getInstance().trace('addRow()');
            this._data.push(rowData);
            this.fireModelChanged(new ModelEvent(this, this._data.length - 1, undefined, undefined, ModelEvent.INSERT));
        },
        insertRow : function(row, rowData) {
            Logger.getInstance().trace('insertRow(' + row + ')');
            this._data.splice(row, 0, rowData);
            this.fireModelChanged(new ModelEvent(this, row, undefined, undefined, ModelEvent.INSERT));
        },
        removeRow : function(row) {
            Logger.getInstance().trace('removeRow(' + row + ')');
            this._data.splice(row, 1);
            this.fireModelChanged(new ModelEvent(this, row, undefined, undefined, ModelEvent.DELETE));
        },
        getValueAt : function(row, column) {
            return this._data[row][column];
        },
        setValueAt : function(value, row, column) {
            this._data[row][column] = value;
            return this;
        },
        isCellEditable : function(row, column) {
            return this._isColumnEditable[column];
        },
        removeAll : function() {
            Logger.getInstance().trace('removeAll()');
            var rowCount = this.getRowCount();
            if (rowCount <= 0) {
                return;
            }
            this._data = [];
            this.fireModelChanged(new ModelEvent(this, 0, rowCount - 1, undefined, ModelEvent.DELETE));
        }
    });

    var BeanModel = Class.create(Model,
    {
        initialize : function($super, parameters) {
            parameters = parameters || {};
            $super(parameters);
            this._keys = parameters.keys;
            this._getFunctionName = parameters.getFunctionName || null;
            this._setFunctionName = parameters.setFunctionName || null;
            this._useGetterSetter = (parameters.useGetterSetter === true);
        },
        getValueAt : function(row, column) {
            var rowObject = this.getRow(row);
            var key = this._keys[column];
            if (this._useGetterSetter) {
                var getter = key.camelize('get');
                if (! Object.isFunction(rowObject[getter])) {
                    throw new Exception('No getter (' + getter + ')');
                }
                return rowObject[getter]();
            } else if (this._getFunctionName != null) {
                return rowObject[this._getFunctionName](key);
            }
            return rowObject[key];
        },
        setValueAt : function(value, row, column) {
            Logger.getInstance().trace('setValueAt(' + value + ', ' + row + ', ' + column + ')');
            var rowObject = this.getRow(row);
            var key = this._keys[column];
            if (this._useGetterSetter) {
                var setter = key.camelize('set');
                if (! Object.isFunction(rowObject[setter])) {
                    throw new Exception('No setter (' + setter + ')');
                }
                rowObject[setter](value);
                return this;
            } else if (this._setFunctionName != null) {
                return rowObject[this._setFunctionName](key, value);
            }
            rowObject[key] = value;
            return this;
        }
    });

    /*
     * TODO separate the table view and the cell content view
     */
    var View = Class.create({
        initialize : function(parameters) {
            parameters = parameters || {};
            this._columnTypes = parameters.columnTypes;
            this._cellParameters = parameters.cellParameters || null;
            this._rowParameters = parameters.rowParameters || null;
            this._altCellStyle = parameters.altCellStyle || {
                selected: {borderStyle: 'double'},
                notSelected: {borderStyle: 'dotted'}
            };
        },
        createRow : function(row) {
            return new Row(this._rowParameters);
        },
        createHeaderCellRenderer : function(column) {
            return new TextCellRenderer(this._cellParameters);
        },
        createCellRenderer : function(row, column, editable) {
            switch (this._columnTypes[column]) {
            case 'boolean':
                if (editable) {
                    return new BooleanCellEditor(this._cellParameters);
                } else {
                    return new BooleanCellRenderer(this._cellParameters);
                }
            case 'number':
            case 'string':
                return new TextCellRenderer(this._cellParameters);
            case 'date':
            default:
                return new Cell(this._cellParameters);
            }
        },
        createEditor : function(row, column) {
            switch (this._columnTypes[column]) {
            case 'number':
            case 'string':
                return new TextEditor(this._cellParameters);
            case 'boolean':
            case 'date':
            default:
                return null;
            }
        },
        changeCellSelection : function(cell, select) {
        },
        changeRowSelection : function(row, select) {
            for (var j = row.getChildCount() - 1; j >= 0; j--) {
                var cell = row.getChild(j);
                cell.getStyle().setProperties(this._altCellStyle[select ? 'selected' : 'notSelected']);
            }
        }
    });
            
    var DataGrid = Class.create(HtmlElement,
    {
        initialize : function($super, parameters, parent) {
            this._tableBody = null;
            this._model = null;
            this._view = null;
            this._selectedRow = -1;
            this._selectedColumn = -1;
            this._editingRow = -1;
            this._editingColumn = -1;
            this._editor = null;
            parameters = parameters || {};
            if (parameters.model) {
                this.setModel(parameters.model);
            }
            if (parameters.view) {
                this.setView(parameters.view);
            }
            $super(parameters, parent);
            if (this._model && this._view) {
                this.render();
            }
            this.observe('click', (function (event) {
                var rowCount = this.getChildCount();
                var i, j;
                for (i = 0, j = -1; i < rowCount; i++) {
                    var row = this.getChild(i);
                    for (j = row.getChildCount() - 1; j >= 0; j--) {
                        var cell = row.getChild(j);
                        if (cell.containsNode(event.target)) {
                            break;
                        }
                    }
                    if (j >= 0) {
                        this.selectCell(i - 1, j);
                        break;
                    }
                }
            }).bind(this));
        },
        onCreate : function($super) {
            this.setAttribute('htmlTagName', 'table');
            $super();
            this._tableBody = document.createElement('tbody');
            this.getHtmlElement().appendChild(this._tableBody);
        },
        onAddChild : function(child) {
            if (child instanceof Row) {
                this._tableBody.appendChild(child.getHtmlElement());
            }
        },
        onInsertChild : function(index, child) {
            if (child instanceof Row) {
                this._tableBody.insertBefore(child.getHtmlElement(), this._tableBody.childNodes[index]);
            }
        },
        selectCell : function(rowIndex, columnIndex) {
            Logger.getInstance().trace('selectCell(' + rowIndex + ', ' + columnIndex + ')');
            this.changeSelection(rowIndex, columnIndex);
        },
        changeSelection : function(rowIndex, columnIndex, toggle, extend) {
            if ((this._selectedRow == rowIndex) && (this._selectedColumn == columnIndex)) {
                // for check box
                var row = this.getChild(rowIndex + 1);
                var cell = row.getChild(columnIndex);
                var value = cell.getValue();
                this._model.setValueAt(value, rowIndex, columnIndex);
                return;
            }
            if ((this._selectedRow >= 0) && (this._selectedRow + 1 < this.getChildCount())) {
                var selectedRow = this.getChild(this._selectedRow + 1);
                //var selectedCell = selectedRow.getChild(this._selectedColumn);
                selectedRow.setSelected(false);
                this._view.changeRowSelection(selectedRow, selectedRow.isSelected());
                this._selectedRow = -1;
                this._selectedColumn = -1;
            }
            if ((rowIndex < 0) || (columnIndex < 0)) {
                this.stopEditing();
                return;
            }
            Logger.getInstance().trace('changeSelection(' + rowIndex + ', ' + columnIndex + ')');
            var row = this.getChild(rowIndex + 1);
            //var cell = row.getChild(columnIndex);
            if (! row.isSelected()) {
                row.setSelected(true);
                this._view.changeRowSelection(row, row.isSelected());
            }
            Logger.getInstance().trace('changeSelection() selectedRow: ' + rowIndex);
            this._selectedRow = rowIndex;
            this._selectedColumn = columnIndex;
            if (this._model.isCellEditable(rowIndex, columnIndex)) {
                this.editCellAt(rowIndex, columnIndex);
            }
        },
        editCellAt : function(rowIndex, columnIndex) {
            Logger.getInstance().trace('editCellAt(' + rowIndex + ', ' + columnIndex + ')');
            var row = this.getChild(rowIndex + 1);
            var cell = row.getChild(columnIndex);
            this.stopEditing();
            this._editor = this._view.createEditor(rowIndex, columnIndex);
            if (! this._editor) {
                // for checkbox
                var value = cell.getValue();
                this._model.setValueAt(value, rowIndex, columnIndex);
                return;
            }
            var value = this._model.getValueAt(rowIndex, columnIndex);
            this._editor.setValue(value);
            cell.edit(this._editor);
            this._editingRow = rowIndex;
            this._editingColumn = columnIndex;
        },
        stopEditing : function() {
            if ((this._editingRow < 0) || (this._editingColumn < 0)) {
                return;
            }
            Logger.getInstance().trace('stopEditing(' + this._editingRow + ', ' + this._editingColumn + ')');
            var row = this.getChild(this._editingRow + 1);
            var cell = row.getChild(this._editingColumn);
            cell.edit(null);
            var value = this._editor.getValue();
            this._model.setValueAt(value, this._editingRow, this._editingColumn);
            cell.setValue(value);
            this._editor = null;
            this._editingRow = -1;
            this._editingColumn = -1;
        },
        getCellSelectionEnabled : function() {
        },
        getRowSelectionAllowed : function() {
        },
        getSelectedColumn : function() {
            return this._selectedColumn;
        },
        getSelectedColumnCount : function() {
        },
        getSelectedRow : function() {
            return this._selectedRow;
        },
        getSelectedRowCount : function() {
        },
        getSelectedRows : function() {
        },
        setView : function(view) {
            this._view = Element.wrap(View, view);
        },
        getView : function() {
        	return this._view;
        },
        setModel : function(model) {
            this._model = Element.wrap(Model, model);
            this._model.addModelListener(this);
        },
        getModel : function() {
        	return this._model;
        },
        render : function() {
            var headerRow = this._view.createRow(-1);
            this.addChild(headerRow);
            var columnCount = this._model.getColumnCount();
            for (var j = 0; j < columnCount; j++) {
                var headerCell = this._view.createHeaderCellRenderer(j);
                headerRow.addChild(headerCell);
                headerCell.setValue(this._model.getColumnName(j));
            }
            var rowCount = this._model.getRowCount();
            for (var i = 0; i < rowCount; i++) {
                var row = this._view.createRow(i);
                this.addChild(row);
                for (var j = 0; j < columnCount; j++) {
                    var cell = this._view.createCellRenderer(i, j, this._model.isCellEditable(i, j));
                    row.addChild(cell);
                    cell.setValue(this._model.getValueAt(i, j));
                }
            }
        },
        modelChanged : function(event) {
            Logger.getInstance().trace('modelChanged(' + event + ')');
            switch (event.type) {
            case ModelEvent.DELETE:
                for (var i = event.lastRow; i >= event.firstRow; i--) {
                    this.removeChild(i + 1); // For header
                }
                break;
            case ModelEvent.INSERT:
                var columnCount = this._model.getColumnCount();
                for (var i = event.firstRow; i <= event.lastRow; i++) {
                    var row = this._view.createRow(i);
                    //this.addChild(row); // TODO Fix
                    this.insertChild(i + 1, row);
                    for (var j = 0; j < columnCount; j++) {
                        var cell = this._view.createCellRenderer(i, j, this._model.isCellEditable(i, j));
                        row.addChild(cell);
                        cell.setValue(this._model.getValueAt(i, j));
                    }
                }
                break;
            }
        }
    });

    Object.extend(DataGrid,
    {
        Row : Row,
        Cell : Cell,
        View : View,
        Model : Model,
        BeanModel : BeanModel
    });

    return DataGrid;

});
define('jls/html/DomEvent', ['jls/lang/Class', 'jls/gui/Event'], function (Class, Event) {

var DomEvent;
/**
 * @class This class represents a DOM event.
 * @name jls.html.DomEvent
 */
DomEvent = Class.create(Event, /** @lends jls.html.DomEvent.prototype */
{
    initialize : function(event, element) {
        this.type = event.type;
        this.target = event.target;
        this.timeStamp = event.timeStamp;
        this.element = element;
        this._event = event;
    },
    keyCode : function() {
        return ('which' in this._event) ? this._event.which : this._event.keyCode;
    }
});

if (window.attachEvent) { // IE specific event handling
	DomEvent.addMethods({
	    stopPropagation : function() {
        	this._event.cancelBubble = true;
	    },
	    preventDefault : function() {
	    	this._event.returnValue = false;
	    }
	});
} else {
	DomEvent.addMethods({
	    stopPropagation : function() {
        	this._event.stopPropagation();
	    },
	    preventDefault : function() {
        	this._event.preventDefault();
	    }
	});
}

return DomEvent;
});
define('jls/html/Edit', ['jls/lang/Class', 'jls/html/HtmlElement'], function (Class, HtmlElement) {

var Edit;
Edit = Class.create(HtmlElement,
{
    onCreate : function($super) {
        this.setAttribute('htmlTagName', 'input');
        $super();
        this.getHtmlElement().setAttribute('type', this.getAttribute('type') || 'text');
    },
    getText : function() {
        return this.getHtmlElement().value;
    },
    setText : function(value) {
        this.getHtmlElement().value = this.getResourceLabel(value);
        return this;
    }
});


return Edit;
});
define('jls/html/GuiUtilities', ['jls/lang/Class', 'jls/html/HtmlElement'], function (Class, HtmlElement) {

var GuiUtilities;
/**
 * @namespace Provides GUI classes for HTML.
 * @name jls.html
 */

GuiUtilities = Class.create();

Object.extend(GuiUtilities, /** @lends jls.html.GuiUtilities */
{
    getRoot : function() {
        return GuiUtilities.BodyElement.getInstance();
    },
    invokeAndWait : function(fn) {
        return fn();
    },
    invokeLater : function(fn) {
    	setTimeout(fn, 10);
    }
});

GuiUtilities.BodyElement = Class.create(HtmlElement,
{
    getTitle : function() {
        return window.document.title;
    },
    setTitle : function(value) {
        window.document.title = this.getResourceLabel(value);
        return this;
    }
});

Object.extend(GuiUtilities.BodyElement,
{
    _instance : null,
    getInstance : function() {
        if (GuiUtilities.BodyElement._instance == null) {
            var body = document.getElementsByTagName('body')[0];
            GuiUtilities.BodyElement._instance = new GuiUtilities.BodyElement({attributes: {htmlElement: body}});
        }
        return GuiUtilities.BodyElement._instance;
    }
});

return GuiUtilities;
});
define('jls/html/HtmlElement', ['jls/lang/Class', 'jls/lang/Logger', 'jls/gui/Element', 'jls/html/DomEvent'], function (Class, Logger, Element, DomEvent) {

var HtmlElement;
HtmlElement = Class.create(Element,
{
    /*initialize : function($super, parameters, parent) {
        $super(parameters, parent);
    },*/
    onCreate : function() {
        this._htmlDispatcher = null;
        this._htmlEventListeners = {};
    	this._htmlElement = this.getAttribute('htmlElement');
    	if (this._htmlElement == null) {
    		this._htmlElement = this.onCreateHtmlElement();
    	}
    },
    onCreateHtmlElement : function() {
        return document.createElement(this.getAttribute('htmlTagName') || 'div');
    },
    getHtmlElement : function() {
    	return this._htmlElement;
    },
    onAddChild : function(child) {
    	if (child instanceof HtmlElement) {
    		this._htmlElement.appendChild(child._htmlElement);
    	}
    },
    onInsertChild : function(index, child) {
        //Logger.getInstance().trace('onInsertChild(' + index + ')');
        if (child instanceof HtmlElement) {
            Logger.getInstance().trace('' + index + '/' + this._htmlElement.childNodes.length);
            this._htmlElement.insertBefore(child._htmlElement, this._htmlElement.childNodes[index]);
        }
    },
    setClass : function(value) {
        this._htmlElement.className = value;
        return this;
    },
    getClass : function() {
        return this._htmlElement.className;
    },
    clean : function() {
        while (this._htmlElement.hasChildNodes()) {
            this._htmlElement.removeChild(this._htmlElement.firstChild);
        }
        return this;
    },
    getTextContent : function() {
        if ((this._htmlElement != null) && (this._htmlElement.firstChild.nodeType == 3)) {
            return this._htmlElement.firstChild.nodeValue;
        }
        return '';
    },
    setTextContent : function(value) {
        this.clean();
    	this._htmlElement.appendChild(document.createTextNode(this.getResourceLabel(value)));
        return this;
    },
    setHtmlContent : function(value) {
        this.clean();
        this._htmlElement.innerHTML = value;
        return this;
    },
    onSetAttribute : function(key, value) {
    	if ((typeof value != 'undefined') && (value != null)) {
        	this._htmlElement.setAttribute(key, value);
    	} else {
            this._htmlElement.removeAttribute(key);
    	}
    },
    onGetAttribute : function(key) {
        return this._htmlElement.getAttribute(key);
    },
    onStyleChange : function(key, oldValue, newValue) {
    	//Logger.getInstance().trace('onStyleChange(' + key + ', ' + oldValue + ', ' + newValue + ')');
        if (this._htmlElement == null) {
            return;
        }
        if (newValue != null) {
            this._htmlElement.style[key] = newValue;
            //this._htmlElement.style.setProperty(key, newValue);
        } else {
            this._htmlElement.style.removeProperty(key);
        }
    },
    _getDispatcher: function() {
        if (this._htmlDispatcher == null) {
            this._htmlDispatcher = (function(e) {
                this.dispatch(new DomEvent(e, this));
            }).bind(this);
        }
        return this._htmlDispatcher;
    },
    observe: function($super, type, handler) {
	    $super(type, handler);
	    if (! (type in this._htmlEventListeners)) {
	        this._htmlEventListeners[type] = this._getDispatcher();
	        HtmlElement.addEventListener(this._htmlElement, type, this._htmlEventListeners[type]);
	    }
    },
    unobserve: function($super, type, handler) {
    	$super(type, handler);
    	if (! this.isObserving(type)) {
    	    HtmlElement.removeEventListener(this._htmlElement, type, this._htmlEventListeners[type]);
    	    delete this._htmlEventListeners[type];
    	}
    },
    onDestroy : function(detach) {
        //jls.logger.trace('onDestroy() ' + this._htmlElement.nodeName);
        if ((! detach) && this._htmlElement) {
            if (this._htmlElement.parentNode) {
                this._htmlElement.parentNode.removeChild(this._htmlElement);
            }
        }
    },
    containsNode : function(node) {
        if (node === this._htmlElement) {
            return true;
        }
        var children = this.getChildren();
        for ( var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.containsNode(node)) {
                return true;
            }
        }
        return false;
    }
});

Object.extend(HtmlElement,
{
    addEventListener : function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else {
            element.attachEvent('on' + type, handler, false);
        }
    },
    removeEventListener : function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else {
            element.detachEvent('on' + type, handler, false);
        }
    }
});


return HtmlElement;
});
define('jls/html/Label', ['jls/lang/Class', 'jls/html/HtmlElement'], function (Class, HtmlElement) {

var Label;
Label = Class.create(HtmlElement,
{
    onCreate : function($super) {
        this.setAttribute('htmlTagName', 'label')
        $super();
    },
    getText : function() {
        return this.getTextContent();
    },
    setText : function(value) {
    	this.setTextContent(value);
        return this;
    }
});


return Label;
});
define('jls/html/Table', ['jls/lang/Class', 'jls/lang/Exception', 'jls/lang/Logger', 'jls/html/HtmlElement'], function (Class, Exception, Logger, HtmlElement) {

var Table;
Table = Class.create(HtmlElement,
{
    initialize : function($super, parameters, parent) {
        this._fixedOrientation = 'horizontal';
        this._fixedSize = 1;
        this._tableBody = null;
        this._rowAttributes = null;
        this._cellAttributes = null;
        this._cellStyle = null;
        $super(parameters, parent);
    },
    onCreate : function($super) {
        this.setAttribute('htmlTagName', 'table');
        $super();
        this._tableBody = document.createElement('tbody');
        this.getHtmlElement().appendChild(this._tableBody);
    },
    setCellAttributes : function(cellAttributes) {
        this._cellAttributes = cellAttributes;
        return this;
    },
    setRowAttributes : function(rowAttributes) {
        this._rowAttributes = rowAttributes;
        return this;
    },
    setCellStyle : function(cellStyle) {
        this._cellStyle = cellStyle;
        return this;
    },
    getFixedOrientation : function() {
        return this._fixedOrientation;
    },
    setFixedOrientation : function(value) {
        this._fixedOrientation = value;
        return this;
    },
    getFixedSize : function() {
        return this._fixedSize;
    },
    setFixedSize : function(value) {
        if (typeof value != 'number') {
            value = parseInt(value, 10);
        }
        this._fixedSize = value;
        return this;
    },
    insertRow : function(num) {
        Logger.getInstance().trace('insertRow(' + num + ')');
        var row = document.createElement('tr');
        if (this._rowAttributes != null) {
            for (var name in this._rowAttributes) {
                row.setAttribute(name, this._rowAttributes[name]);
            }
        }
        var refElement = null;
        if (num && (num >= 0) && (num < this._tableBody.childNodes.length)) {
            refElement = this._tableBody.childNodes[num];
        }
        this._tableBody.insertBefore(row, refElement);
        return row;
    },
    addRow : function() {
        Logger.getInstance().trace('addRow()');
        return this.insertRow();
    },
    getRow : function(num) {
        Logger.getInstance().trace('getRow(' + num + ')');
        if (typeof num == 'number') {
            if ((num >= 0) && (num < this._tableBody.childNodes.length)) {
                return this._tableBody.childNodes[num];
            }
            while (num > this._tableBody.childNodes.length) {
                this.addRow();
            }
        }
        return this.addRow();
    },
    addCell : function(row, child) {
        Logger.getInstance().trace('addCell()');
        var cell = document.createElement('td');
        if (this._cellAttributes != null) {
            for (var name in this._cellAttributes) {
                switch (name) {
                case 'class':
                case 'className':
                    cell.className = this._cellAttributes[name];
                    break;
                default:
                    cell.setAttribute(name, this._cellAttributes[name]);
                    break;
                }
            }
        }
        if (this._cellStyle != null) {
            for (var key in this._cellStyle) {
                cell.style[key] = this._cellStyle[key];
            }
        }
        row.appendChild(cell);
        cell.appendChild(child.getHtmlElement());
        return cell;
    },
    replaceChild : function(index, child) {
        if (index >= this.getChildCount()) {
            throw new Exception('Index out of bounds');
        }
        var row = this.getRow(index / this._fixedSize);
        var num = index % this._fixedSize;
        var cell = row.childNodes[num];
        while (cell.hasChildNodes()) {
            cell.removeChild(cell.firstChild);
        }
        this.removeChild(index);
        cell.appendChild(child.getHtmlElement());
        //this._children.push(child);
        this._children.splice(index, 0, child);
        return child;
    },
    onAddChild : function(child) {
        var cellIndex = (this.getChildCount() - 1) % this._fixedSize;
        Logger.getInstance().trace('onAddChild() cellIndex: ' + cellIndex);
        var row = null;
        if (this._fixedOrientation == 'horizontal') {
            if (cellIndex == 0) {
                //row = this.getRow(Math.floor(this.getChildCount() / this._fixedSize));
                row = this.addRow();
            } else {
                row = this._tableBody.lastChild;
            }
        } else {
            if (this.getChildCount() <= this._fixedSize) {
                //row = this.getRow(Math.floor(this.getChildCount() / this._fixedSize));
                row = this.addRow();
            } else {
                row = this._tableBody.childNodes[cellIndex];
            }
        }
        this.addCell(row, child);
    },
    removeLastChild : function() {
        this.removeChild(this.getChildCount() - 1);
        var rowCount = Math.floor(this.getChildCount() / this._fixedSize);
        while (this._tableBody.childNodes.length > rowCount) {
            this._tableBody.removeChild(this._tableBody.lastChild);
        }
    }
    /*onRemoveChild : function(child) {
        var rowCount = Math.floor(this.getChildCount() / this._fixedSize);
        while (this._tableBody.childNodes.length > rowCount) {
            this._tableBody.removeChild(this._tableBody.lastChild);
        }
    }*/
});

return Table;
});
define('jls/lang/Exception', ['jls/lang/Class', '_AMD'], function (Class, _AMD) {

var Exception;

Exception = Class.create(/** @lends jls.lang.Exception.prototype */
{
    /**
     * @param {String} [message] The detail message.
     * @param {Object} [cause] The cause.
     * @constructs
     * @class Provide the base Exception.
     */
    initialize : function(message, cause, name) {
        /**
         * The detail message
         * 
         * @private
         * @type String
         */
        this._message = message || null;
        /**
         * The cause
         * 
         * @private
         * @type Object
         */
        this._cause = null;
        if (cause) {
            this._cause = Exception.wrap(cause);
        }
        this._name = name || null;
    },
    /**
     * Returns the cause of this exception or null if the cause is nonexistent or unknown. The cause is the exception that caused this
     * exception to get thrown.
     * 
     * @returns {Object} The cause.
     */
    getCause : function() {
        return this._cause;
    },
    /**
     * Returns the detail message string of this exception.
     * 
     * @returns {String} The detail message.
     */
    getMessage : function() {
        return this._message;
    },
    getName : function() {
        return this._name || _AMD.getModuleId(this) || 'Exception';
    },
    /**
     * Returns the stack trace of this exception.
     * 
     * @returns {Array} The stack trace.
     */
    getStackTrace : function() {
        return [];
    },
    /**
     * Prints this exception and its stacktrace.
     * 
     * @param {jls.io.PrintStream} [ps] The print stream to use.
     */
    printStackTrace : function(ps) {
        if (! ps) {
            return;
        }
        var last = null;
        for (var e = this; e != null; e = e.getCause()) {
            if (e == this) {
                ps.println(e.toString());
            } else {
                ps.println('Caused by: ' + e.toString());
            }
            var st = e.getStackTrace();
            var steStr = null;
            for (var i = 0; i < st.length; i++) {
                var ste = st[i]
                steStr = '\tat ' + ste.fileName + ':' + ste.lineNumber;
                if (ste.arguments && (ste.arguments.length > 2)) {
                    steStr += ' called with ' + ste.arguments;
                }
                if (steStr == last) {
                    ps.println('\t... ' + (st.length - i) + ' more');
                    break;
                }
                ps.println(steStr);
            }
            last = steStr;
        }
    },
    /**
     * Returns a short description of this exception.
     * 
     * @returns {String} The detail message.
     */
    toString : function() {
        var msg = this.getMessage();
        if (msg == null) {
            return this.getName();
        } else {
            return this.getName() + ': ' + msg;
        }
    }
});

Object.extend(Exception, /** @lends jls.lang.Exception */
{
    wrap : function(e) {
        if (e instanceof Exception) {
            return e;
        } else {
            return new Exception(e == null ? undefined : e.toString());
        }
    }
});

return Exception;
});
define('jls/util/Cookie', ['jls/lang/Class'], function (Class) {

var Cookie;
/**
 * @class This class is a collection of Cookie helper functions.
 * @name jls.util.Cookie
 */
Cookie = Class.create();

Object.extend(Cookie, /** @lends jls.util.Cookie */
{
    /**
     * Returns a cookie depending on its name or null if there is no cookie for this name.
     * 
     * @param {String} name The name of the cookie to get.
     * @returns {String} The value or null if there is no cookie for this name.
     */
    get : function(name) {
        var cookies = document.cookie;
        var prefix = name + '=';
        var indexOfPrefix = cookies.indexOf('; ' + prefix);
        if (indexOfPrefix > 0) {
            indexOfPrefix += 2;
        } else {
            indexOfPrefix = cookies.indexOf(prefix);
            if (indexOfPrefix != 0) {
                return null;
            }
        }
        var end = document.cookie.indexOf(';', indexOfPrefix);
        if (end == -1) {
            end = cookies.length;
        }
        return unescape(cookies.substring(indexOfPrefix + prefix.length, end));
    },
    /**
     * Sets a cookie.
     * The expiration date tells the browser when to delete the cookie.
     * The domain and path tell the browser that the cookie has to be sent back to the server when requesting URLs of a given domain and path.
     * If not specified, they default to the domain and path of the object that was requested.
     * As a result, the domain and path strings may tell the browser to send the cookie when it normally would not.
     * For security reasons, the cookie is accepted only if the server is a member of the domain specified by the domain string.
     * A secure cookie is only used when a browser is visiting a server via HTTPS.
     * 
     * @param {String} name The name of the cookie to set.
     * @param {String} value The value.
     * @param {Object} [opts] The options.
     * @param {Date} [opts.expires] The expiration date.
     * @param {String} [opts.domain] The domain.
     * @param {String} [opts.path] The path.
     * @param {String} [opts.secure] The secure.
     */
    set : function(name, value, opts) {
        var cookie = name + '=' + escape(value);
        if (opts) {
            if (('expires' in opts) && (opts.expires != null)) {
                cookie += '; expires=' + opts.expires.toGMTString();
            }
            if (('domain' in opts) && (opts.domain != null)) {
                cookie += '; domain=' + opts.domain.toString();
            }
            if (('path' in opts) && (opts.path != null)) {
                cookie += '; path=' + opts.path.toString();
            }
            if (('secure' in opts) && opts.secure) {
                cookie += '; secure';
            }
        }
        document.cookie = cookie;
    },
    /**
     * Clears a cookie depending on its name.
     * 
     * @param {String} name The name of the cookie to get.
     */
    clear : function(name) {
        document.cookie = name + '=; expires=' + new Date(0).toGMTString(); 
    },
    /**
     * Returns all cookies.
     * 
     * @returns {Object} The cookies.
     */
    all : function() {
        var cookies = document.cookie;
        cookies = cookies.split('; ');
        var all = {};
        for (var i = 0; i < cookies.length; i++) {
            var kv = cookies[i].split('=');
            all[kv[0]] = kv[1];
        }
        return all;
    }
});

return Cookie;
});
define('jls/util/Location', ['jls/lang/Class'], function (Class) {

var Location;
/**
 * @class This class is a collection of Location helper functions.
 */
Location = Class.create();

Object.extend(Location, /** @lends jls.util.Location */
{
	hash : function(value) {
		if (typeof value == 'undefined') {
	        return this.getHash();
		}
		this.setHash(value);
	},
	search : function(value) {
		if (typeof value == 'undefined') {
	        return this.getSearch();
		}
		this.setSearch(value);
	},
    reload : function() {
        window.location.reload();
        return this;
    },
	getHash : function() {
		var hash = window.location.hash;
        return hash && hash.length > 1 ? hash.substr(1) : '';
	},
	setHash : function(value) {
		if (value) {
			window.location.replace(window.location.pathname + '#' + value);
		} else {
			window.location.replace(window.location.pathname + '#');
		}
	},
	getSearch : function() {
		var search = window.location.search;
        return search && search.length > 1 ? search.substr(1) : '';
	},
	setSearch : function(value) {
		if (value) {
			window.location.search = value;
		} else {
			window.location.replace(window.location.pathname);
		}
	},
    toQuery : function(queryObj) {
    	var queryStr = '';
    	for (var key in queryObj) {
    		if (queryStr.length > 0) {
        		queryStr += '&';
    		}
    		queryStr += key + '=' + queryObj[key];
    	}
    	return queryStr;
    },
    decodeURIComponent : function(s) {
        return decodeURIComponent(s).replace('+', ' ');
	},
    parseQuery : function(queryStr) {
        var queryObj = null;
        var pairs = queryStr.split('&');
        for (var i = 0; i < pairs.length; i++) {
        	var pair = pairs[i];
        	var j = pair.indexOf('=');
        	if (j >= 0) {
        	    if (queryObj == null) {
        	        queryObj = {};
        	    }
                var key = Location.decodeURIComponent(pair.substring(0, j));
                var value = Location.decodeURIComponent(pair.substring(j + 1));
        		queryObj[key] = value;
        	}
        }
        return queryObj;
    }
});

return Location;
});
define('jls/util/Sxe', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/util/SxeEnvelope',
  'jls/util/EventBroker'
], function (
  Class,
  Exception,
  Logger,
  SxeEnvelope,
  EventBroker
) {

var Sxe;
Sxe = Class.create( /** @lends jls.util.Sxe.prototype */
{
    /**
     * Creates a Simple XML Exchange.
     * 
     * @param {String} url The URL.
     * @constructs
     * @class This class represents a Simple XML Exchange.
     */
    initialize : function(url) {
        this._url = url;
        this._eventBroker = null;
    },
    getEventBroker : function() {
        if (this._eventBroker == null) {
            return Sxe.DEFAULT_EVENT_BROKER;
        }
        return this._eventBroker;
    },
    setEventBroker : function(eventBroker) {
        this._eventBroker = eventBroker;
    },
    onException : function(e) {
        Logger.getInstance().warn('Uncaught exception during exchange processing "' + e + '"');
        setTimeout(function() {
            throw new Exception('Uncaught exception during exchange processing "' + e + '"', e);
        }, 10);
    },
    /**
     * Sends the SXE request.
     * 
     * @param {jls.util.SxeEnvelope} value The XML value to send.
     * @param {Function} [onComplete] The function to call when a request completes.
     * @param {Function} [onException] The function to call when an exception is raised.
     */
    send : function(value, onComplete, onException) {
        //var charset = 'ISO-8859-1';
        var charset = 'UTF-8';
		var body = value.toString(charset);
        Logger.getInstance().trace('Sxe.send("' + body + '")');
    	var onCompleteWrapper = Class.emptyFunction;
    	if (onComplete) {
    	    var self = this;
    		onCompleteWrapper = function() {
    		    if (this.succeed()) {
    		        Logger.getInstance().trace('Sxe received ->' + this.getResponseText() + '<-');
    		    } else {
                    Logger.getInstance().trace('Sxe failed (' + this.getStatus() + ')');
    		    }
				var response = new Sxe.SxeResponse(this);
				if (typeof onComplete == 'string') {
				    self.getEventBroker().publish(onComplete, response);
				} else {
				    onComplete(response);
				}
            };
    	}
    	new _native.boot.httpRequest(this._url, {
            method :'post',
            contentType :'application/x-www-form-urlencoded', // 'text/plain',
            postBody :body,
            encoding : charset,
            asynchronous :true,
            onException : this.getEventBroker().callback(onException) || this.onException,
            onComplete : onCompleteWrapper,
            context : this
        }).send();
    }
});

Object.extend(Sxe,
{
    /**
     * The default event broker.
     * @type jls.util.EventBroker
     */
    DEFAULT_EVENT_BROKER: EventBroker.DEFAULT
});


Sxe.SxeResponse = Class.create( /** @lends jls.util.Sxe.SxeResponse.prototype */
{
    /**
     * Creates a Simple XML Exchange Response.
     * 
     * @param {Object} httpRequest The HTTP request native object.
     * @constructs
     * @class This class represents a Simple XML Exchange Response.
     */
    initialize : function(httpRequest) {
        this._httpRequest = httpRequest;
    },
    /**
     * Returns the HTTP status.
     * @returns {Number} the HTTP status.
     */
    getStatus : function() {
        return this._httpRequest.getStatus();
    },
    /**
     * Tells wether or not the exchange completes succesfully.
     * @returns {Boolean} true if the exchange completes succesfully.
     */
    succeed : function() {
        var status = this._httpRequest.getStatus();
        if ((status >= 200) && (status < 300) && (this._httpRequest._xhr.responseXML)) {
            return true;
        }
        return false;
    },
    /**
     * Returns the response envelope.
     * @returns {jls.util.SxeEnvelope} the response envelope.
     */
    getEnvelope : function() {
        return SxeEnvelope.createFromDOM(this._httpRequest.getResponseXML());
    }
});

return Sxe;
});
define('jls/util/XMLHttpRequest', ['jls/lang/Class', 'jls/lang/Exception'], function (Class, Exception) {

var XMLHttpRequest;
XMLHttpRequest = Class.create({
    /**
     * Creates an XMLHttpRequest.
     * 
     * @param {String} url The URL.
     * @constructs
     * @class This class allows to perform HTTP requests.
     */
    initialize : function(url) {
        this._url = url;
        this._method = 'get';
        this._contentType = 'application/x-www-form-urlencoded'; // 'text/plain';
        this._user = null;
        this._password = null;
        this._async = true;
        this._headers = null;
    },
    /**
     * Sets the authentication credentials.
     * 
     * @param {String} user The authentication user.
     * @param {String} password The authentication password.
     * @returns {jls.util.XMLHttpRequest} this XMLHttpRequest.
     */
    setAuthentication : function(user, password) {
        this._user = user;
        this._password = password;
        return this;
    },
    /**
     * Sets the HTTP content type.
     * 
     * @param {String} contentType The HTTP content type.
     * @returns {jls.util.XMLHttpRequest} this XMLHttpRequest.
     */
    setContentType : function(contentType) {
        this._contentType = contentType;
        return this;
    },
    /**
     * Sets the HTTP method.
     * 
     * @param {String} method The HTTP method.
     * @returns {jls.util.XMLHttpRequest} this XMLHttpRequest.
     */
    setMethod : function(method) {
        this._method = method;
        return this;
    },
    /**
     * Adjusts this request's asynchronous mode.
     * 
     * @param {Boolean} asynchronous Whether the request is placed in asynchronous mode.
     * @returns {jls.util.XMLHttpRequest} this XMLHttpRequest.
     */
    configureAsynchronous : function(asynchronous) {
        this._async = asynchronous;
        return this;
    },
    /**
     * Appends an header to the list of HTTP header name/value pairs to be used in the request.
     * 
     * @param {String} name The name of the header.
     * @param {String} [value] The value of the header.
     * @returns {jls.util.XMLHttpRequest} this XMLHttpRequest.
     */
    setRequestHeader : function(name, value) {
        if (this._headers == null) {
            this._headers = {};
        }
        if (typeof value == 'undefined') {
            delete this._headers[name];
        } else {
            this._headers[name] = value;
        }
        return this;
    },
    /**
     * Sends the HTTP request.
     * 
     * @param {String} [data] The HTTP body to send.
     * @param {Function} [onComplete] The function to call when the request completes.
     * @param {Function} [onException] The function to call when an exception is thrown.
     */
    send : function(data, onComplete, onException) {
        new _native.boot.httpRequest(this._url, {
            method : this._method,
            contentType : this._contentType,
    	    user : this._user,
    	    password : this._password,
            postBody : data || null,
            asynchronous : this._async,
            onComplete : onComplete || Class.emptyFunction,
            onException : onException || XMLHttpRequest.DEFAULT_ON_EXCEPTION,
            headers : this._headers,
            context : this
        }).send();
    }
});

Object.extend(XMLHttpRequest, /** @lends jls.util.XMLHttpRequest */
{
    DEFAULT_ON_EXCEPTION: function(e) {
        //jls.logger.warn('Uncaught exception during exchange processing "' + e + '"');
        setTimeout(function() {
            throw new Exception('Uncaught exception during request processing (' + e + ')', e);
        }, 10);
    }
});

return XMLHttpRequest;
});

require(['_AMD'], function(_AMD) {
  _AMD.disableDefine();
  _AMD.disableDeferredLoading();
});
