IQdev = new function () { // version: 0.1.2

/*

	standardization:

	- pseudo constants are written in UPPERCASE and should not be changed under no circumstances
	--- :note: javascript does not have real constants
	--- :example: I_AM_CONSTANT

	- functions/methods and variables/properties are written in mixedCase starting with lower case character
	--- :example: iAmVariable, iAmFunction, iAmMethod

	- classes are written in MixedCase starting with start with capital letter
	--- :note: classes are realized using function objects
	--- :example: IamClass

	- each class should have set NAME private property and defined .toString public method
	--- if not used otherwise, .toString method should return NAME private property

	- each function/method should use try/catch[/finally] statement and implement error handling
	  and reporting mechanism using checkArguments and supplied error logging functions

	- :note: all error logging functions (starting with log...) return null value


*/

	// ----- PROTECTED pseudo CONSTANTS -----
    // should be treated strictly as READ ONLY !!!

	var DOM_LEVEL_1; // true, if DOM level 1 is supported
	var DOM_LEVEL_2; // true, if DOM level 2 is supported
	var ERR_MESSAGE = 0; // informative message
	var ERR_WARNING = 1; // system warning or recoverable error, which cannot impact behaviour
	var ERR_IMPORTANT = 10; // important system warning or recoverable error, which may impact behaviour
	var ERR_ERROR = 30; // module specific non-recoverable error, that may render part of modul useless
	var ERR_FAILURE = 50; // non-critical, non-recoverable error, that causes local mulfunctions
	var ERR_FATAL = 99; // critical error, typically missing critical feature or unknown exception
	var ERROR_NO_METHOD = new Error('no known method is available');
	var ERROR_NOT_FOUND = new Error('object not found');
	var ERROR_NOT_NUMBER = new Error('unknown number format');
	var ERROR_OBJECT_CREATE = new Error('object creation failed');
    var ERROR_INVALID_VALUE = new Error('invalid value');
	var IS_ARGUMENTS_OBJECT; // true, if function 'arguments' is object and needs conversion to array
							 // :note: for compatibility always use supplied 'fixArguments' method
	var IS_IE; // true, if browser is Internet Explorer, initialized in constructor, see there for details
	var IS_NAME_BUG; // true if document.getElementById incorrectly returns also by Name
	var IS_NETSCAPE; // true if browser is old Netscape browser
	var IS_XMLHTTP; // true, if known XML HTTP request method is supported
	var NAME = 'IQdev';
	var PX; // should be used when setting CSS values (e.g. width, ...)
	var REGEXP_FLOAT = new RegExp('^[+-]{0,1}[0-9]+[\\.]{0,1}[0-9]*$');
	var REGEXP_INTEGER = new RegExp('^[+-]{0,1}[0-9]*$');

	// ----- PROTECTED PROPERTIES -----

    var config; // initial config object
	var clientPath; // path to javascript engine
	var debugMode; // true if debug mode is enabled
	var domDocumentBody; // pointer to DOM document body
	var domDocumentRoot; // pointer to root DOM document element
	var e; // reserved for error container
	var ee; // reserved for error container
	var eee; // reserved for error container
	var falseFunction; // empty function returning boolean 'false' value
	var init; // true if everything needed is ok
	var loggingDisabled; // no errors except critical are logged
	var loggingLevel; // how serious errors are logged
    var modules; // object with loaded modules
	var myGetElementById; // holds pointer to document.getElementById or alternative
	var myXmlHttpRequest; // holds pointer to class for creating XML Http request
	var nullFunction; // empty function returning null value
	var voidFunction; // empty function returning no value
	var self = this;
	var serverExtension; // extension of server side scripts
	var serverPath; // path to server side scripting engine
	var sessionStartTime; // unix timestamp of session start time
	var sysLog; // holds system log
	var sysLogEventCall; // holds function to be called on system log event
    var userIniFile; // filename and path to file with user ini

	// ----- PUBLIC METHODS -----

    this.execFunction = function (f, o) {
    // see private method execFunction
        return execFunction(f, o);
    };

    this.execScript = function (s) {
    // see private method execScript
        return execScript(s);
    };

	this.toString = function () {
		return NAME;
	};

	// ----- PROTECTED METHODS -----

	function checkArguments() {
	// see module 'debug' for details
		return true;
	}

	function debugOn(required) {
	// enable debug mode, extra logging and advanced debugger
	// :note: this option slows application and is not recommended for production environment
		if (debugMode !== true) {
			if (!required) {
				includeModule('debug'); // debug is standalone, so we can load it asynchronously
			} else {
				requireModule('debug'); // but if asked, make synchronous request
			}
			debugMode = true;
		}
	}

	function debugOff() {
	// disable debug mode
		if (debugMode !== false) {
			debugMode = false;
		}
	}

	function domGetElementById(elementName) {
	// browser optimized api for getElementById function
		try {
			checkArguments(arguments, 1, 'S');
			return myGetElementById(elementName);
		} catch (e) {
			logFatal.call(this, e);
		}
		return null;
	}

    function execEval(s) {
    // function executes eval on string suspending possible crash
    // - on success returns eval value of string
    // - on failure returns error object
        try {
            return eval(s); // neccessary here, sorry
        } catch (e) {
            return e;
        }
    }

    function execFunction(f, o) {
    // executes function on local private scope
    // :note: right now I do not know any option how to execute function on private scope
    //        without converting it to 'string' and than EVALing it
    // :todo: is it possible to execute function on private scope without dirty EVAL ???
        try {
            var s;

            if (!isFunction(f)) {
                throw new Error('first parameter must be "function" type');
            }
            s = execEval('s = ' + String(f) + ';');
            s(o);
            return true;
        } catch (e) {
            logFailure.call(this, 'execFunction', e);
            return false;
        }
    }

    function execScript(s) {
    // executes script on local private scope
        return safeEval(s);
    }

	function fixArguments(args) {
	// function fixes arguments to be array, because IE incorectly *sometimes* creates object instead
		var i;
		var a;

		try {
			if (IS_ARGUMENTS_OBJECT && (typeof args.length !== 'number')) {
				a = [];
				for (i in args) if ((typeof args.hasOwnProperty !== 'function') || args.hasOwnProperty(i)) {
					a[a.length] = args[i];
				}
				return a;
			} else {
				return args;
			}
		} catch (e) {
			logFailure.call(this, 'fixArguments', e);
			return [];
		}
	}

	function getDate() {
	// returns date in YYYY:mm:dd format
		var d = new Date();

		return d.getFullYear() + (d.getMonth() < 10 ? '-0' : '-') + d.getMonth() +
			(d.getDate() < 10 ? '-0' : '-') + d.getDate();
	}

	function getFile(requestURI, onSuccess, onFailure, onChange, silentMode) {
	// returns contents of file with get request, no data are posted
		var request, response;

		checkArguments(arguments, 1, 'Sfffb');
		request = new XmlHttp(requestURI, 'get', null, onSuccess, onFailure, onChange, silentMode);
		response = request.get();

		return response.response;
	}

	function getFilePostData(requestURI, postData, onSuccess, onFailure, onChange, silentMode) {
	// returns contents of file with post request, posted data are raw data
		var request, response;

		checkArguments(arguments, 2, 'SSfffb');
		request = new XmlHttp(requestURI, 'rawpost', postData, onSuccess, onFailure, onChange, silentMode);
		response = request.get();

		return response.response;
	}

	function getFilePostVars(requestURI, postVars, onSuccess, onFailure, onChange, silentMode) {
	// returns contents of file with post request, posted data are in get format
		var request, response;

		checkArguments(arguments, 2, 'SSfffb');
		request = new XmlHttp(requestURI, 'post', postVars, onSuccess, onFailure, onChange, silentMode);
		response = request.get();

		return response.response;
	}

	function getTime() {
	// returns time in HH:ii:ss format
		var t = new Date();

		return (t.getHours() < 10 ? '0' : '') + t.getHours() + (t.getMinutes() < 10 ? ':0' : ':') + t.getMinutes() +
			(t.getSeconds() < 10 ? ':0' : ':') + t.getSeconds();
	}

	function getTimeStamp() {
	// returns current unix time stamp
		return new Date().getTime();
	}

	function includeModule(moduleName) {
	// load module asynchronously
		var module;

		checkArguments(arguments, 1, 'S');
		module = new Module(moduleName, voidFunction);
	}

	function isArray(a) {
	// returns true if argument is array
		try {
			return (typeof a === 'object') && isNumeric(a.length) && isFunction(a.propertyIsEnumerable) &&
				!a.propertyIsEnumerable('length') && isFunction(a.splice) ?
				true : false;
		} catch (e) {
			logFailure.call(this, 'isArray', e);
			return false;
		}
	}

	function isBoolean(b) {
	// returns true if argument is boolean
		try {
			return typeof b === 'boolean' ? true : false;
		} catch (e) {
			logFailure.call(this, 'isBoolean', e);
			return false;
		}
	}

	function isDefined(a) {
	// returns true if argument is defined (aka is not undefined)
		try {
			return typeof a === 'undefined' ? false : true;
		} catch (e) {
			logFailure.call(this, 'isDefined', e);
			return true;
		}
	}

	function isEmptyArray(a) {
	// returns true if argument is empty array
		try {
			return isArray(a) && isZero(a.length) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isEmptyArray', e);
			return false;
		}
	}

	function isEmptyObject(o) {
	// returns true if argument is empty object
		var i; // iterator

		try {
			if (o === isEmptyObject) { // if inside self
				return false; // prevent self-inspecting loop
			}
			if (!isObject(o)) { // if not in object
				return false;
			}
			for (i in o) if ((!isFunction(o.hasOwnProperty) || o.hasOwnProperty(i)) &&
				isDefined(o[i]) && !isFunction(o[i])) {
				return false;
			}
			return true;
		} catch (e) {
			logFailure.call(this, 'isEmptyObject', e);
			return false;
		}
	}

	function isEmptyString(s) {
	// returns true if argument is empty string
		try {
			return isString(s) && (s === '') ? true : false;
		} catch (e) {
			logFailure.call(this, 'isEmptyString', e);
			return false;
		}
	}

	function isFunction(f) {
	// returns true, if argument is function
		try {
			return typeof f === 'function' ? true : false;
		} catch (e) {
			logFailure.call(this, 'isFunction', e);
			return false;
		}
	}

	function isNegative(n) {
	// returns true if n is valid negative number
		try {
			return isNumber(n) && (n < 0) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNegative', e);
			return false;
		}
	}

	function isNonEmptyArray(a) {
	// returns true, if argument is non-empty array
		try {
			return isArray(a) && isPositive(a.length) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNonEmptyArray', e);
			return false;
		}
	}

	function isNonEmptyObject(o) {
	// returns true, if argument is non-empty object
		var i; // iterator

		try {
			if (o === isNonEmptyObject) { // if inside self
				return true; // prevent self-inspecting loop
			}
			if (!isObject(o)) { // if not in object
				return false;
			}
			for (i in o) if ((!isFunction(o.hasOwnProperty) || o.hasOwnProperty(i)) &&
				isDefined(o[i]) && !isFunction(o[i])) {
				return true;
			}
			return false;
		} catch (e) {
			logFailure.call(this, 'isNonEmptyObject', e);
			return false;
		}
	}

	function isNonEmptyString(s) {
	// returns true, if argument is non-empty string
		try {
			return isString(s) && (s !== '') ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNonEmptyString', e);
			return false;
		}
	}

	function isNull(o) {
	// returns true, if argument is null
		try {
			return o === null ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNull', e);
			return false;
		}
	}

	function isNumber(n) {
	// returns true, if argument is enumerable number
		try {
			return isNumeric(n) && isFinite(n) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNumber', e);
			return false;
		}
	}

	function isNumeric(n) {
	// returns true, if argument is string
		try {
			return typeof n === 'number' ? true : false;
		} catch (e) {
			logFailure.call(this, 'isNumeric', e);
			return false;
		}
	}

	function isObject(o) {
	// returns true, if argument is object
		try {
			return (typeof o === 'object') && !isNull(o) && !isArray(o) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isObject', e);
			return false;
		}
	}

    function isPercent(n) {
    // return true, if argument is percent
        var p;

        if (!isNonEmptyString(n)) {
            return false;
        }
        p = n.length;
        if ((p > 1) && (n.substr(p - 1) === '%') &&
            REGEXP_FLOAT.test(n.substr(0, p - 1))) {
            return true;
        }
        return false;
    }

	function isPositive(n) {
	// returns true if n is valid positive number
		try {
			return isNumber(n) && (n > 0) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isPositive', e);
			return false;
		}
	}

	function isString(s) {
	// returns true, if argument is string
		try {
			return typeof s === 'string' ? true : false;
		} catch (e) {
			logFailure.call(this, 'isString', e);
			return false;
		}
	}

	function isValue(v) {
	// returns true, if argument is non-empty string of valid number
		try {
			return isNonEmptyString(v) || isNumber(v) ? true : false;
		} catch (e) {
			logFailure.call(this, 'isValue', e);
			return false;
		}
	}

	function isZero(n) {
	// returns true if n is valid zero number
		try {
			return n === 0 ? true : false;
		} catch (e) {
			logFailure.call(this, 'isZero', e);
			return false;
		}
	}

	function logFatal(e) {
	// log critical error - always returns null
		return sysLogEvent.call(this, ERR_FATAL, 'Unexpected error', e);
	}

	function logError(message, e) {
	// log module specific error - always returns null
		return sysLogEvent.call(this, ERR_ERROR, message, e);
	}

	function logImportant(message, e) {
	// log important warning - always returns null
		return sysLogEvent.call(this, ERR_IMPORTANT, message, e);
	}

	function logMessage(message) {
	// log message - always returns null
		return sysLogEvent.call(this, ERR_MESSAGE, message);
	}

	function logFailure(functionName, e) {
	// log system error - always returns null
		return sysLogEvent.call(this, ERR_FAILURE, '"' + toHtml(functionName) + '" failed', e);
	}

	function logWarning(message, e) {
	// log warning - always returns null
		return sysLogEvent.call(this, ERR_WARNING, message, e);
	}

	function requireModule(moduleName) {
	// load module synchronously
		var module;

		checkArguments(arguments, 1, 'S');
		module = new Module(moduleName); // load synchronously
	}

	function safeEval(s) {
	// function evaluates string suspending possible crash
	// - on success returns true
	// - on failure returns error object
        var er;

		try {
            er = execEval(s);
            if (er instanceof Error) {
			    throw er;
            }
            return true;
		} catch (e) {
			return e;
		}
	}

	function sysLogEvent(errorLevel, errorMessage, errorData) {
	// function mediates system log event call
	// :note: sysLogEventCall *MUST NOT* crash, i.e. it must self-handle errors
		sysLogEventWrite.call(this, errorLevel, errorMessage, errorData);
		sysLogEventCall.call(this);
		return null;
	}

	function sysLogEventWrite(errorLevel, errorMessage, errorData) {
	// store system event into system log
	// system log is array of objects, each object has these properties:
	// - creationDate - date of event creation, string in YYYY-MM-DD format
	// - creationTime - time of event creation, string in HH:ii:ss format
	// - callerFunction - function, which caused the error
	// - errorLevel - level of error event, see ERR_ constants
	// - errorData - additional error data
		var functionName; // name of caller function
		var nowDate; // current date
		var nowTime; // current time
		var sysLogSelfError; // empty string if ok, string if self-test failed

		if (loggingDisabled || (errorLevel < loggingLevel)) {
			return null;
		}

		functionName = isFunction(this.toString) ? this.toString() : '-anonymous-function-';
		nowDate = getDate();
		nowTime = getTime();

		// we cannot use checkArguments here, because we could get into loop
		// and get 'Stack overflow' easily, so we perform argument self-test

		sysLogSelfError = ''; // we assume no error at first
		if (!isNumber(errorLevel)) { // self check for correct errorLevel value
			sysLogSelfError += '"errorLevel" parameter must be number, "' + typeOf(errorLevel) + '" given\n';
			errorLevel = ERR_FATAL; // on no error given assume highest error level
		}
		if (!isString(errorMessage)) { // self check for correct errorMessage value
			sysLogSelfError += '"errorMessage" parameter must be string, "' + typeOf(errorMessage) + '" given\n';
			errorMessage = 'invalid non-string message';
		}
		if (sysLogSelfError !== '') { // is self-test failed, log event
			sysLog[sysLog.length] = {
				creationDate: nowDate,
				creationTime: nowTime,
				callerFunction: functionName,
				errorLevel: ERR_FAILURE,
				errorMessage: '"sysLogEventWrite" self-test failed',
				errorData: sysLogSelfError
			};
		}
		sysLog[sysLog.length] = {
			creationDate: nowDate,
			creationTime: nowTime,
			callerFunction: functionName,
			errorLevel: errorLevel,
			errorMessage: errorMessage,
			errorData: errorData
		};
		return null;
	}

	function toHtml(s) {
	// converts html characters to entities
		return String(s).
			replace(/\&/g, '&amp;').
			replace(/>/g, '&gt;').
			replace(/</g, '&lt;').
			replace(/\"/g, '&quot;').
			replace(/\'/g, '&#039;').
			replace(/\\n/g, "<br />").
			replace(/\\r/g, "").
			replace(/\\t/g, " ");
	}

	function toNumber(n, precision, keepString) {
	// returns number with selected precision
	// - if precision is given, number will be returned with selected precision
	//   :note: precision of 0 is integer number, negative values will round the number
	//          to 10 power (-precision), i.e. value of -2 will round 2531 to 2500
	// - by default, number is returned as Number type, if keepString is true, and
	//   precision is given, the number will be returned as String type

		var p;

		checkArguments(arguments, 1, 'vib');
		if (isNumber(n)) {
			if(isNumber(precision)) {
				n = n.toFixed(n);
			}
			return keepString ? n : Number(n);
		} else if (typeof n === 'string') {
			p = n.length;
			if((p > 2) && (n.substr(p - 2) === 'px') &&
				REGEXP_INTEGER.test(n.substr(0, p - 2))) {
				n = Number(n.substr(0, n.length-2));
				if(isNumber(precision)) {
					n = n.toFixed(precision);
				}
				return keepString ? n : Number(n);
			} else if ((p > 1) && (n.substr(p - 1) === '%') &&
				REGEXP_FLOAT.test(n.substr(0, p - 1))) {
				n = Number(n.substr(0, p - 1) / 100);
				if(isNumber(precision)) {
					n = n.toFixed(precision);
				}
				return keepString ? n : Number(n);
			} else if (REGEXP_FLOAT.test(n)) {
				n = Number(n);
				if(isNumber(precision)) {
					n = n.toFixed(precision);
				}
				return keepString ? n : Number(n);
			} else {
				throw ERROR_NOT_NUMBER;
			}
		}
	}

	function typeOf(v, simple) {
	// return type of v using advanced detections and better recognition scope
	// - if simple is true, only lower case values are returned
	//   (i.e. 'string' is returned for empty and non-empty string)
	// - if simple is false (or not given), advanced mode is enabled (see inline notes)
		if (typeof v === 'undefined') { // undefined
			v = 'undefined';
		} else if (v === null) { // if null, let's report it as 'null'
			v = 'null';
		} else if (typeof v === 'function') { // function
			v = 'function';
		} else if (typeof v === 'boolean') { // if boolean, let's test it for value
			v = (v ? 'Boolean' : 'boolean'); // if true, let's capitalize first letter
		} else if (typeof v === 'string') { // if v is string, let's test if it is empty
			v = (v === '' ? 'string' : 'String'); // if not empty, let's capitalize first letter
		} else if(v === NaN) { // if number type but not a number
			v = 'NaN (not-a-number)';
		} else if(v === Infinity) { // if number type but positive infinity
			v = 'positive-infinity';
		} else if(v === Infinity) { // if number type but negative infinity
			v = 'negative-infinity';
		} else if(v === NaN) { // if number type but not a number
			v = 'NaN (not-a-number)';
		} else if (typeof v === 'number') { // if v is number, let's test if it is valid value
			v = 'number';  // if valid, let's capitalize first letter
		} else if (isArray(v)) { // if v is array, let's test if it is empty
			v = (v.length === 0 ? 'array' : 'Array'); // if not empty, let's capitalize first letter
		} else if (typeof v === 'object') { // if v is object (and this is the only option left), let's test if it is empty
			v = isNonEmptyObject(v) ? 'Object' : 'object'; // if not empty, let's capitalize first letter
		} else { // this should never happen
			alert('unknown type');
		}
		return simple ? v.toLowerCase() : v; // if simple mode is requested, convert all to lower case
	}

	// ----- ONLOAD INITIALIZATION -----

	window.onload = function () {
		var NAME = 'window.onload';

		this.toString = function () {
			return NAME;
		};

		function findDocumentBody() {
		// find DOM document body element
			try {
				if (document.getElementsByTagName('body')) {
					domDocumentBody = document.getElementsByTagName('body').item(0);
					throw 'body';
				} else if (document.getElementsByTagName('html').item(0)) {
					domDocumentBody = document.getElementsByTagName('html').item(0);
					throw 'html';
				} else {
					domDocumentBody = null;
					throw 'no support';
				}
			} catch (e) {
				if (e === 'no support') {
					logImportant.call(this, 'could not find document body', ERROR_NOT_FOUND);
				} else if (typeof e === 'string') {
					logMessage.call(this, 'using "' + e + '" as DOM document body');
				} else {
					domDocumentBody = null;
					return logFatal.call(this, e);
				}
			}
		}

		function findDocumentRoot() {
		// find root DOM document element
			try {
				domDocumentRoot = document;
				if (isDefined(document)) {
					if (isDefined(document.documentElement)) { // modern browsers
						domDocumentRoot = document.documentElement;
						throw 'document.documentElement';
					} else if (isDefinded(document.all)) { // IE 6 and lower
						domDocumentRoot = document.all;
						throw 'document.all';
					} else if (isDefined(document.layers)) { // old NetScape
						domDocumentRoot = document.layers;
						throw 'document.layers';
					} else { // cannot guess safely, use best possible option
						domDocumentRoot = document;
						throw 'document';
					}
				}
			} catch (e) {
				if (typeof e === 'string') {
					logMessage.call(this, 'using "' + e + '" as root DOM document');
				} else {
					logFatal.call(this, 'could not safely find document body, using default "document"');
				}
			}
		}

		function findEncodeURI() {
			if (isFunction(encodeURI)) {
				logMessage.call(this, '"encodeURI" function found');
			} else {
				encodeURI = function (s) {
					s = escape(s);
					return s.
						replace('%21', '!').
						replace('%23', '#').
						replace('%24', '$').
						replace('%26', '&').
						replace('%28', '(').
						replace('%29', ')').
						replace('%3D', '=').
						replace('%3A', ':').
						replace('%3B', ';').
						replace('%3F', '?').
						replace('%27', "'").
						replace('%2C', ",").
						replace('%7E', "~");
				};
				logImportant.call(this, '"encodeURI" function NOT found, ',
					'this was fixed but ONLY for ASCII characters 0 to 127 (included)');
			}
		}

		function findEncodeURIComponent() {
			if (isFunction(encodeURIComponent)) {
				logMessage.call(this, '"encodeURIComponent" function found');
			} else {
				encodeURIComponent = function (s) {
					s = escape(s);
					return s.
						replace('%21', '!').
						replace('@', '%40').
						replace('%28', '(').
						replace('%29', ')').
						replace('/', '%2F').
						replace('+', '%2B').
						replace('%27', "'").
						replace('%7E', "~");
				};
				logImportant.call(this, '"encodeURIComponent" function NOT found,' +
					'this was fixed but ONLY for ASCII characters 0 to 127 (included)');
			}
		}

		function findGetElementById() {
			// :note: for IE bug see:
			// http://www.sixteensmallstones.org/ie-javascript-bugs-overriding-internet-explorers-documentgetelementbyid-to-be-w3c-compliant-exposes-an-additional-bug-in-getattributes
			try {
				if (isDefined(document)) {
					if (document.getElementById) { // standard getElementById is supported
						if (IS_NAME_BUG) { // but IE and Opera both have terrible NAME & ID bug, so we must override it
							// the bug is, that IE matches NAMES as IDs, which can be very wrong and must be fixed
							myGetElementById = function (elementName) {
								var el;
								var i;
								el  = document.getElementById(elementName); // fist, we use "standard" implementation to find something
								if (el) { // if we are successful, we must do some test, if what we found is what we want
									if(IS_IE) {
									// :note: IE has also .getAttribute bug, so we must access through .getAttributeNode('id').value !!!
										if (el.attributes['id'].value == elementName) { // we check, if attribute ID matches
											return el; // if matches, return element
										} else { // otherwise we must cycle throught document.all[elementName]
											for (i = 1; i < document.all[elementName].length; i++) { // to find the correct element
												if (document.all[elementName][i].attributes['id'].value == elementName) {
													return document.all[elementName][i];
												}
											}
										}
									} else { // this apply to Opera (ant possibly other browsers)
										if (el.getAttribute('id') === elementName) {
											return el; // if matches, return element
										} else { //otherwise we must cycle throught document.all[elementName]
											for (i = 1; i < document.all[elementName].length; i++) { // to find the correct element
												// for IE
												if (document.all[elementName][i].getAttribute('id') === elementName) {
													return document.all[elementName][i];
												}
											}
										}
									}
								}
								return null;
							};
							throw 'namebug_fix';
						} else { // otherwise we use standard
							myGetElementById = function (elementName) {
								return document.getElementById(elementName);
							}
							throw 'standard';
						}
					} else if (document.all) {
						myGetElementById = function (elementName) {
							return document.all[elementName] ? document.all[elementName] : null;
						};
						throw 'ie';
					} else if (document.layers) {
						myGetElementById = function (elementName) {

							function findElementThroughLayers(elementName, o) {
								var found;
								var i;

								if (o.layers[elementName]) {
									return o.layers[elementName];
								} else {
									found = null;
									for (i = 0; i < o.layers.length; i++) {
										found = findElementThroughLayers(elementName, o.layers[i].document);
										if (found) {
											return found;
										}
									}
									return found;
								}
							}

							return findElementThroughLayers(elementName, document);
						};
						throw 'ns';
					} else {
						throw 'none';
					}
				}
			} catch (e) {
				if (e === 'none') {
					myGetElementById = function () {
						return null;
					};
					e = '';
				} else if (e === 'ie') {
					e = 'document.all';
				} else if (e === 'namebug_fix') {
					e = 'document.getElementById (with name bug fix)';
				} else if (e === 'standard') {
					e = 'document.getElementById';
				} else if (e === 'ns') {
					e = 'document.layers';
				}
				if (typeof e === 'string') {
					if (e === '') {
						logMessage.call(this, 'cannot find function for getting element by ID');
					} else {
						logMessage.call(this, 'using "' + e + '" for getting element by ID');
					}
				} else {
					logFatal.call(this, e);
				}
			}
		}

		function findNavigatorInformation() {
			try {
				if (navigator) {
					if (navigator.userAgent) {
						logMessage.call(this, '"navigator.userAgent" ' + navigator.userAgent);
					}
					if (navigator.appVersion) {
						logMessage.call(this, '"navigator.appVersion" ' + navigator.appVersion);
					}
				}
			} catch (e) {
				// on error do nothing
			}
		}

		function loadUserIni(fileName) {
		// load user ini file, if exists
			var evalStatus;
			var userIni;
			userIni = getFile(fileName);
			if (isString(userIni)) {
				logMessage.call(this, 'user initialization file "' + fileName + '" found, parsing...');
				evalStatus = safeEval(userIni);
				if (evalStatus === true) {
					logMessage.call(this, 'user initialization file parsing completed');
				} else {
					logError.call(this, 'user initialization file parsing error', evalStatus);
					debugOn(); // on error auto activate debug
				}
			}
		}

		function testArgumentsObject() {
			IS_ARGUMENTS_OBJECT = !isArray(arguments) && isObject(arguments) ? true : false;
			logMessage.call(this, 'fix for argument object ' + (IS_ARGUMENTS_OBJECT ?
				'is neccessary, remember to always use "fixArguments"' : 'is "not needed"'));
		}

		function testNameBug() {
			var el;
			var store;

			IS_NAME_BUG = false;
			if(IS_IE) { // can I assume this more safely ???
				IS_NAME_BUG = true;
			} else if (domDocumentBody !== null) {
				if(domDocumentBody.setAttribute) {
				store = domDocumentBody.getAttribute('name'); // store original name
					domDocumentBody.setAttribute('name', NAME + 'testNameBug'); // set test name
				} else {
					store = domDocumentBody['name']; // store original name
					domDocumentBody['name'] = NAME + 'testNameBug';
				}
				el = document.getElementById(NAME + 'testNameBug'); // find document by test name
				if (el === domDocumentBody) { // if found
					IS_NAME_BUG = true; // there is name bug here
				}
				if(domDocumentBody.setAttribute) {
					domDocumentBody.setAttribute('name', store); // restore original name
				} else {
					domDocumentBody['name'] = store; // restore original name
				}
			}
			logMessage.call(this, 'this browser "' + (IS_NAME_BUG ? '*HAS*' : 'has not') + ' getElementById" name bug');
		}

		function testInternetExplorer() {
			// :note: this test is based on fact, that Internet Explorer is the only browser, which has FILTERS,
			//        so testing for their presence should be simple and safe way to recognize IE
			IS_IE = document && document.body &&
				(typeof document.body.filters === 'object') ?
				true : false;
			logMessage.call(this, 'detected browser "is ' + (IS_IE ? '' : ' *NOT*') + '" Internet Explorer');
		}

		function testNetscape() {
			// :note: this test is based on fact, that old Netscape used document.layers
			IS_NETSCAPE = document && document.layers ? true : false;
			logMessage.call(this, 'detected browser "is ' + (IS_NETSCAPE ? '' : ' *NOT*') + '" old Netscape');
		}

		try {

			// test DOM level 1 support
			DOM_LEVEL_1 = document && document.getElementById && document.getElementsByTagName ? true : false;

			// test DOM level 2 support
			DOM_LEVEL_2 = DOM_LEVEL_1 && document.createElement ? true : false;

			// try to recognize and log navigator information
			findNavigatorInformation();

			// test for old Netscape browser
			testNetscape();

			// test for Internet Explorer
			testInternetExplorer();

			// test for Internet Explorer style arguments
			testArgumentsObject();

			// find root DOM document element
			findDocumentRoot();

			// find DOM document body element
			findDocumentBody();

			// test for getElementById name bug
			testNameBug();

			// find getElementById or alternative
			findGetElementById();

			// decide, wheather 'px' are used when setting size values in CSS
			PX = document && document.childNodes ? 'px' : 0;

			// initialize XML HTTP Request
			IS_XMLHTTP = setupXmlHttpRequest();

			if (IS_XMLHTTP === null) {
				throw new Error('Unexpected initialization error');
			}

			init = DOM_LEVEL_2 && IS_XMLHTTP ? true : false;

			if (init === false) {
				throw new Error('Initialization was not successful');
			} else {
				logMessage.call(self, 'Initialization successful');
			}

			// test and repair support for encodeURI
			findEncodeURI();

			// test and repair support for encodeURIComponent
			findEncodeURIComponent();

			// load and parse user ini file, if available
            loadUserIni(userIniFile);

		} catch (e) {
			// basic object parser
			function parseObject(o) {
				var i;
				var s = '';
				if (typeof o === 'object') {
					for (i in o) if ((typeof o.hasOwnProperty !== 'function') || o.hasOwnProperty(i)) {
						if (o[i] === null) {
							s += i + ': null\n';
						} else if (typeof o[i] === 'number') {
							s += i + ': Number ' + o[i] + '\n';
						} else if (typeof o[i] === 'string') {
							s += i + ': String "' + o[i] + '"\n';
						} else {
							s += i + ': ' + (typeof o[i]) + '\n';
						}
					}
				}
				return s === '' ? '-- empty --': s;
			}

			function parseSystemLog() {
				var i;
				var o;
				var s = '';
				for (i = 0; i < sysLog.length; i++) {
					o = sysLog[i];
					s += o.creationDate + ' ' + o.creationTime + ' ' + o.callerFunction + '\n' +
						o.errorLevel + ' ' + o.errorMessage + (typeof o.errorData === 'undefined' ? '' : '\n' +
						(typeof o.errorData === 'object' ? String(o.errorData) + '\n' + parseObject(o.errorData) : o.errorData)) +
						'\n\n';
				}
				return s;
			}

			// log last error
			logFatal.call(this, e);
			// parse and display system log
			alert(parseSystemLog());

		}
	};

	// ----- CLASSES -----

	function Module(moduleName, onSuccess, onFailure, onChange, silentMode) {
	// class loads and compiles module file

		// ----- Module PRIVATE PROPERTIES -----

		var ARGS; // holds initial 'arguments' object
		var NAME = 'Module';
		var asynchronous;
		var caller;
		var evalStatus;
		var fullpath;
		var name;
		var reporting;
		var request;
		var response;
		var self = this;

		// ----- Module PRIVATE METHODS -----

		function makeModule() {
		// make module from response
			try {
				if (!isDefined(request)) { // this is hack for IE being too slow
					window.setTimeout(makeModule, 25); // if result is not ready yet, wait another 25 miliseconds
					return;
				}
				response = request.get();
				if (reporting) {
					logMessage.call(caller, name + ' file obtained, parsing...');
				}
				evalStatus = safeEval('modules.' + moduleName + ' = new ' +
                    response.response + '();');
				if (evalStatus === true) {
					if (reporting) {
						logMessage.call(caller, name + ' file parsing completed');
					}
					if (isFunction(onSuccess)) {
						if (reporting) {
							logMessage.call(caller, name + ' calling user function...');
						}
                        try {
                            onSuccess(response);
						} catch (e) {
                            logImportant.call(caller, name + ' user function crashed');
                        }
						if (reporting) {
							logMessage.call(caller, name + ' user function finished');
						}
					}
				} else {
					if (reporting) {
						logError.call(caller, name + ' parsing failed', evalStatus);
					}
					makeModuleError();
				}
				if (asynchronous && reporting) {
					logMessage.call(caller, name + ' loading finished');
				}
			} catch (e) {
				logFatal.call(caller, e);
			}
		}

		function makeModuleError() {
		// if response is bad or module make failed
			if (isFunction(onFailure)) {
				response = request.get();
				if (reporting) {
					logMessage.call(caller, name + ' calling user function...');
				}
                try {
				    onFailure(response);
                } catch (e) {
                    logImportant.call(caller, name + ' user function crashed', e);
                }
				if (reporting) {
					logMessage.call(caller, name + ' user function finished');
				}
			}
		}

		// ----- Module INITIALIZATION -----

		ARGS = fixArguments(arguments);

		// ----- Module CONSTRUCTOR -----

		return function () {
			try {
				caller = this;
				reporting = silentMode ? false : true;
				checkArguments(ARGS, 1, 'Sfffb');
				name = 'module "' + moduleName + '"';
				asynchronous = isFunction(onSuccess) ? true : false;
				fullpath = clientPath + moduleName + '.js';
				if (reporting) {
					logMessage.call(this, 'loading ' + name);
				}
				if (asynchronous) {
					request = new XmlHttp(fullpath, 'get', null, makeModule, makeModuleError, onChange, silentMode);
				} else {
					request = new XmlHttp(fullpath, 'get', null, null, null, null, silentMode);
					if (response === null) {
						makeModuleError();
					} else {
						makeModule();
					}
				}
			} catch (e) {
				logFatal.call(this, e);
			}
			if (!asynchronous && reporting) {
				logMessage.call(this, name + ' loading finished');
			}
		}();

	}

	function Vector() {
	// class for multi-dimensional vector operations

		// ----- Vector PRIVATE CONSTANTS -----

		var ARGS; // holds initial 'arguments' object
		var NAME = 'Vector';

		// ----- Vector PRIVATE PROPERTIES -----

		var self = this;
		var values;
        var vectorSize;

		// ----- Vector PUBLIC METHODS -----

		this.addScalar = function (scalarValue) {
		// add scalar value to each member of vector
			var i;

			for (i = 0; i < vectorSize; i++) {
				values[i] += scalarValue;
			}
		};

		this.addValue = function (v, n) {
		// add value inside vector
			checkArguments(arguments, 2, 'Pn');
			if (v >= vectorSize) {
				logImportant.call(this, NAME + ': "addValue" out of range',
					new RangeError('value must be within 0 and ' + vectorSize + ' included'));
			} else {
				values[v] += n;
			}
		};

        this.addVector = function (vector) {
        // executes vector plus on current vector
            var i; // iterator

            if (vector instanceof Vector) {
                if (vectorSize === vector.getSize()) {
                    for (i = 0; i < vectorSize; i++) {
                        self.addValue(i, vector.getValue(i));
                    }
                } else {
                    logImportant.call(this, NAME + ': "addVector" is expecting vector of the same size, given vector: ' + vector.toString());
                }
                return self;
            } else {
                logImportant.call(this, NAME + ': "addVector" is expecting vector',
                    new TypeError('unsupported type "' + typeOf(vector) + '"'));
                return self;
            }
        };

        this.getSize = function () {
        // return size of vector
            return vectorSize;
        };

		this.getVector = function () {
		// returns array with values
			return values;
		};

		this.getValue = function (v) {
			return values[v];
		};

		this.setValue = function (v, n) {
		// set value inside vector
			checkArguments(arguments, 2, 'Pn');
			if (v >= vectorSize) {
				logImportant.call(this, NAME + ': "addValue" out of range',
					new RangeError('value must be within 0 and ' + vectorSize + ' included')
				);
			} else {
				values[v] = n;
			}
		};

		this.toScalar = function () {
		// convert vector to scalar value
			var i;
			var v;

			v = 0;
			for (i = 0; i < vectorSize; i++) {
				v += values[i] * values[i];
			}
			return Math.sqrt(v);
		};

		this.toString = function () {
			return '[' + values.join(', ') + ']';
		};

		// ----- Vector INITIALIZATION -----

		ARGS = fixArguments(arguments);

		// ----- Vector CONSTRUCTOR -----

		return function () {
			var i;

			if (ARGS.length < 2) {
				throw new Error(NAME + ': expecting two or more arguments');
			}
			values = [];
            vectorSize = ARGS.length;
			for (i = 0; i < vectorSize; i++) {
				if (isNumber(ARGS[i])) {
					values[i] = ARGS[i];
				} else {
					throw new TypeError(NAME + ': arguments must be numbers\n' +
						'argument #' + i + ' type: ' + typeOf(ARGS[i]) + '" given' +
						(isValue(typeOf(ARGS[i])) ? ' with value: "' + String(ARGS[i]) + '"' : '')
					);
				}
			}
		}();

	}

	function XmlHttp(requestURI, requestMethod, postData, onSuccess, onFailure, onChange, silentMode) {
	// create and register new xmlHttp request
	// - requestURI is string URI where request is send to
	// - requestMethod string defines type of method request is made and can be:
	// --- 'get' for GET method
	// --- 'post' for POST method, where postData are variables in GET format (e.g. 'a=5&b=10')
	// --- 'rawpost' for POST method, where postData are raw data (e.g. content of file)
	// - postData are used only with POST method and contain data posted with request
	// - onSuccess can be undefined, null, or function and defines, whether request is synchronous or asynchronous
	// --- if undefined or null, synchronous request is made and control flow continues
	// --- if function, asynchronous request is made and control flow is passed to onSuccess function
	// - onFailure can be undefined, null, or function and defines behaviour on request failure
	// --- if undefined or null, control flow continues normally
	// --- if function, this function is called after finishing the request with requestObject (see below) as parameter
	// - onChange can be undefined, null, or function and defines behaviour when request status changes
	// --- if undefined or null, nothing happens, this is standard behaviour
	// --- if function, this function is called on each request change with requestObject as parameter
	// - if ignoreErrors is true, no errors except critical are logged, this is useful when testing if file exists
	// - requestObject is returned by this.get() method and has following properties:
	// --- data - request data passed to XmlHttp method
	// --- method - request method passed to XmlHttp method
	// --- name - internal request name
	// --- request - xmlHttpRequest object
	// --- response - server response string or null if failed
	// --- retries - number of retries, 0 means first attempt, -1 means initialization error
	// --- uri - request URI passed to XmlHttp method

		// ----- XmlHttp PRIVATE PROPERTIES -----

		var ARGS; // holds initial 'arguments' object
		var NAME = 'XmlHttp';
		var asynchronous;
		var caller;
		var data;
		var id;
		var method;
		var name;
		var reporting;
		var response;
		var request;
		var retries = -1;
		var self = this;
		var status;

		// ----- XmlHttp PUBLIC METHODS -----

		this.abort = function () {
		// method aborts current request
			try {
				request.abort();
				if (reporting) {
					logMessage.call(this, name + ' abort successful.');
				}
				return true;
			} catch (e) {
				if (reporting) {
					logImportant.call(this, name + ' abort failed.', e);
				}
				return false;
			}
		};

		this.get = function () {
		// build and return requestObject
			return {
				data: data,
				method: requestMethod,
				name: name,
				request: request,
				response: response,
				retries: retries,
				uri: requestURI
			};
		};

		this.retry = function () {
		// executes request attemp
			retries++;
			request = myXmlHttpRequest();
			request.open(requestMethod === 'get' ? 'GET' : 'POST', requestURI, asynchronous);
			if (requestMethod === 'post') {
				request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			}
			if (asynchronous) {
				request.onreadystatechange = handleAsynchronous;
				if (reporting) {
					logMessage.call(this, 'asynchronous ' + name + ' at URI "' + requestURI + '" started');
				}
				request.send(requestMethod === 'get' ? null : data);
			} else {
				if (reporting) {
					logMessage.call(this, 'synchronous ' + name + ' at URI "' + requestURI + '" started');
				}
				request.send(requestMethod === 'get' ? null : data);
				handleResult();
			}
		};

		this.toString = function () {
			return NAME;
		};

		// ----- XmlHttp PRIVATE METHODS -----

		function handleAsynchronous() {
		// handles asynchronous request managing server response
			status = request.readyState;
            if (isFunction(onChange)) {
                if (reporting) {
                    logMessage.call(caller, name + ' at URI "' + requestURI + '" calling user function...');
                }
                try {
                    onChange(self.get());
                } catch (e) {
                    logImportant.call(caller, name + ' at URI "' + requestURI + '" user function crashed', e);
                }
                if (reporting) {
                    logMessage.call(caller, name + ' at URI "' + requestURI + '" user function finished');
                }
            }
			if (status === 2) {
				if (reporting) {
					logMessage.call(caller, name + ' at URI "' + requestURI + '" loaded, waiting to be "interactive"');
				}
			} else if (status === 3) {
				if (reporting) {
					logMessage.call(caller, name + ' at URI "' + requestURI + '" interactive, waiting to be "completed"');
				}
			} else if (status === 4) {
				handleResult();
			}
		}

		function handleResult() {
		// handles final result according to server response
			status = request.status;
			if (((status >= 200) && (status < 300)) || (status === 304)) {
				if (reporting && (status === 304)) {
					logWarning.call(caller, name + ' at URI "' + requestURI + '"', status);
				}
				response = request.responseText;
				if (reporting) {
					logMessage.call(caller, name + ' at URI "' + requestURI + '" completed with status: "' + status + '"');
				}
				if (isFunction(onSuccess)) {
                    if (reporting) {
                        logMessage.call(caller, name + ' at URI "' + requestURI + '" calling user function...');
                    }
					try {
                        onSuccess(self.get());
                    } catch (e) {
                        logImportant.call(caller, name + ' at URI "' + requestURI + '" user function crashed', e);
                    }
					if (reporting) {
						logMessage.call(caller, name + ' at URI "' + requestURI + '" user function finished');
					}
				}
			} else {
				response = null;
				if (reporting) {
					logError.call(caller, name + ' at URI "' + requestURI + '" failed', status);
				}
				if (isFunction(onFailure)) {
                    if (reporting) {
                        logMessage.call(caller, name + ' at URI "' + requestURI + '" calling user function...');
                    }
					try {
                        onFailure(self.get());
                    } catch (e) {
                        logImportant.call(caller, name + ' at URI "' + requestURI + '" user function crashed', e);
                    }
					if (reporting) {
						logMessage.call(caller, name + ' at URI "' + requestURI + '" user function finished');
					}
				}
			}
		}

		// ----- XmlHttp INITIALIZATION -----

		ARGS = fixArguments(arguments);

		// ----- XmlHttp CONSTRUCTOR -----

		return function () {
			try {
				caller = this;
				if (typeof self.constructor.requestId === 'undefined') {
					self.constructor.requestId = 0;
				}
				checkArguments(ARGS, 2, 'SSSfffb');
				if ((requestMethod !== 'get') && (requestMethod !== 'post') && (requestMethod !== 'rawpost')) {
					throw new Error('bad method');
				}
				id = self.constructor.requestId++;
				name = 'request "#' + id + '"';
				response = null;
				data = postData;
				status = -1;
				reporting = silentMode === true ? false : true;
				asynchronous = isFunction(onSuccess) ? true : false;
				self.retry.call(this);
			} catch (e) {
				if (e === 'bad method') {
					if (reporting) {
						logError.call(this, 'invalid method: "' + requestMethod + '"', e);
					}
					request = null;
				} else {
					request = logFatal.call(this, e);
				}
			}
		}();

	}

	// ----- PREDEFINED METHODS -----

	function setupXmlHttpRequest() {
	// check for available xmlHttpRequest method
	// - on success returns true and sets myXmlHttpRequest property as pointer to available method
	// - on failure returns false, i.e. no known method is found, myXmlHttpRequest is null
		try { // silently test request availability
			// test standard request first
			if (xmlHttpXMLHttpRequest(true) !== null) { // if available
				throw xmlHttpXMLHttpRequest; // throw the bone to catch
			}
			// test microsoft ActiveXObject Msxml2.XMLHTTP.4.0
			if (xmlHttpMsxml2XMLHTTP40(true) !== null) {
				throw xmlHttpMsxml2XMLHTTP40;
			}
			// test microsoft ActiveXObject Msxml2.XMLHTTP
			if (xmlHttpMsxml2XMLHTTP(true) !== null) {
				throw xmlHttpMsxml2XMLHTTP;
			}
			// test microsoft ActiveXObject Microsoft.XMLHTTP
			if (xmlHttpMicrosoftXMLHTTP(true) !== null) {
				throw xmlHttpMicrosoftXMLHTTP;
			}
			throw 'none';
		} catch (e) {
			if (e === 'none') { // if no suitable function found
				return false;
			} else if (isFunction(e)) { // if we found, what we need, store it and return true
				myXmlHttpRequest = e;
				return true;
			} else {
				logFailure.call(this, 'setupXmlHttpRequest', e); // reset this result to null
				return null;
			}
		}
	}

	function xmlHttpXMLHttpRequest(silent) {
	// -- standard XMLHTTP request
		try {
			return new XMLHttpRequest();
		} catch (e) {
			return silent ? null : logFailure.call(this, 'xmlHttpXMLHttpRequest', e);
		}
	}

	function xmlHttpMicrosoftXMLHTTP(silent) {
	// -- microsoft XMLHTTP
		try {
			return new ActiveXObject('Microsoft.XMLHTTP');
		} catch (e) {
			return silent ? null : logFailure.call(this, 'xmlHttpMicrosoftXMLHTTP', e);
		}
	}

	function xmlHttpMsxml2XMLHTTP(silent) {
	// -- microsoft XMLHTTP 3.0
		try {
			return new ActiveXObject('Msxml2.XMLHTTP');
		} catch (e) {
			return silent ? null : logFailure.call(this, 'xmlHttpMsxml2XMLHTTP', e);
		}
	}

	function xmlHttpMsxml2XMLHTTP40(silent) {
	// -- microsoft XMLHTTP 4.0
		try {
			return new ActiveXObject('Msxml2.XMLHTTP.4.0');
		} catch (e) {
			return silent ? null : logFailure.call(this, 'xmlHttpMsxml2XMLHTTP40', e);
		}
	}

	// ----- CONSTRUCTOR -----

	return function () {
		debugMode = false;
		domDocumentBody = null;
		domDocumentRoot = document;
		init = false;
		loggingDisabled = false;
		loggingLevel = ERR_MESSAGE; // setup logging level
		modules = {}; // reset modules object
		falseFunction = function () { // setup null function
			return false;
		};
		nullFunction = function () { // setup null function
			return null;
		};
		voidFunction = function () {}; // setup void function
		sessionStartTime = getTimeStamp(); // setup new session
		sysLog = []; // reset system log
		sysLogEventCall = voidFunction; // by default, no function is called

        // if default configuration is not given in IQdevConfig, generate empty config object
        config = (typeof IQdevConfig === 'undefined') || !isObject(IQdevConfig) ? {} : IQdevConfig;
        // setup client path
        clientPath = isString(config['clientPath']) ?
            config['clientPath'] : '_iqdev-js-engine/';
        // setup server script path
        serverPath = isString(config['serverPath']) ?
            config['serverPath'] : '_iqdev-php-engine/';
        // setup server script extension
        serverExtension = isString(config['serverExtension']) ?
            config['serverExtension'] : '.php';
        // setup userIniFile
        userIniFile = isString(config['userIniFile']) ?
            config['userIniFile'] : 'iqdevini.js';

		// register useful constants with String object
		String.NBSP=String('\u00A0');
		String.BULLET=String('\u2022');
		String.COPYRIGHT=String('\u00A9');
		String.CROSS=String('\u2020');
		String.CUBIC=String('\u00B3');
		String.DBL_CROSS=String('\u2021');
		String.DBL_GT=String('\u00BB');
		String.DBL_LT=String('\u00AB');
		String.DIVIDE=String('\u00F7');
		String.DOT=String('\u2219');
		String.DOTX=String('\u00A4');
		String.INF=String('\u221E');
		String.MICRO=String('\u00B5');
		String.PER_MILLE=String('\u2030');
		String.REGISTERED=String('\u00AE');
		String.SQUARED=String('\u00B2');
		String.THREE_DOTS=String('\u2026');
		String.CEDILLA=String('\u00B8');
	}();

}();