1 /** Licensed Materials - Property of IBM, 5724-E76 and 5724-E77, (C) Copyright IBM Corp. 2011, 2012 - All Rights reserved.  **/
  2 (function(){
  3 	/**
  4 	 * START main
  5 	 */
  6 
  7 	/**
  8 	 * The global namespace of the IBM Client API
  9 	 * @name i$
 10 	 * @namespace The global namespace of the IBM Client API
 11 	 */ 
 12 	 
 13 	var w=window,
 14 	i$=function(){
 15 		if(i$.qel){
 16 			return i$.qel.apply(this,arguments);
 17 		} 
 18 	};
 19 	w.i$ = i$;
 20 	
 21 	/**
 22 	 * Refers to the global namespace, by default the window object.
 23 	 * @field global
 24 	 * @type Window
 25 	 */
 26 	i$.global = w;
 27 	//i$.doc = document;
 28 	
 29 	/**
 30 	 * Native console normalization
 31 	 */
 32 	if(typeof(console) == "undefined"){
 33 		/**
 34 		 * @ignore
 35 		 */
 36 		var f = function(){};
 37 		console = {
 38 			log:f,
 39 			debug:f,
 40 			info:f,
 41 			warn:f,
 42 			error:f,
 43 			assert:f
 44 		};
 45 	}
 46 	
 47 	/**
 48 	 * Generates a partial function based on an existing function.  The first argument denotes the 
 49 	 * function to create a new partial for.  All subsequent arguments after that are used to
 50 	 * prefill the original function's parameters with fixed values whenever the partial is
 51 	 * called.  Any undefined values in the arguments list will be used as a placeholder to
 52 	 * shift in the actual calling arguments.  Any calling arguments that are left over after
 53 	 * shifting into placeholder locations will be concatenated to the end of the resulting
 54 	 * arguments that are passed to the original function as if they were default placeholders. 
 55 	 * @type Function
 56 	 * @param {Function} func Function to create a partial from. Must not be null.
 57 	 * @param {Mixed} [args] Values to set at fixed positions in the calling context's
 58 	 * 		actual arguments.
 59 	 * @return {Function} A new partial function based on f. Never null.
 60 	 * 
 61 	 * @example
 62 	 * Example 1
 63 	 * var f = i$.partial(function(a, b, c){ 
 64 	 *     alert(a + " - " + b + " - " + c);
 65 	 * }, 1, 5); // fixes the first 2 parameters a and b
 66 	 * f(10); // alerts "1 - 5 - 10"
 67 	 * 
 68 	 * @example
 69 	 * Example 2
 70 	 * var f = i$.partial(function(a, b, c){ 
 71 	 *     alert(a + " - " + b + " - " + c);
 72 	 * }, 1, undefined, 5); // fixes parameter a and c, and marks b as a placeholder
 73 	 * f(3); // alerts "1 - 3 - 5"
 74 	 * 
 75 	 * @example
 76 	 * Example 3
 77 	 * var f = i$.partial(function(a, b, c){ 
 78 	 *     alert(a + " - " + b + " - " + c);
 79 	 * }, undefined, 10); // fixes parameter b
 80 	 * f(1, 100); // alerts "1 - 10 - 100"
 81 	 */
 82 	i$.partial = function(/*Function*/f) {
 83 		var factoryArgs = i$.toArray(arguments).slice(1);
 84 		return function() {
 85 			var args = factoryArgs.slice(0), 	// copy factory args
 86 				cArgs = i$.toArray(arguments),	// calling args
 87 				i=0;
 88 			for(;i<args.length;i++){
 89 				if(args[i] === undefined){
 90 					args[i] = cArgs.shift();	// shift calling args into placeholders
 91 				}
 92 			}
 93 			args.push.apply(args, cArgs);	// push the left over onto args
 94 			return f.apply(this, args);				// call the original function
 95 		};
 96 	};
 97 	/**
 98 	 * Generates a partial function based on an existing function but fixes the scope in which the
 99 	 * partial function is called regardless of the eventual calling scope.
100 	 * @see i$.partial
101 	 * @type Function
102 	 * @param {Object} obj Object to scope the function to so that the returned
103 	 * 		function always calls func in context of this scope object. Must not be null.
104 	 * @param {Function} func Function to scope. Must not be null.
105 	 * @param {Mixed} [args] Arguments with same semantics as {@link i$.partial}
106 	 * 
107 	 * @return {Function}
108 	 * A new function like {@link i$.partial} but fixes the function's scope permanently.
109 	 * Calling this without additional arguments besides obj and func simply creates a new function
110 	 * of the same arity whose scope is fixed to obj.
111 	 * 
112 	 * @example
113 	 * Example 1:
114 	 * var obj = {a: 1};
115 	 * var f = i$.scope(obj, function(b, c){ 
116 	 *     alert(this.a + " - " + b + " - " + c); 
117 	 * });
118 	 * f(3, 5); // alerts "1 - 3 - 5"
119 	 * 
120 	 * @example
121 	 * Example 2:
122 	 * var obj = {a: 1};
123 	 * var f = i$.scope(obj, function(b, c){ 
124 	 *     alert(this.a + " - " + b + " - " + c); 
125 	 * }, undefined, 5);
126 	 * f(3); // alerts "1 - 3 - 5"
127 	 */
128 	i$.scope = function(/*Object*/s,/*Function|String*/f) {
129 		var of = f;
130 		f = function(){
131 			return (i$.isString(of) ? s[of] : of).apply(s, arguments);
132 		};
133 		return i$.partial.apply(this, i$.toArray(arguments).slice(1));
134 	};
135 	/**
136 	 * Logs an error to the console.error function.  Entry point for extensions to capture logged
137 	 * errors.
138 	 * 
139 	 * @private
140 	 * @param {String} message Message to be logged out as error
141 	 * @param {Error} [err] Error object to be logged
142 	 * @type void
143 	 */
144 	i$.error = function(/*String*/message, /*Error?*/err){
145 		console.error(err || new Error(message));
146 	};
147 	
148 	/**
149 	 * Enumerates over all items in an array or an object that is like an array as defined
150 	 * by {@link i$.isLikeArray}, calling function func for each enumerated value.
151 	 * 
152 	 * @private
153 	 * @param {Array} arr Array to enumerate. Must not be null.
154 	 * @param {Function} func Function with signature function(value, index, originalArray) to 
155 	 * 		call for each property or index. Must not be null.
156 	 * @param {Number} [start] optional start count
157 	 * @type void
158 	 */
159 	i$.forEach = function(arr,f,start) {
160 		if(start==null){start=0;}
161 		for(var i=(start>=0)?start:0;i<arr.length;i++){
162 			f(arr[i],i,arr);
163 		}
164 	};
165 	/**
166 	 * Enumerates over all properties of obj, calling function func for each enumerated value.
167 	 * 
168 	 * @private
169 	 * @param {Object} obj Object whose properties should be enumerated
170 	 * @param {Function} func Function with signature function(value, propName, originalObject) to 
171 	 * 		call for each property or index.
172 	 */
173 	i$.forIn = function(o,f){
174 		for(var i in o) {
175 			if (Object.prototype.hasOwnProperty.call(o,i)) {
176 				f(o[i],i,o);	
177 			}
178 		}
179 	};
180 	/**
181 	 * Enumerates over all properties of obj if obj is an object, or all items in obj if it is an array or is
182 	 * like an array (see {@link i$.isLikeArray}), calling function func in optional scope (defaulting to the global scope)
183 	 * for each enumerated value.
184 	 * 
185 	 * @param {Object|Array} obj Object or Array to enumerate. Must not be null
186 	 * @param {Function} func Function with signature function(value, index|propName, originalObject) to 
187 	 * 		call for each property or index. Must not be null
188 	 * @param {Object} [scope=i$.global] Object optional scope to call func in
189 	 * @type void
190 	 */
191 	i$.each = function(o,f,s){
192 		if(s){f = i$.scope(s,f);}
193 		if(o) {
194 			if(o instanceof Array || typeof o.length === "number") {
195 				i$.forEach(o,f);
196 			}
197 			else {
198 				i$.forIn(o,f);
199 			}
200 		}
201 	};
202 	/**
203 	 * Tests whether some element in the array passes the test implemented by the provided function.
204 	 * 
205 	 * @return {Boolean} Returns true if calling function func on each of the items in arr ever returns true; false otherwise. 
206 	 * @type Boolean
207 	 * @param {Array|ArrayLike} arr Array to search; may simply be like an array. Must not be null.
208 	 * @param {Function} func Function with signature function(value) to 
209 	 * 		call for each property or index. Must not be null.
210 	 * @param {Object} [scope=i$.global] Object optional scope to call func in
211 	 */
212 	i$.some = function(a,f,s){
213 		if(s){f = i$.scope(s,f);}
214 		for(var i=0;i<a.length;i++){
215 			if(f(a[i])){
216 				return true;
217 			}
218 		}
219 		return false;
220 	};
221 	/**
222 	 * Tests whether all elements in the array pass the test implemented by the provided function.
223 	 * 
224 	 * @return {Boolean} Returns true if calling function func on each of the items in arr never returns false; false otherwise.  
225 	 * @type Boolean
226 	 * @param {Array|ArrayLike} arr Array to search; may simply be like an array. Must not be null.
227 	 * @param {Function} func Function with signature function(value) to 
228 	 * 		call for each property or index. Must not be null.
229 	 * @param {Object} [scope=i$.global] Object optional scope to call func in
230 	 */
231 	i$.every = function(o,f,s){
232 		if(s){f = i$.scope(s,f);}
233 		return !i$.some(o,function(val){
234 			return !f(val);
235 		});
236 	};
237 	
238 
239 	/**
240 	 * Provides light-weight AOP-style programming with around advice semantics.
241 	 * Overrides the function at obj[name] with a new function that effectively wraps the previous
242 	 * one and that has this signature:  function(originalFn, arguments)
243 	 * Normal processing can be continued by returning the return value from calling
244 	 * originalFn.apply(this, arguments).
245 	 * The modified object property is tagged such that it can be unwrapped to restore its
246 	 * original form using {@link i$.unwrap}.
247 	 * <p>Note: A function property may be wrapped multiple times, but is modeled as a stack
248 	 * such that {@link i$.unwrap} will only unwrap the top wrapping layer at that point
249 	 * in time.</p>
250 	 * 
251 	 * @example
252 	 * Example:
253 	 * var car = {
254 	 *     drive: function(){
255 	 *         console.log("Driving");
256 	 *     }
257 	 * };
258 	 * i$.wrap(car, "drive", function(originalFn, args) {
259 	 *     if(!isIcy) {
260 	 *         return originalFn.apply(this, args);
261 	 *     }
262 	 *     else {
263 	 *         console.warn("It is too icy!");
264 	 *     }
265 	 * });
266 	 * @param {Object} obj object to wrap a function property on. Must not be null.
267 	 * @param {String} name name of the object property that references a function to wrap. Must not be null.
268 	 * @param {Function} func function to replace the original with that has the signature 
269 	 * 		function(originalFn, args). Must not be null.
270 	 * @type Function
271 	 * @return {Function} the wrapped function. Never null.
272 	 */
273 	i$.wrap = function(o,n,f){
274 		var fn = o[n];
275 		o[n] = function(){
276 			return f.call(this,fn,arguments);
277 		};
278 		o[n]._wrapped = fn;
279 		return o[n];
280 	};
281 	/**
282 	 * Unwraps a previously wrapped function at obj[name] from {@link i$.wrap} to its original form and
283 	 * resets it back.
284 	 * @param {Object} obj object to unwrap a function property on. Must not be null.
285 	 * @param {String} name name of the object property that references a function to unwrap. Must not be null.
286 	 * @type Function
287 	 * @return {Function} the unwrapped function or if no unwrapping possible, the original function again. Never null.
288 	 */
289 	i$.unwrap = function(o,n){
290 		var fn = o[n];
291 		if(fn && fn._wrapped){o[n] = fn._wrapped;}
292 		return o[n];
293 	};
294 	
295 	i$.copyShallow = function(o){
296 		var r = i$.isArrayLike(o)?[]:{};
297 		i$.forIn(o, function(v,k){
298 			r[k]=v;
299 		});
300 		return r;
301 	};
302 	
303 	/**#@+ @ignore */
304 	var shadowPropFn = function(propName,target,overwrite,name){
305 		if(overwrite || target[name] === undefined){
306 			target[name] = function(){
307 				return this[propName][name].apply(this[propName], arguments);
308 			};
309 		}
310 	}, shadowObjFn = function(obj,target,overwrite, name){
311 		if(overwrite || target[name] === undefined){
312 			target[name] = function(){
313 				return obj[name].apply(obj, arguments);
314 			};
315 		}
316 	};
317 	/**#@-*/
318 	
319 	/** 
320 	 * Creates shadowing functions on target that call the underlying functions on the shadowed source referred
321 	 * to by source.  Those functions are called in the source's scope instead of the target's.  This allows
322 	 * building up functions with less code that provide passthroughs to other objects as well as hiding
323 	 * APIs (Example: read-only).
324 	 * 
325 	 * @param {String|Object} source String|Object refers to the source to delegate functions to.  If it is a string, it refers
326 	 * 		to the name of the property on the scope of the function's execution context.  If it is an object, it is
327 	 * 		accessed directly as a property on that object.
328 	 * @param {Object} target Object the target to create new functions on which shadow functions on the source.
329 	 * @param {Array} names Array of string names to create function properties for.
330 	 * @param {Boolean} [overwrite=false] Boolean property to specify whether or not the shadowing
331 	 * 		process should overwrite existing functions on the target with the same name.
332 	 * @type void
333 	 * 
334 	 * @example
335 	 * Example 1:
336 	 * 
337 	 * var source = {
338 	 *     say: function(){ 
339 	 *         alert("I am " + this.name); 
340 	 *     }, 
341 	 *     name: "Sam" 
342 	 * };
343 	 * var target = {
344 	 *     name: "Mouse"
345 	 * };
346 	 * i$.shadow(source, target, ["say"]);	// creates a "say" function on target
347 	 * target.say(); // alerts "I am Mouse"
348 	 * source.say = function(){ alert(this.name + " I am"); };
349 	 * target.say(); // alerts "Mouse I am"
350 	 * 
351 	 * @example
352 	 * Example 2:
353 	 * 
354 	 * var target = {
355 	 *     name: "Mouse", 
356 	 *     sourceProp: {
357 	 *          say: function(){ 
358 	 *              alert("I am " + this.name); 
359 	 *          },
360 	 *          name: "Sam" 
361 	 *     }
362  	 * };
363 	 * i$.shadow("sourceProp", target, ["say"]);	// creates a "say" function on target
364 	 * target.say(); // alerts "I am Mouse"
365 	 * target.sourceProp.say = function(){ alert(this.name + " I am"); };
366 	 * target.say(); // alerts "Mouse I am"
367 	 */
368 	i$.shadow = function(s,t,names,over){
369 		i$.each(names, i$.partial(i$.isString(s) ? shadowPropFn : shadowObjFn, s, t, over));
370 	};
371 	
372 	/**#@+
373 	   @ignore
374 	*/
375 	var objFromPath = function(path, c, s){
376 		var i, p, ts = s||i$.global;
377 		for(i=0;ts!=null,i<path.length,p=path[i];i++){
378 			if(ts[p]==null) {
379 				if(c){ts[p]={};}
380 				else{ts=null;break;}
381 			}
382 			ts = ts[p];
383 		}
384 		return ts;
385 	};
386 	/**#@-*/
387 	
388 	/**
389 	 * Gets whatever value is resolved by the dot-delimited namepath in the property chain of the scope object, 
390 	 * which defaults to the global scope if none is provided.  Conditionally creates the path if any
391 	 * part of it does not exist, setting empty objects at each null or undefined segment in the path.
392 	 * 
393 	 * @param {String} namepath String with dot-delimited segments that refer to a name path to an object. Must not be null.
394 	 * @param {Boolean} [create=false] Boolean value that instructs the function to create the name path if it
395 	 * 		does not exist completely.
396 	 * @param {Object} [scope=i$.global] Object to begin the lookup for the name path resolution.
397 	 * @type Object
398 	 * @return {Object} the path object or null.
399 	 * 
400 	 * @example
401 	 * Example 1:
402 	 * 
403 	 * var obj = i$.fromPath("com.ibm.theme.feature");
404 	 * alert(obj); // alerts "null"
405 	 * 
406 	 * @example
407 	 * Example 2:
408 	 * 
409 	 * var obj = i$.fromPath("com.ibm.theme.feature", true);
410 	 * alert(obj===com.ibm.theme.feature); // alerts "true"
411 	 * 
412 	 * @example
413 	 * Example 3:
414 	 * 
415 	 * var obj1 = i$.fromPath("com.ibm.theme", true);
416 	 * var obj2 = i$.fromPath("feature", true, obj1);
417 	 * alert(obj2===com.ibm.theme.feature); // alerts "true"
418 	 */
419 	i$.fromPath = function(n, c, s) {
420 		var path = n.split(".");
421 		return objFromPath(path, c, s);
422 	};
423 	/**
424 	 * Sets a value to the dot-delimited path namepath in the property chain of the scope object, 
425 	 * which defaults to the global scope if none is provided.
426 	 * 
427 	 * @param {String} namepath String with dot-delimited parts that refer to a name path to an object. Must not be null.
428 	 * 			Any null or undefined segments in the path will be initialized to empty objects. 
429 	 * @param {Mixed} value Any value to set at the last part of the objects resolved by the name path. Must not be null.
430 	 * @param {Object} [scope=i$.global] Object to begin the lookup for the name path resolution.
431 	 * @type Mixed
432 	 * @return {Mixed} the passed in value.
433 	 * 
434 	 * @example
435 	 * Example 1:
436 	 * 
437 	 * i$.toPath("com.ibm.theme.feature", {
438 	 *     say: function() {
439 	 *         alert("hello");
440 	 *     }
441 	 * });
442 	 * com.ibm.theme.feature.say(); // alerts "hello"
443 	 * 
444 	 * @example
445 	 * Example 2:
446 	 * 
447 	 * var ibm = i$.fromPath("com.ibm", true);
448 	 * i$.toPath("theme.feature", {
449 	 *     say: function() {
450 	 *         alert("hello");
451 	 *     }
452 	 * }, ibm);
453 	 * com.ibm.theme.feature.say(); // alerts "hello"
454 	 */
455 	i$.toPath = function(n, v, s) {
456 		var path = n.split("."), 
457 			p = path.pop(),
458 			o = objFromPath(path, true, s);
459 		o[p] = v;
460 		return v;
461 	};
462 	
463 	/**
464 	 * Wraps a function into a singleton-factory builder such that on the first function call,
465 	 * it calls the wrapped function and stores its return value then returns it.  On subsequent
466 	 * calls, it just returns the original value.
467 	 * 
468 	 * @param {Function} func the function to be called the first time. Must not be null.
469 	 * @param {Object} [scope] Object optional scope to call func in
470 	 * @type Function
471 	 * @returns {Function} Returns the singleton factory function. Never null.
472 	 * 
473 	 * @example
474 	 * var singleton = i$.cachedFn(function() {
475 	 *     alert("hello");
476 	 *     return true;
477 	 * });
478 	 * singleton(); // alerts "hello"
479 	 * singleton(); // does not alert anything, just returns true
480 	 */
481 	i$.cachedFn = function(f,s){
482 		var val;
483 		var fn = function(){
484 			if(!fn.called){ // expose for backdoor uncaching
485 				fn.called = true;
486 				val = f.apply(s, arguments);
487 			}
488 			return val;
489 		}
490 		return fn;
491 	};
492 	
493 	i$.xhrFmts = {
494 		text: function(xhr){
495 			return xhr.responseText;
496 		},
497 		json: function(xhr) {
498 			return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
499 					xhr.responseText.replace(/"(\\.|[^"\\])*"/g, ''))) &&
500 					eval('(' + xhr.responseText + ')');
501 		},
502 		xml: function(xhr) {
503 			return xhr.responseXML;
504 		},
505 		javascript: function(xhr) {
506 			if ((/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
507 					str.replace(/"(\\.|[^"\\])*"/g, '')))) {
508 					throw new SyntaxError("Invalid characters in javascript object");
509 			}
510 			else {
511 				return  eval('(' +  xhr.responseText + ')');
512 			}
513 		}
514 	};
515 	
516 	/**
517 	 * END main
518 	 */
519 })();(function(){
520 	/**
521 	 * START of i$/core_ext
522 	 */
523 	/**
524 	 * Support for frames
525 	 */
526 	var i$ = window.i$;
527 	
528 	/**
529 	 * This module defines APIs that are directly defined here but may also 
530 	 * be reimplemented by some compat or adapter module.  Such implementations
531 	 * may use another framework to do so.  The overrides may be applied after
532 	 * this is loaded or in place of it.
533 	 */
534 	
535 	// doclets for client detection properties
536 	/**
537 	 * Value indicating the version of Internet Explorer being used; undefined
538 	 * otherwise.
539 	 * @property
540 	 * @type Number
541 	 * @name i$.isIE
542 	 */
543 	 
544 	/**
545 	 * Value indicating the version of Firefox being used; undefined
546 	 * otherwise.
547 	 * @property
548 	 * @type Number
549 	 * @name i$.isFF
550 	 */
551 	 
552 	/**
553 	 * Value indicating the version of Opera being used; undefined
554 	 * otherwise.
555 	 * @property
556 	 * @type Number
557 	 * @name i$.isOpera
558 	 */
559 	 
560 	/**
561 	 * Value indicating the version of Safari being used; undefined
562 	 * otherwise.
563 	 * @property
564 	 * @type Number
565 	 * @name i$.isSafari
566 	 */
567 	 
568 	/**
569 	 * Value indicating the version of Chrome being used; undefined
570 	 * otherwise.
571 	 * @property
572 	 * @type Number
573 	 * @name i$.isChrome
574 	 */
575 	 
576 	/**
577 	 * Value indicating the version of WebKit being used; undefined
578 	 * otherwise.
579 	 * @property
580 	 * @type Number
581 	 * @name i$.isWebKit
582 	 */
583 	
584 	/**#@+ @ignore */
585 	// client detection
586 	(function(ua){
587 		var toVer = function(verStr){
588 				return parseFloat(verStr);	// return type Number
589 				/*
590 				var p = verStr.split(".");
591 				return {major:p[0],minor:p[1],rev:p[2],toString: function(){return p.join(".");}};
592 				*/
593 			},
594 			list=[
595 				["IE", /MSIE\s*([\S]+)*/],
596 				["FF", /Firefox\/([\S]+)*/],
597 				["Opera", /Opera[\s\/]([\S]+)*/],
598 				["Safari", /Version\/([\S]+)*[\s\S]*Safari/],
599 				["Chrome", /Chrome\/([\S]+)*/],
600 				["WebKit", /AppleWebKit\/([\S]+)*/]];
601 		i$.each(list, function(test){
602 			var m = test[1].exec(ua);
603 			if(m && m.length > 1) { 
604 				i$["is"+test[0]] = toVer(m[1]);
605 			};
606 		});
607 	})(navigator.userAgent);
608 	// check if IE is in compatibility mode, update i$.isIE if it is different than what was retrieved from the user agent
609 	var compatMode = document.documentMode;
610 	if(compatMode && compatMode != 5 && Math.floor(i$.isIE) != compatMode){
611 		i$.isIE = compatMode;
612 	}
613 	/**#@- */
614 	
615 	
616 	/**
617 	 * Determines if an object is a DOM node or not.
618 	 * 
619 	 * @param {Object} obj Object to be tested. Must not be null.
620 	 * @type Boolean
621 	 * @return {Boolean} Returns true if obj is a DOM node, false otherwise.
622 	 */
623 	i$.isNode = function(o){
624 		return typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string";
625 	};
626 	/**
627 	 * Determines if an object is a function or not.
628 	 * 
629 	 * @param {Object} obj Object to be tested. Must not be null.
630 	 * @type Boolean
631 	 * @return {Boolean} Returns true if obj is a function, false otherwise.
632 	 */
633 	i$.isFunction = function(o){
634 		return typeof o === "function" || o instanceof Function;
635 	};
636 	/**
637 	 * Determines if an object is an object or not.
638 	 * 
639 	 * @param {Object} obj Object to be tested. Must not be null.
640 	 * @type Boolean
641 	 * @return {Boolean} Returns true if obj is an object, false otherwise.
642 	 */
643 	i$.isObject = function(o){
644 		return typeof o === "object";
645 	};
646 	/**
647 	 * Determines if an object is an array or not.
648 	 * 
649 	 * @param {Object} obj Object to be tested. Must not be null.
650 	 * @type Boolean
651 	 * @return {Boolean} Returns true if obj is an array, false otherwise.
652 	 */
653 	i$.isArray = function(o){
654 		if (typeof Array.isArray === "function") {
655 			return Array.isArray(o);
656 		} else {
657 			return Object.prototype.toString.call(o) === "[object Array]";
658 		}
659 	};
660 	/**
661 	 * Determines if an object is a string or not.
662 	 * 
663 	 * @param {Object} obj Object to be tested. Must not be null.
664 	 * @type Boolean
665 	 * @return {Boolean} Returns true if obj is a string, false otherwise.
666 	 */
667 	i$.isString = function(o){
668 		return typeof o === "string";
669 	};
670 	/**
671 	 * Determines if an object is a number or not.
672 	 * 
673 	 * @param {Object} obj Object to be tested. Must not be null.
674 	 * @type Boolean
675 	 * @return {Boolean} Returns true if obj is a number, false otherwise.
676 	 */
677 	i$.isNumber = function(o){
678 		return typeof o === "number";
679 	};
680 	/**
681 	 * Determines if an object is a boolean or not.
682 	 * 
683 	 * @param {Object} obj Object to be tested. Must not be null.
684 	 * @type Boolean
685 	 * @return {Boolean} Returns true if obj is a boolean, false otherwise.
686 	 */
687 	i$.isBoolean = function(o){
688 		return typeof o === "boolean";
689 	};
690 	/**
691 	 * Determines if an object is array like or not.
692 	 * 
693 	 * @param {Object} obj Object to be tested. Must not be null.
694 	 * @type Boolean
695 	 * @return {Boolean} Returns true if obj is like an array, namely that it at least has a length property of type number; 
696 	 * false otherwise.
697 	 */
698 	i$.isLikeArray = function(o){
699 		return o instanceof Array || typeof o.length === "number";
700 	};
701 	
702 	/**
703 	 * Returns a true array from obj, creating a copy if obj is already an array. Useful for
704 	 * coercing array-like structures into true arrays safely.
705 	 * 
706 	 * @param {Object|Array} obj Array or array-like object to convert into a new array. Must not be null.
707 	 * @type Array
708 	 * @return {Array} A new array. Never null.
709 	 */
710 	i$.toArray = function(o){
711 		return Array.prototype.slice.call(o);
712 	};
713 	
714 	/**#@+ @ignore */
715 	if(i$.isIE) {
716 		var fast = i$.toArray;
717 		i$.toArray = function(o) {
718 			try { // fast toArray
719 				return fast(o);
720 			} catch(err) { // slow toArray
721 				var a = new Array(o.length);
722 				for(var i=0;i<o.length;i++) {
723 					a[i]=o[i];
724 				}
725 				return a;
726 			}
727 		};
728 	}
729 	
730 	// window/document onload and onunload handling
731 	var pageLoaded = (document.readyState === "complete"),
732 		loadFns = [],
733 		unloadFns = [],
734 		unloadSet = false;
735 
736 	i$._initPage = function() {
737 		// fires all the loaders
738 		var fn;
739 		pageLoaded = true;
740 		if(window.detachEvent) {
741 			// leak protection
742 			window.detachEvent("onload", i$._initPage);
743 		}
744 		
745 		while(loadFns.length>0){
746 			if(fn = loadFns.shift()) {
747 				try {
748 					fn();
749 				}
750 				catch (err) {
751 					console.log(err);
752 				}
753 			}
754 		}
755 	};
756 	i$._exitPage = function() {
757 		// fires all the unloaders
758 		var fn;
759 		while(unloadFns.length>0){
760 			if(fn = unloadFns.shift()) {
761 				try {
762 					fn();
763 				}
764 				catch (err) {
765 					console.log(err);
766 				}
767 			}
768 		}
769 	};
770 	i$._addEvent = function(e,f,o){
771 		// adds an event to given object
772 		// e: the event name, must have "on" as the first two characters
773 		// f: the function to run when the event fires, fired on o
774 		// o: the object on which to attach the event, window if unspecified
775 		var w = o ? o : window;
776 		var s = w.attachEvent ? e : e.substring(2);  // chop off the "on" part
777 		var a = w.attachEvent || w.addEventListener;
778 		a(s, function(){ f.apply(w, arguments); }, false);
779 	};
780 	// add init and exit page handlers
781 	if(!pageLoaded) { 
782 		i$._addEvent("onload", i$._initPage);
783 		if (document.addEventListener) {  // browser compatibility
784 			document.addEventListener("DOMContentLoaded", i$._initPage, false); // fires before onload, is sufficient and faster
785 		}
786 	}
787 	/**#@-*/
788 	
789 	/**
790 	 * Adds a function to call on page load
791 	 * 
792 	 * @param {Function|String} func The function to call, either a function or name of a function on 
793 	 * 		scope object. Must not be null
794 	 * @param {Object} [scope=i$.global] The scope in which to call the function, i.e. the 'this' keyword within the function represents the scope object
795 	 * @type void
796 	 */
797 	i$.addOnLoad = function(f,o) {
798 		if(o) { f = i$.scope(o,f); }
799 		if(pageLoaded) {  // fire immediately if page is loaded
800 			f();
801 		} else {
802 			loadFns.push(f);
803 		}
804 	};
805 	/**
806 	 * Adds a function to call on page unload. Not supported on Opera.
807 	 * 
808 	 * @param {Function|String} func The function to call, either a function or name of a function on 
809 	 * 		scope object. Must not be null.
810 	 * @param {Object} [scope=i$.global] The scope in which to call the function
811 	 * @type void
812 	 */
813 	i$.addOnUnload = function(f,o) {
814 		// please note: Opera does not support the onunload event
815 		if(!unloadSet) { i$._addEvent("onunload", i$._exitPage); unloadSet = true; }
816 		if(o) { f = i$.scope(o,f); }
817 		unloadFns.push(f);
818 	};
819 		
820 	/**#@+
821 	   @ignore
822 	*/
823 	var mx = function(o,m){
824 		for(var p in m) {
825 			if(m.hasOwnProperty(p)){o[p]=m[p];}
826 		}
827 	}, mxn = function(o,m,names) {
828 		i$.forEach(names, function(p){
829 			if(m.hasOwnProperty(p)){o[p]=m[p];}
830 		});
831 	};
832 	/**#@-*/
833 	
834 	/**
835 	 * Enumerates over arguments, mashing all the native properties of each argument 
836 	 * object into the first argument object, returning the first.  Properties with the
837 	 * same name are resolved by using the last argument that contains that property.
838 	 * 
839 	 * @param {Object} obj Target object to get new property values from subsequent arguments. Must not be null.
840 	 * @param {Object} props Objects to mash properties into the prototype. Must not be null.
841 	 * @type Function
842 	 * @return {Function} Returns obj again which has been passed into the mash function
843 	 * 
844 	 * @example
845 	 * var bag1 = {
846 	 *     prop1: "value", 
847 	 *     prop2: "Pass"
848 	 * };
849 	 * var bag2 = {
850 	 *     prop2: 15
851 	 * };
852 	 * i$.mash(stash, bag1, bag2);
853 	 * 
854 	 * is functionally equivalent to:
855 	 * 
856 	 * stash.prop1 = "value";
857 	 * stash.prop2 = "Pass";
858 	 * stash.prop2 = 15;
859 	 */
860 	i$.mash = function(o) {
861 		i$.forEach(arguments, function(v){
862 			mx(o,v);
863 		},1); // start at index 1 of arguments
864 		return o;
865 	};
866 	/**
867 	 * Like {@link i$.mash} but only mashes properties whose names are in the names array first
868 	 * argument. The same semantics as {@link i$.mash} are applied except that the arguments
869 	 * are shifted by one to accommodate the names argument.  This is useful for only mashing
870 	 * certain known properties from various objects into a target.
871 	 * 
872 	 * @param {String[]} names An array of property names to mash. Must not be null.
873 	 * @param {Object} obj Target object to get new property values from subsequent arguments. Must not be null.
874 	 * @param {Object} props Objects to mash properties from. Must not be null.
875 	 * @type Function
876 	 * @return {Function} Returns obj again which has been passed into the mashSpec function
877 	 */
878 	i$.mashSpec = function(n,o) {
879 		i$.forEach(arguments, function(v){
880 			mxn(o,v,n);
881 		},2);	// start at index 2 of arguments
882 		return o;
883 	};
884 	/**
885 	 * Like {@link i$.mash} but mashes properties into the function's prototype.
886 	 * Properties with the same name are resolved by using the last 
887 	 * argument that contains that property.
888 	 * 
889 	 * @param {Function} func Function whose prototype should be augmented. Must not be null.
890 	 * @param {Object} props Objects to mash properties into the prototype. Must not be null.
891 	 * @type Function
892 	 * @return {Function} Returns func again which has been passed into the augment function
893 	 * 
894 	 * @example
895 	 * var visuals = {
896 	 *     color: "white"
897 	 * };
898 	 * var structural = {
899 	 *     make: "sedan"
900 	 * };
901 	 * i$.augment(Car, visuals, structural);
902 	 * 
903 	 * is functionally equivalent to:
904 	 * 
905 	 * Car.prototype.color = "white";
906 	 * Car.prototype.make = "sedan";
907 	 */
908 	i$.augment = function(f) {
909 		var r = f;
910 		if(f && f.prototype) {
911 			f = f.prototype;
912 			i$.mash.apply(i$, arguments);
913 		}
914 		return r;
915 	};
916 	/**
917 	 * Creates and returns a new object whose prototype is the proto argument.  This provides
918 	 * a light-weight API for building prototypal inheritance structures without
919 	 * constructing instances of the o argument.  All arguments after the proto argument
920 	 * are used to mash properties into the new object just like {@link i$.mash}.
921 	 * 
922 	 * @function
923 	 * @param {Object} proto Object to use as the prototype of the returned object. Must not be null.
924 	 * @param {Object} props Objects to mash properties into the prototype. Must not be null.
925 	 * @type Object
926 	 * @return {Object} A new object. Never null.
927 	 */
928 	i$.make = (function(){
929 		var l = function(){};
930 		return function(o) {
931 			l.prototype = o;
932 			o = new l();
933 			return i$.mash.apply(i$, arguments);
934 		};
935 	})();
936 	
937 	var frontTrim = /^\s+/g;
938 	/**
939 	 * The trim function removes all newlines, spaces (including non-breaking spaces), and tabs
940 	 * from the beginning and end of the supplied string. If these whitespace characters occur
941 	 * in the middle of the string, they are preserved.
942 	 * 
943 	 * @param {String} str String to be trimmed. Must not be null.
944 	 * @type String
945 	 * @return {String} The trimmed string
946 	 */
947 	i$.trim = function(str){
948 		str = str.replace(frontTrim, "");
949 		var i = str.length-1;
950 		while(str.charAt(i)==" " || str.charAt(i)=="\t" || str.charAt(i)=="\n" || str.charAt(i)=="\r") {
951 			i--;
952 		}
953 		return str.substring(0,i+1);
954 	};
955 
956 	// alias for perf
957 	var isArray = i$.isArray,
958 		isObject = i$.isObject;
959 	
960 	/**
961 	 * Merges a value object's properties into the target object. If value and target are both
962 	 * arrays then a resulting merged array is created, otherwise all object properties are
963 	 * merged from value into target.
964 	 * 
965 	 * @param {Object|Array} obj Either object or array/array-like object to merge into the target object. Must not be null.
966 	 * @param {Object|Array} [target=i$.global] The target object or array
967 	 * @type Object|Array
968 	 * @return {Object|Array} Returns the merged object target. Same type as the target object that was passed in.
969 	 * 
970 	 * @example
971 	 * Example 1:
972 	 * 
973 	 * var visuals = {
974 	 *     color: "white"
975 	 * };
976 	 * var structural = {
977 	 *     make: "sedan"
978 	 * };
979 	 * var car = {};
980 	 * i$.merge(visuals, car);
981 	 * i$.merge(structural, car);
982 	 * 
983 	 * Result:
984 	 * car = {
985 	 *     color: "white",
986 	 *     make: "sedan"
987 	 * };
988 	 * 
989 	 * @example
990 	 * Example 2:
991 	 * 
992 	 * var car = ["4 doors"];
993 	 * i$.merge(["white","sedan"], car);
994 	 * 
995 	 * Result:
996 	 * car = ["4 doors", "white", "sedan"]
997 	 */
998 	i$.merge = function(value, target, path){
999 		var path = path || [], v, c;
1000 		// if target is null, then someone called with i$.merge(obj) defaulting target to the global obj
1001 		target = target || i$.global;
1002 		
1003 		if(isArray(value) && isArray(target)) {
1004 			target.push.apply(target, value);
1005 		}
1006 		else {
1007 			for(var x in value){
1008 				if(value.hasOwnProperty(x)){
1009 					v = value[x], c = target[x];
1010 					if(c != null && ((isArray(v) && isArray(c)) || (isObject(v) && isObject(c)))) {
1011 						// c is not null or undefined, so we won't be calling merge against null
1012 						target[x] = i$.merge(v, c, path.concat(x));
1013 					}
1014 					else {
1015 						// if all else fails, just override
1016 						target[x] = v;
1017 					}
1018 				}
1019 			}
1020 		}		
1021 		return target;
1022 	};
1023 	
1024 	var RTLMap;
1025 	/**
1026 	 * Determines whether a certain locale is a right to left language.
1027 	 * 
1028 	 * @param {String} locale The locale to be tested. Must not be null.
1029 	 * @type Boolean
1030 	 * @return {Boolean} Returns true if locale is right to left, false otherwise.
1031 	 */
1032 	i$.isRTL = function(locale) {
1033 		if(!RTLMap){
1034 			RTLMap = i$.fromPath("ibmCfg.themeConfig.RTLMap");
1035 		}
1036 		var _rtl_locales = RTLMap || {"iw":1,"he":1,"ar":1};
1037 		return (locale.substring(0,2) in _rtl_locales);
1038 	};
1039 	
1040 	/**
1041 	 * END of i$/core_ext
1042 	 */
1043 })();
1044