1 /* Licensed to the Apache Software Foundation (ASF) under one or more
  2  * contributor license agreements.  See the NOTICE file distributed with
  3  * this work for additional information regarding copyright ownership.
  4  * The ASF licenses this file to you under the Apache License, Version 2.0
  5  * (the "License"); you may not use this file except in compliance with
  6  * the License.  You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 /*
 17  theoretically we could save some code
 18  by
 19  defining the parent object as
 20  var parent = new Object();
 21  parent.prototype = new myfaces._impl.core._Runtime();
 22  extendClass(function () {
 23  }, parent , {
 24  But for now we are not doing it the little bit of saved
 25  space is not worth the loss of readability
 26  */
 27 /**
 28  * @memberOf myfaces._impl
 29  * @namespace
 30  * @name _util
 31  */
 32 /**
 33  * @class
 34  * @name _Lang
 35  * @memberOf myfaces._impl._util
 36  * @extends myfaces._impl.core._Runtime
 37  * @namespace
 38  * @description Object singleton for Language related methods, this object singleton
 39  * decorates the namespace myfaces._impl.core._Runtime and adds a bunch of new methods to
 40  * what _Runtime provided
 41  * */
 42 _MF_SINGLTN(_PFX_UTIL + "_Lang", Object, /** @lends myfaces._impl._util._Lang.prototype */ {
 43     _processedExceptions:{},
 44     _installedLocale:null,
 45     _RT:myfaces._impl.core._Runtime,
 46     /**
 47      * returns a given localized message upon a given key
 48      * basic java log like templating functionality is included
 49      *
 50      * @param {String} key the key for the message
 51      * @param {String} defaultMessage optional default message if none was found
 52      *
 53      * Additionally you can pass additional arguments, which are used
 54      * in the same way java log templates use the params
 55      *
 56      * @param key
 57      */
 58     getMessage:function (key, defaultMessage /*,vararg templateParams*/) {
 59         if (!this._installedLocale) {
 60             //we first try to install language and variant, if that one fails
 61             //we try to install the language only, and if that one fails
 62             //we install the base messages
 63             this.initLocale();
 64         }
 65         var msg = this._installedLocale[key] || defaultMessage || key + " - undefined message";
 66         //we now make a simple templating replace of {0}, {1} etc... with their corresponding
 67         //arguments
 68         for (var cnt = 2; cnt < arguments.length; cnt++) {
 69             msg = msg.replace(new RegExp(["\\{", cnt - 2, "\\}"].join(""), "g"), new String(arguments[cnt]));
 70         }
 71         return msg;
 72     },
 73     /**
 74      * (re)inits the currently installed
 75      * messages so that after loading the main scripts
 76      * a new locale can be installed optionally
 77      * to our i18n subsystem
 78      *
 79      * @param newLocale locale override
 80      */
 81     initLocale:function (newLocale) {
 82         if (newLocale) {
 83             this._installedLocale = new newLocale();
 84             return;
 85         }
 86         var language_Variant = this._RT.getLanguage(this._RT.getGlobalConfig("locale")),
 87                 langStr = language_Variant ? language_Variant.language : "",
 88                 variantStr = language_Variant ? [language_Variant.language, "_", language_Variant.variant || ""].join("") : "",
 89                 i18nRoot = myfaces._impl.i18n, i18nHolder = i18nRoot["Messages_" + variantStr] || i18nRoot["Messages_" + langStr] || i18nRoot["Messages"];
 90         this._installedLocale = new i18nHolder();
 91     },
 92     assertType:function (probe, theType) {
 93         return this._RT.assertType(probe, theType);
 94     },
 95     exists:function (nms, theType) {
 96         return this._RT.exists(nms, theType);
 97     },
 98     fetchNamespace:function (namespace) {
 99         this._assertStr(namespace, "fetchNamespace", "namespace");
100         return this._RT.fetchNamespace(namespace);
101     },
102     reserveNamespace:function (namespace) {
103         this._assertStr(namespace, "reserveNamespace", "namespace");
104         return this._RT.reserveNamespace(namespace);
105     },
106     globalEval:function (code) {
107         this._assertStr(code, "globalEval", "code");
108         return  this._RT.globalEval(code);
109     },
110     /**
111      * determines the correct event depending
112      * on the browsers state
113      *
114      * @param evt incoming event object (note not all browsers
115      * have this)
116      *
117      * @return an event object no matter what is incoming
118      */
119     getEvent:function (evt) {
120         evt = (!evt) ? window.event || {} : evt;
121         return evt;
122     },
123     /**
124      * cross port from the dojo lib
125      * browser save event resolution
126      * @param evt the event object
127      * (with a fallback for ie events if none is present)
128      */
129     getEventTarget:function (evt) {
130         //ie6 and 7 fallback
131         evt = this.getEvent(evt);
132         /**
133          * evt source is defined in the jsf events
134          * seems like some component authors use our code
135          * so we add it here see also
136          * https://issues.apache.org/jira/browse/MYFACES-2458
137          * not entirely a bug but makes sense to add this
138          * behavior. I dont use it that way but nevertheless it
139          * does not break anything so why not
140          * */
141         var t = evt.srcElement || evt.target || evt.source || null;
142         while ((t) && (t.nodeType != 1)) {
143             t = t.parentNode;
144         }
145         return t;
146     },
147 
148     /**
149      * equalsIgnoreCase, case insensitive comparison of two strings
150      *
151      * @param source
152      * @param destination
153      */
154     equalsIgnoreCase:function (source, destination) {
155         //either both are not set or null
156         if (!source && !destination) {
157             return true;
158         }
159         //source or dest is set while the other is not
160         if (!source || !destination) return false;
161         //in any other case we do a strong string comparison
162         return source.toLowerCase() === destination.toLowerCase();
163     },
164 
165     /**
166      * Save document.getElementById (this code was ported over from dojo)
167      * the idea is that either a string or domNode can be passed
168      * @param {Object} reference the reference which has to be byIded
169      */
170     byId:function (/*object*/ reference) {
171         if (!reference) {
172             throw this.makeException(new Error(), null, null, this._nameSpace, "byId", this.getMessage("ERR_REF_OR_ID", null, "_Lang.byId", "reference"));
173         }
174         return (this.isString(reference)) ? document.getElementById(reference) : reference;
175     },
176 
177     /**
178      * String to array function performs a string to array transformation
179      * @param {String} it the string which has to be changed into an array
180      * @param {RegExp} splitter our splitter reglar expression
181      * @return an array of the splitted string
182      */
183     strToArray:function (/*string*/ it, /*regexp*/ splitter) {
184         //	summary:
185         //		Return true if it is a String
186         this._assertStr(it, "strToArray", "it");
187         if (!splitter) {
188             throw this.makeException(new Error(), null, null, this._nameSpace, "strToArray", this.getMessage("ERR_PARAM_STR_RE", null, "myfaces._impl._util._Lang.strToArray", "splitter"));
189         }
190         var retArr = it.split(splitter);
191         var len = retArr.length;
192         for (var cnt = 0; cnt < len; cnt++) {
193             retArr[cnt] = this.trim(retArr[cnt]);
194         }
195         return retArr;
196     },
197     _assertStr:function (it, functionName, paramName) {
198         if (!this.isString(it)) {
199             throw this.makeException(new Error(), null, null, this._nameSpace, arguments.caller.toString(), this.getMessage("ERR_PARAM_STR", null, "myfaces._impl._util._Lang." + functionName, paramName));
200         }
201     },
202     /**
203      * hyperfast trim
204      * http://blog.stevenlevithan.com/archives/faster-trim-javascript
205      * crossported from dojo
206      */
207     trim:function (/*string*/ str) {
208         this._assertStr(str, "trim", "str");
209         str = str.replace(/^\s\s*/, '');
210         var ws = /\s/, i = str.length;
211 
212         while (ws.test(str.charAt(--i))) {
213             //do nothing
214         }
215         return str.slice(0, i + 1);
216     },
217     /**
218      * Backported from dojo
219      * a failsafe string determination method
220      * (since in javascript String != "" typeof alone fails!)
221      * @param it {|Object|} the object to be checked for being a string
222      * @return true in case of being a string false otherwise
223      */
224     isString:function (/*anything*/ it) {
225         //	summary:
226         //		Return true if it is a String
227         return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
228     },
229     /**
230      * hitch backported from dojo
231      * hitch allows to assign a function to a dedicated scope
232      * this is helpful in situations when function reassignments
233      * can happen
234      * (notably happens often in lazy xhr code)
235      *
236      * @param {Function} scope of the function to be executed in
237      * @param {Function} method to be executed, the method must be of type function
238      *
239      * @return whatever the executed method returns
240      */
241     hitch:function (scope, method) {
242         return !scope ? method : function () {
243             return method.apply(scope, arguments || []);
244         }; // Function
245     },
246     /**
247      * Helper function to merge two maps
248      * into one
249      * @param {Object} dest the destination map
250      * @param {Object} src the source map
251      * @param {boolean} overwrite if set to true the destination is overwritten if the keys exist in both maps
252      **/
253     mixMaps:function (dest, src, overwrite, blockFilter, whitelistFilter) {
254         if (!dest || !src) {
255             throw this.makeException(new Error(), null, null, this._nameSpace, "mixMaps", this.getMessage("ERR_PARAM_MIXMAPS", null, "_Lang.mixMaps"));
256         }
257         var _undef = "undefined";
258         for (var key in src) {
259             if (!src.hasOwnProperty(key)) continue;
260             if (blockFilter && blockFilter[key]) {
261                 continue;
262             }
263             if (whitelistFilter && !whitelistFilter[key]) {
264                 continue;
265             }
266             if (!overwrite) {
267                 /**
268                  *we use exists instead of booleans because we cannot rely
269                  *on all values being non boolean, we would need an elvis
270                  *operator in javascript to shorten this :-(
271                  */
272                 dest[key] = (_undef != typeof dest[key]) ? dest[key] : src[key];
273             } else {
274                 dest[key] = (_undef != typeof src[key]) ? src[key] : dest[key];
275             }
276         }
277         return dest;
278     },
279     /**
280      * checks if an array contains an element
281      * @param {Array} arr   array
282      * @param {String} str string to check for
283      */
284     contains:function (arr, str) {
285         if (!arr || !str) {
286             throw this.makeException(new Error(), null, null, this._nameSpace, "contains", this.getMessage("ERR_MUST_BE_PROVIDED", null, "_Lang.contains", "arr {array}", "str {string}"));
287         }
288         return this.arrIndexOf(arr, str) != -1;
289     },
290     arrToMap:function (arr, offset) {
291         var ret = new Array(arr.length);
292         var len = arr.length;
293         offset = (offset) ? offset : 0;
294         for (var cnt = 0; cnt < len; cnt++) {
295             ret[arr[cnt]] = cnt + offset;
296         }
297         return ret;
298     },
299     objToArray:function (obj, offset, pack) {
300         if (!obj) {
301             return null;
302         }
303         //since offset is numeric we cannot use the shortcut due to 0 being false
304         //special condition array delivered no offset no pack
305         if (obj instanceof Array && !offset && !pack)  return obj;
306         var finalOffset = ('undefined' != typeof offset || null != offset) ? offset : 0;
307         var finalPack = pack || [];
308         try {
309             return finalPack.concat(Array.prototype.slice.call(obj, finalOffset));
310         } catch (e) {
311             //ie8 (again as only browser) delivers for css 3 selectors a non convertible object
312             //we have to do it the hard way
313             //ie8 seems generally a little bit strange in its behavior some
314             //objects break the function is everything methodology of javascript
315             //and do not implement apply call, or are pseudo arrays which cannot
316             //be sliced
317             for (var cnt = finalOffset; cnt < obj.length; cnt++) {
318                 finalPack.push(obj[cnt]);
319             }
320             return finalPack;
321         }
322     },
323     /**
324      * foreach implementation utilizing the
325      * ECMAScript wherever possible
326      * with added functionality
327      *
328      * @param arr the array to filter
329      * @param func the closure to apply the function to, with the syntax defined by the ecmascript functionality
330      * function (element<,key, array>)
331      * <p />
332      * optional params
333      * <p />
334      * <ul>
335      *      <li>param startPos (optional) the starting position </li>
336      *      <li>param scope (optional) the scope to apply the closure to  </li>
337      * </ul>
338      */
339     arrForEach:function (arr, func /*startPos, scope*/) {
340         if (!arr || !arr.length) return;
341         var startPos = Number(arguments[2]) || 0;
342         var thisObj = arguments[3];
343         //check for an existing foreach mapping on array prototypes
344         //IE9 still does not pass array objects as result for dom ops
345         arr = this.objToArray(arr);
346         (startPos) ? arr.slice(startPos).forEach(func, thisObj) : arr.forEach(func, thisObj);
347     },
348     /**
349      * foreach implementation utilizing the
350      * ECMAScript wherever possible
351      * with added functionality
352      *
353      * @param arr the array to filter
354      * @param func the closure to apply the function to, with the syntax defined by the ecmascript functionality
355      * function (element<,key, array>)
356      * <p />
357      * additional params
358      * <ul>
359      *  <li> startPos (optional) the starting position</li>
360      *  <li> scope (optional) the scope to apply the closure to</li>
361      * </ul>
362      */
363     arrFilter:function (arr, func /*startPos, scope*/) {
364         if (!arr || !arr.length) return [];
365         arr = this.objToArray(arr);
366         return ((startPos) ? arr.slice(startPos).filter(func, thisObj) : arr.filter(func, thisObj));
367     },
368     /**
369      * adds a EcmaScript optimized indexOf to our mix,
370      * checks for the presence of an indexOf functionality
371      * and applies it, otherwise uses a fallback to the hold
372      * loop method to determine the index
373      *
374      * @param arr the array
375      * @param element the index to search for
376      */
377     arrIndexOf:function (arr, element /*fromIndex*/) {
378         if (!arr || !arr.length) return -1;
379         var pos = Number(arguments[2]) || 0;
380         arr = this.objToArray(arr);
381         return arr.indexOf(element, pos);
382     },
383     /**
384      * helper to automatically apply a delivered arguments map or array
385      * to its destination which has a field "_"<key> and a full field
386      *
387      * @param dest the destination object
388      * @param args the arguments array or map
389      * @param argNames the argument names to be transferred
390      */
391     applyArgs:function (dest, args, argNames) {
392         var UDEF = 'undefined';
393         if (argNames) {
394             for (var cnt = 0; cnt < args.length; cnt++) {
395                 //dest can be null or 0 hence no shortcut
396                 if (UDEF != typeof dest["_" + argNames[cnt]]) {
397                     dest["_" + argNames[cnt]] = args[cnt];
398                 }
399                 if (UDEF != typeof dest[ argNames[cnt]]) {
400                     dest[argNames[cnt]] = args[cnt];
401                 }
402             }
403         } else {
404             for (var key in args) {
405                 if (!args.hasOwnProperty(key)) continue;
406                 if (UDEF != typeof dest["_" + key]) {
407                     dest["_" + key] = args[key];
408                 }
409                 if (UDEF != typeof dest[key]) {
410                     dest[key] = args[key];
411                 }
412             }
413         }
414     },
415 
416     /**
417      * transforms a key value pair into a string
418      * @param key the key
419      * @param val the value
420      * @param delimiter the delimiter
421      */
422     keyValToStr:function (key, val, delimiter) {
423         var ret = [], pushRet = this.hitch(ret, ret.push);
424         pushRet(key);
425         pushRet(val);
426         delimiter = delimiter || "\n";
427         pushRet(delimiter);
428         return ret.join("");
429     },
430     parseXML:function (txt) {
431         try {
432             var parser = new DOMParser();
433             return parser.parseFromString(txt, "text/xml");
434         } catch (e) {
435             //undefined internal parser error
436             return null;
437         }
438     },
439     serializeXML:function (xmlNode, escape) {
440         if (!escape) {
441             if (xmlNode.data) return xmlNode.data; //CDATA block has raw data
442             if (xmlNode.textContent) return xmlNode.textContent; //textNode has textContent
443         }
444         return (new XMLSerializer()).serializeToString(xmlNode);
445     },
446     serializeChilds:function (xmlNode) {
447         var buffer = [];
448         if (!xmlNode.childNodes) return "";
449         for (var cnt = 0; cnt < xmlNode.childNodes.length; cnt++) {
450             buffer.push(this.serializeXML(xmlNode.childNodes[cnt]));
451         }
452         return buffer.join("");
453     },
454     isXMLParseError:function (xmlContent) {
455         //no xml content
456         if (xmlContent == null) return true;
457         var findParseError = function (node) {
458             if (!node || !node.childNodes) return false;
459             for (var cnt = 0; cnt < node.childNodes.length; cnt++) {
460                 var childNode = node.childNodes[cnt];
461                 if (childNode.tagName && childNode.tagName == "parsererror") return true;
462             }
463             return false;
464         };
465         return !xmlContent ||
466                 (this.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) ||
467                 findParseError(xmlContent);
468     },
469     /**
470      * fetches the error message from the xml content
471      * in a browser independent way
472      *
473      * @param xmlContent
474      * @return a map with the following structure {errorMessage: the error Message, sourceText: the text with the error}
475      */
476     fetchXMLErrorMessage:function (text, xmlContent) {
477         var _t = this;
478         var findParseError = function (node) {
479             if (!node || !node.childNodes) return false;
480             for (var cnt = 0; cnt < node.childNodes.length; cnt++) {
481                 var childNode = node.childNodes[cnt];
482                 if (childNode.tagName && childNode.tagName == "parsererror") {
483                     var errorMessage = _t.serializeXML(childNode.childNodes[0]);
484                     //we now have to determine the row and column position
485                     var lastLine = errorMessage.split("\n");
486                     lastLine = lastLine[lastLine.length-1];
487                     var positions = lastLine.match(/[^0-9]*([0-9]+)[^0-9]*([0-9]+)[^0-9]*/);
488 
489                     var ret = {
490                         errorMessage: errorMessage,
491                         sourceText: _t.serializeXML(childNode.childNodes[1].childNodes[0])
492                     }
493                     if(positions) {
494                         ret.line = Math.max(0, parseInt(positions[1])-1);
495                         ret.linePos = Math.max(0, parseInt(positions[2])-1);
496                     }
497                     return ret;
498                 }
499             }
500             return null;
501         };
502         var ret = null;
503         if (!xmlContent) {
504             //chrome does not deliver any further data
505             ret =  (this.trim(text || "").length > 0)? {errorMessage:"Illegal response",sourceText:""} : {errorMessage:"Empty Response",sourceText:""};
506         } else if (this.exists(xmlContent, "parseError.errorCode") && xmlContent.parseError.errorCode != 0) {
507             ret =   {
508                 errorMessage:xmlContent.parseError.reason,
509                 line:Math.max(0, parseInt(xmlContent.parseError.line)-1),
510                 linePos:Math.max(0,parseInt(xmlContent.parseError.linepos) -1),
511                 sourceText:xmlContent.parseError.srcText
512             };
513         } else {
514             ret = findParseError(xmlContent);
515         }
516         //we have a line number we now can format the source accordingly
517         if(ret && 'undefined' != typeof ret.line) {
518             var source = ret.sourceText ||"";
519             source = source.split("\n");
520             if(source.length-1 < ret.line) return ret;
521             source = source[ret.line];
522             var secondLine = [];
523             var lineLen = (ret.linePos - 2);
524             for(var cnt = 0; cnt < lineLen; cnt++) {
525                 secondLine.push(" ");
526             }
527             secondLine.push("^^");
528             ret.sourceText = source;
529             ret.visualError = secondLine;
530         }
531         return ret;
532     },
533 
534     /**
535      * creates a neutral form data wrapper over an existing form Data element
536      * the wrapper delegates following methods, append
537      * and adds makeFinal as finalizing method which returns the final
538      * send representation of the element
539      *
540      * @param formData an array
541      */
542     createFormDataDecorator:function (formData) {
543         //we simulate the dom level 2 form element here
544         var _newCls = null;
545         var bufInstance = null;
546         if (!this.FormDataDecoratorArray) {
547             this.FormDataDecoratorArray = function (theFormData) {
548                 this._valBuf = theFormData;
549                 this._idx = {};
550             };
551             _newCls = this.FormDataDecoratorArray;
552             _newCls.prototype.append = function (key, val) {
553                 this._valBuf.push([encodeURIComponent(key), encodeURIComponent(val)].join("="));
554                 this._idx[key] = true;
555             };
556             _newCls.prototype.hasKey = function (key) {
557                 return !!this._idx[key];
558             };
559             _newCls.prototype.makeFinal = function () {
560                 return this._valBuf.join("&");
561             };
562         }
563         if (!this.FormDataDecoratorString) {
564             this.FormDataDecoratorString = function (theFormData) {
565                 this._preprocessedData = theFormData;
566                 this._valBuf = [];
567                 this._idx = {};
568             };
569             _newCls = this.FormDataDecoratorString;
570             _newCls.prototype.append = function (key, val) {
571                 this._valBuf.push([encodeURIComponent(key), encodeURIComponent(val)].join("="));
572                 this._idx[key] = true;
573             };
574             //for now we check only for keys which are added subsequently otherwise we do not perform any checks
575             _newCls.prototype.hasKey = function (key) {
576                 return !!this._idx[key];
577             };
578             _newCls.prototype.makeFinal = function () {
579                 if (this._preprocessedData != "") {
580                     return this._preprocessedData + "&" + this._valBuf.join("&")
581                 } else {
582                     return this._valBuf.join("&");
583                 }
584             };
585         }
586         if (!this.FormDataDecoratorOther) {
587             this.FormDataDecoratorOther = function (theFormData) {
588                 this._valBuf = theFormData;
589                 this._idx = {};
590             };
591             _newCls = this.FormDataDecoratorOther;
592             _newCls.prototype.append = function (key, val) {
593                 this._valBuf.append(key, val);
594                 this._idx[key] = true;
595             };
596             _newCls.prototype.hasKey = function (key) {
597                 return !!this._idx[key];
598             };
599             _newCls.prototype.makeFinal = function () {
600                 return this._valBuf;
601             };
602         }
603         if (formData instanceof Array) {
604             bufInstance = new this.FormDataDecoratorArray(formData);
605         } else if (this.isString(formData)) {
606             bufInstance = new this.FormDataDecoratorString(formData);
607         } else {
608             bufInstance = new this.FormDataDecoratorOther(formData);
609         }
610         return bufInstance;
611     },
612     /**
613      * define a property mechanism which is browser neutral
614      * we cannot use the existing setter and getter mechanisms
615      * for now because old browsers do not support them
616      * in the long run we probably can switch over
617      * or make a code split between legacy and new
618      *
619      *
620      * @param obj
621      * @param name
622      * @param value
623      */
624     attr:function (obj, name, value) {
625         var findAccessor = function (theObj, theName) {
626             return (theObj["_" + theName]) ? "_" + theName : ( (theObj[theName]) ? theName : null)
627         };
628         var applyAttr = function (theObj, theName, value, isFunc) {
629             if (value) {
630                 if (isFunc) {
631                     theObj[theName](value);
632                 } else {
633                     theObj[theName] = value;
634                 }
635                 return null;
636             }
637             return (isFunc) ? theObj[theName]() : theObj[theName];
638         };
639         try {
640             var finalAttr = findAccessor(obj, name);
641             //simple attibute no setter and getter overrides
642             if (finalAttr) {
643                 return applyAttr(obj, finalAttr, value);
644             }
645             //lets check for setter and getter overrides
646             var found = false;
647             var prefix = (value) ? "set" : "get";
648             finalAttr = [prefix, name.substr(0, 1).toUpperCase(), name.substr(1)].join("");
649             finalAttr = findAccessor(obj, finalAttr);
650             if (finalAttr) {
651                 return applyAttr(obj, finalAttr, value, true);
652             }
653 
654             throw this.makeException(new Error(), null, null, this._nameSpace, "contains", "property " + name + " not found");
655         } finally {
656             findAccessor = null;
657             applyAttr = null;
658         }
659     },
660 
661     /**
662      * creates an exeption with additional internal parameters
663      * for extra information
664      *
665      * @param {String} title the exception title
666      * @param {String} name  the exception name
667      * @param {String} callerCls the caller class
668      * @param {String} callFunc the caller function
669      * @param {String} message the message for the exception
670      */
671     makeException:function (error, title, name, callerCls, callFunc, message) {
672         error.name = name || "clientError";
673         error.title = title || "";
674         error.message = message || "";
675         error._mfInternal = {};
676         error._mfInternal.name = name || "clientError";
677         error._mfInternal.title = title || "clientError";
678         error._mfInternal.caller = callerCls || this._nameSpace;
679         error._mfInternal.callFunc = callFunc || ("" + arguments.caller.toString());
680         return error;
681     }
682 });
683