1 /*< ilib.js */
  2 /*
  3  * ilib.js - define the ilib name space
  4  * 
  5  * Copyright © 2012-2015, JEDLSoft
  6  *
  7  * Licensed under the Apache License, Version 2.0 (the "License");
  8  * you may not use this file except in compliance with the License.
  9  * You may obtain a copy of the License at
 10  *
 11  *     http://www.apache.org/licenses/LICENSE-2.0
 12  *
 13  * Unless required by applicable law or agreed to in writing, software
 14  * distributed under the License is distributed on an "AS IS" BASIS,
 15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  *
 17  * See the License for the specific language governing permissions and
 18  * limitations under the License.
 19  */
 20 
 21 /**
 22  * @namespace The global namespace that contains general ilib functions useful
 23  * to all of ilib
 24  * 
 25  * @version "11.0.006"
 26  */
 27 var ilib = ilib || {};
 28 
 29 /** @private */
 30 ilib._ver = function() {
 31     return "11.0.006"
 32     ;
 33 };
 34 
 35 /**
 36  * Return the current version of ilib.
 37  * 
 38  * @static
 39  * @return {string} a version string for this instance of ilib
 40  */
 41 ilib.getVersion = function () {
 42 	// TODO: need some way of getting the version number under dynamic load code
 43     return ilib._ver() || "11.0"; 
 44 };
 45 
 46 /**
 47  * Place where resources and such are eventually assigned.
 48  */
 49 ilib.data = {
 50 	/** @type {{ccc:Object.<string,number>,nfd:Object.<string,string>,nfc:Object.<string,string>,nfkd:Object.<string,string>,nfkc:Object.<string,string>}} */
 51     norm: {
 52     	ccc: {},
 53     	nfd: {},
 54     	nfc: {},
 55     	nfkd: {},
 56     	nfkc: {}
 57     },
 58     zoneinfo: {
 59         "Etc/UTC":{"o":"0:0","f":"UTC"},
 60         "local":{"f":"local"}
 61     },
 62     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype: null,
 63     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_c: null,
 64     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_l: null,
 65     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_m: null,
 66     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_p: null,
 67     /** @type {null|Object.<string,Array.<Array.<number>>>} */ ctype_z: null,
 68     /** @type {null|Object.<string,Array.<Array.<number>>>} */ scriptToRange: null,
 69     /** @type {null|Object.<string,string|Object.<string|Object.<string,string>>>} */ dateformats: null,
 70     /** @type {null|Array.<string>} */ timezones: []
 71 };
 72 
 73 /*
 74 if (typeof(window) !== 'undefined') {
 75     window["ilib"] = ilib;
 76 }
 77 */
 78 
 79 // export ilib for use as a module in nodejs
 80 if (typeof(module) !== 'undefined') {
 81     
 82     module.exports.ilib = ilib;  // for backwards compatibility with older versions of ilib
 83 }
 84 
 85 /**
 86  * Sets the pseudo locale. Pseudolocalization (or pseudo-localization) is used for testing
 87  * internationalization aspects of software. Instead of translating the text of the software
 88  * into a foreign language, as in the process of localization, the textual elements of an application
 89  * are replaced with an altered version of the original language.These specific alterations make
 90  * the original words appear readable, but include the most problematic characteristics of 
 91  * the world's languages: varying length of text or characters, language direction, and so on.
 92  * Regular Latin pseudo locale: eu-ES and RTL pseudo locale: ps-AF
 93  * 
 94  * @param {string|undefined|null} localename the locale specifier for the pseudo locale
 95  */
 96 ilib.setAsPseudoLocale = function (localename) {
 97    if (localename) {
 98 	   ilib.pseudoLocales.push(localename)
 99    }
100 };
101 
102 /**
103  * Reset the list of pseudo locales back to the default single locale of zxx-XX.
104  * @static
105  */
106 ilib.clearPseudoLocales = function() {
107 	ilib.pseudoLocales = [
108         "zxx-XX",
109         "zxx-Cyrl-XX",
110         "zxx-Hans-XX",
111         "zxx-Hebr-XX"
112     ];
113 };
114 
115 ilib.clearPseudoLocales();
116 
117 /**
118  * Return the name of the platform
119  * @private
120  * @static
121  * @return {string} string naming the platform
122  */
123 ilib._getPlatform = function () {
124     if (!ilib._platform) {
125     	try {
126     		if (typeof(java.lang.Object) !== 'undefined') {
127     			ilib._platform = (typeof(process) !== 'undefined') ? "trireme" : "rhino";
128     			return ilib._platform;
129     		}
130     	} catch (e) {}
131     	
132         if (typeof(process) !== 'undefined' && typeof(module) !== 'undefined') {
133             ilib._platform = "nodejs";
134         } else if (typeof(Qt) !== 'undefined') {
135         	ilib._platform = "qt";
136         } else if (typeof(window) !== 'undefined') {
137             ilib._platform = (typeof(PalmSystem) !== 'undefined') ? "webos" : "browser";
138         } else {
139             ilib._platform = "unknown";
140         }
141     }    
142     return ilib._platform;
143 };
144 
145 /**
146  * If this ilib is running in a browser, return the name of that browser.
147  * @private
148  * @static
149  * @return {string|undefined} the name of the browser that this is running in ("firefox", "chrome", "ie", 
150  * "safari", or "opera"), or undefined if this is not running in a browser or if
151  * the browser name could not be determined 
152  */
153 ilib._getBrowser = function () {
154 	var browser = undefined;
155 	if (ilib._getPlatform() === "browser") {
156 		if (navigator && navigator.userAgent) {
157 			if (navigator.userAgent.indexOf("Firefox") > -1) {
158 				browser = "firefox";
159 			}
160 			if (navigator.userAgent.indexOf("Opera") > -1) {
161 				browser = "opera";
162 			}
163 			if (navigator.userAgent.indexOf("Chrome") > -1) {
164 				browser = "chrome";
165 			}
166 			if (navigator.userAgent.indexOf(" .NET") > -1) {
167 				browser = "ie";
168 			}
169 			if (navigator.userAgent.indexOf("Safari") > -1) {
170 				// chrome also has the string Safari in its userAgent, but the chrome case is 
171 				// already taken care of above
172 				browser = "safari";
173 			}
174 		}
175 	}
176 	return browser;
177 };
178 
179 /**
180  * Return true if the global variable is defined on this platform.
181  * @private
182  * @static
183  * @param {string} name the name of the variable to check
184  * @return {boolean} true if the global variable is defined on this platform, false otherwise
185  */
186 ilib._isGlobal = function(name) {
187     switch (ilib._getPlatform()) {
188         case "rhino":
189             var top = (function() {
190               return (typeof global === 'object') ? global : this;
191             })();
192             return typeof(top[name]) !== 'undefined';
193         case "nodejs":
194         case "trireme":
195             var root = typeof(global) !== 'undefined' ? global : this;
196             return root && typeof(root[name]) !== 'undefined';
197         case "qt":
198         	return false;
199         default:
200         	try {
201         		return window && typeof(window[name]) !== 'undefined';
202         	} catch (e) {
203         		return false;
204         	}
205     }
206 };
207 
208 /**
209  * Sets the default locale for all of ilib. This locale will be used
210  * when no explicit locale is passed to any ilib class. If the default
211  * locale is not set, ilib will attempt to use the locale of the
212  * environment it is running in, if it can find that. If not, it will
213  * default to the locale "en-US". If a type of parameter is string, 
214  * ilib will take only well-formed BCP-47 tag  <p>
215  * 
216  * 
217  * @static
218  * @param {string|undefined|null} spec the locale specifier for the default locale
219  */
220 ilib.setLocale = function (spec) {
221     if (typeof(spec) === 'string' || !spec) {
222         ilib.locale = spec;
223     }
224     // else ignore other data types, as we don't have the dependencies
225     // to look into them to find a locale
226 };
227 
228 /**
229  * Return the default locale for all of ilib if one has been set. This 
230  * locale will be used when no explicit locale is passed to any ilib 
231  * class. If the default
232  * locale is not set, ilib will attempt to use the locale of the
233  * environment it is running in, if it can find that. If not, it will
234  * default to the locale "en-US".<p>
235  * 
236  * 
237  * @static
238  * @return {string} the locale specifier for the default locale
239  */
240 ilib.getLocale = function () {
241     if (typeof(ilib.locale) !== 'string') {
242     	var plat = ilib._getPlatform();
243     	switch (plat) {
244     		case 'browser':
245             	// running in a browser
246                 ilib.locale = navigator.language.substring(0,3) + navigator.language.substring(3,5).toUpperCase();  // FF/Opera/Chrome/Webkit
247                 if (!ilib.locale) {
248                     // IE on Windows
249                     var lang = typeof(navigator.browserLanguage) !== 'undefined' ? 
250                         navigator.browserLanguage :
251                         (typeof(navigator.userLanguage) !== 'undefined' ? 
252                             navigator.userLanguage :
253                             (typeof(navigator.systemLanguage) !== 'undefined' ?
254                                 navigator.systemLanguage :
255                                 undefined));
256                     if (typeof(lang) !== 'undefined' && lang) {
257                         // for some reason, MS uses lower case region tags
258                         ilib.locale = lang.substring(0,3) + lang.substring(3,5).toUpperCase();
259                     }
260                 }
261                 break;
262     		case 'webos':
263                 // webOS
264                 if (typeof(PalmSystem.locales) !== 'undefined' && 
265                 		typeof(PalmSystem.locales.UI) != 'undefined' && 
266                 		PalmSystem.locales.UI.length > 0) {
267                     ilib.locale = PalmSystem.locales.UI;
268                 } else if (typeof(PalmSystem.locale) !== 'undefined') {
269                 	ilib.locale = PalmSystem.locale;
270                 }
271     			break;
272     		case 'rhino':
273                 if (typeof(environment) !== 'undefined' && environment.user && typeof(environment.user.language) === 'string' && environment.user.language.length > 0) {
274                 	// running under plain rhino
275                     ilib.locale = environment.user.language;
276                     if (typeof(environment.user.country) === 'string' && environment.user.country.length > 0) {
277                         ilib.locale += '-' + environment.user.country;
278                     }
279                 }
280                 break;
281     		case "trireme":
282             	// under trireme on rhino emulating nodejs
283             	var lang = process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL;
284                 // the LANG variable on unix is in the form "lang_REGION.CHARSET"
285                 // where language and region are the correct ISO codes separated by
286                 // an underscore. This translate it back to the BCP-47 form.
287                 if (lang && typeof(lang) !== 'undefined') {
288                     ilib.locale = lang.substring(0,2).toLowerCase() + '-' + lang.substring(3,5).toUpperCase();
289                 }
290             	break;
291     		case 'nodejs':
292                 // running under nodejs
293                 var lang = process.env.LANG || process.env.LC_ALL;
294                 // the LANG variable on unix is in the form "lang_REGION.CHARSET"
295                 // where language and region are the correct ISO codes separated by
296                 // an underscore. This translate it back to the BCP-47 form.
297                 if (lang && typeof(lang) !== 'undefined') {
298                     ilib.locale = lang.substring(0,2).toLowerCase() + '-' + lang.substring(3,5).toUpperCase();
299                 }
300     			break;
301     		case 'qt':
302             	// running in the Javascript engine under Qt/QML
303             	var locobj = Qt.locale();
304             	var lang = locobj.name && locobj.name.replace("_", "-") || "en-US";
305     			break;
306     	}
307         ilib.locale = typeof(ilib.locale) === 'string' ? ilib.locale : 'en-US';
308     }
309     return ilib.locale;
310 };
311 
312 /**
313  * Sets the default time zone for all of ilib. This time zone will be used when
314  * no explicit time zone is passed to any ilib class. If the default time zone
315  * is not set, ilib will attempt to use the time zone of the
316  * environment it is running in, if it can find that. If not, it will
317  * default to the the UTC zone "Etc/UTC".<p>
318  * 
319  * 
320  * @static
321  * @param {string} tz the name of the time zone to set as the default time zone
322  */
323 ilib.setTimeZone = function (tz) {
324     ilib.tz = tz || ilib.tz;
325 };
326 
327 /**
328  * Return the default time zone for all of ilib if one has been set. This 
329  * time zone will be used when no explicit time zone is passed to any ilib 
330  * class. If the default time zone
331  * is not set, ilib will attempt to use the locale of the
332  * environment it is running in, if it can find that. If not, it will
333  * default to the the zone "local".<p>
334  * 
335  * 
336  * @static
337  * @return {string} the default time zone for ilib
338  */
339 ilib.getTimeZone = function() {
340     if (typeof(ilib.tz) === 'undefined') {
341         if (typeof(navigator) !== 'undefined' && typeof(navigator.timezone) !== 'undefined') {
342             // running in a browser
343             if (navigator.timezone.length > 0) {
344                 ilib.tz = navigator.timezone;
345             }
346         } else if (typeof(PalmSystem) !== 'undefined' && typeof(PalmSystem.timezone) !== 'undefined') {
347             // running in webkit on webOS
348             if (PalmSystem.timezone.length > 0) {
349                 ilib.tz = PalmSystem.timezone;
350             }
351         } else if (typeof(environment) !== 'undefined' && typeof(environment.user) !== 'undefined') {
352             // running under rhino
353             if (typeof(environment.user.timezone) !== 'undefined' && environment.user.timezone.length > 0) {
354                 ilib.tz = environment.user.timezone;
355             }
356         } else if (typeof(process) !== 'undefined' && typeof(process.env) !== 'undefined') {
357             // running in nodejs
358             if (process.env.TZ && typeof(process.env.TZ) !== "undefined") {
359                 ilib.tz = process.env.TZ;
360             }
361         }
362         
363         ilib.tz = ilib.tz || "local"; 
364     }
365 
366     return ilib.tz;
367 };
368 
369 /**
370  * @class
371  * Defines the interface for the loader class for ilib. The main method of the
372  * loader object is loadFiles(), which loads a set of requested locale data files
373  * from where-ever it is stored.
374  * @interface
375  */
376 ilib.Loader = function() {};
377 
378 /**
379  * Load a set of files from where-ever it is stored.<p>
380  * 
381  * This is the main function define a callback function for loading missing locale 
382  * data or resources.
383  * If this copy of ilib is assembled without including the required locale data
384  * or resources, then that data can be lazy loaded dynamically when it is 
385  * needed by calling this method. Each ilib class will first
386  * check for the existence of data under ilib.data, and if it is not there, 
387  * it will attempt to load it by calling this method of the laoder, and then place
388  * it there.<p>
389  * 
390  * Suggested implementations of this method might load files 
391  * directly from disk under nodejs or rhino, or within web pages, to load 
392  * files from the server with XHR calls.<p>
393  * 
394  * The first parameter to this method, paths, is an array of relative paths within 
395  * the ilib dir structure for the 
396  * requested data. These paths will already have the locale spec integrated 
397  * into them, so no further tweaking needs to happen to load the data. Simply
398  * load the named files. The second
399  * parameter tells the loader whether to load the files synchronously or asynchronously.
400  * If the sync parameters is false, then the onLoad function must also be specified.
401  * The third parameter gives extra parameters to the loader passed from the calling
402  * code. This may contain any property/value pairs.  The last parameter, callback,
403  * is a callback function to call when all of the data is finishing loading. Make
404  * sure to call the callback with the context of "this" so that the caller has their 
405  * context back again.<p>
406  * 
407  * The loader function must be able to operate either synchronously or asychronously. 
408  * If the loader function is called with an undefined callback function, it is
409  * expected to load the data synchronously, convert it to javascript
410  * objects, and return the array of json objects as the return value of the 
411  * function. If the loader 
412  * function is called with a callback function, it may load the data 
413  * synchronously or asynchronously (doesn't matter which) as long as it calls
414  * the callback function with the data converted to a javascript objects
415  * when it becomes available. If a particular file could not be loaded, the 
416  * loader function should put undefined into the corresponding entry in the
417  * results array. 
418  * Note that it is important that all the data is loaded before the callback
419  * is called.<p>
420  * 
421  * An example implementation for nodejs might be:
422  * 
423  * <pre>
424  *  * 
425  * var myLoader = function() {};
426  * myLoader.prototype = new Loader();
427  * myLoader.prototype.constructor = myLoader;
428  * myLoader.prototype.loadFiles = function(paths, sync, params, callback) {
429  *    if (sync) {
430  *        var ret = [];
431  *        // synchronous load -- just return the result
432  *        paths.forEach(function (path) {
433  *            var json = fs.readFileSync(path, "utf-8");
434  *            ret.push(json ? JSON.parse(json) : undefined);
435  *        });
436  *        
437  *        return ret;
438  *    }
439  *    this.callback = callback;
440  *
441  *    // asynchronous
442  *    this.results = [];
443  *    this._loadFilesAsync(paths);
444  * }
445  * myLoader.prototype._loadFilesAsync = function (paths) {
446  *    if (paths.length > 0) {
447  *        var file = paths.shift();
448  *        fs.readFile(file, "utf-8", function(err, json) {
449  *            this.results.push(err ? undefined : JSON.parse(json));
450  *            // call self recursively so that the callback is only called at the end
451  *            // when all the files are loaded sequentially
452  *            if (paths.length > 0) {
453  *                this._loadFilesAsync(paths);
454  *            } else {
455  *                this.callback(this.results);
456  *            }
457  *        });
458  *     }
459  * }
460  * 
461  * // bind to "this" so that "this" is relative to your own instance
462  * ilib.setLoaderCallback(new myLoader());
463  * </pre>
464 
465  * @param {Array.<string>} paths An array of paths to load from wherever the files are stored 
466  * @param {Boolean} sync if true, load the files synchronously, and false means asynchronously
467  * @param {Object} params an object with any extra parameters for the loader. These can be 
468  * anything. The caller of the ilib class passes these parameters in. Presumably, the code that
469  * calls ilib and the code that provides the loader are together and can have a private 
470  * agreement between them about what the parameters should contain.
471  * @param {function(Object)} callback function to call when the files are all loaded. The 
472  * parameter of the callback function is the contents of the files.
473  */
474 ilib.Loader.prototype.loadFiles = function (paths, sync, params, callback) {};
475 
476 /**
477  * Return all files available for loading using this loader instance.
478  * This method returns an object where the properties are the paths to
479  * directories where files are loaded from and the values are an array
480  * of strings containing the relative paths under the directory of each
481  * file that can be loaded.<p>
482  * 
483  * Example:
484  *  <pre>
485  *  {
486  *      "/usr/share/javascript/ilib/locale": [
487  *          "dateformats.json",
488  *          "aa/dateformats.json",
489  *          "af/dateformats.json",
490  *          "agq/dateformats.json",
491  *          "ak/dateformats.json",
492  *          ...
493  *          "zxx/dateformats.json"
494  *      ]
495  *  }
496  *  </pre>
497  * @returns {Object} a hash containing directory names and
498  * paths to file that can be loaded by this loader 
499  */
500 ilib.Loader.prototype.listAvailableFiles = function() {};
501 
502 /**
503  * Return true if the file in the named path is available for loading using
504  * this loader. The path may be given as an absolute path, in which case
505  * only that file is checked, or as a relative path, in which case, the
506  * relative path may appear underneath any of the directories that the loader
507  * knows about.
508  * @returns {boolean} true if the file in the named path is available for loading, and
509  * false otherwise
510  */
511 ilib.Loader.prototype.isAvailable = function(path) {};
512 
513 /**
514  * Set the custom loader used to load ilib's locale data in your environment. 
515  * The instance passed in must implement the Loader interface. See the
516  * Loader class documentation for more information about loaders. 
517  * 
518  * @static
519  * @param {ilib.Loader} loader class to call to access the requested data.
520  * @return {boolean} true if the loader was installed correctly, or false
521  * if not
522  */
523 ilib.setLoaderCallback = function(loader) {
524     // only a basic check
525     if ((typeof(loader) === 'object' && typeof(loader.loadFiles) === 'function') || 
526             typeof(loader) === 'function' || typeof(loader) === 'undefined') {
527         //console.log("setting callback loader to " + (loader ? loader.name : "undefined"));
528         ilib._load = loader;
529         return true;
530     }
531     return false;
532 };
533 
534 /**
535  * Return the custom Loader instance currently in use with this instance 
536  * of ilib. If there is no loader, this method returns undefined.
537  * 
538  * @protected
539  * @static
540  * @return {ilib.Loader|undefined} the loader instance currently in use, or 
541  * undefined if there is no such loader
542  */
543 ilib.getLoader = function() {
544 	return ilib._load;
545 };
546 
547 /**
548  * Test whether an object in an javascript array. 
549  * 
550  * @static
551  * @param {*} object The object to test
552  * @return {boolean} return true if the object is an array
553  * and false otherwise
554  */
555 ilib.isArray = function(object) {
556 	var o;
557 	if (typeof(object) === 'object') {
558 		o = /** @type {Object|null|undefined} */ object;
559 		return Object.prototype.toString.call(o) === '[object Array]';
560 	}
561 	return false; 
562 };
563 
564 /**
565  * Extend object1 by mixing in everything from object2 into it. The objects
566  * are deeply extended, meaning that this method recursively descends the
567  * tree in the objects and mixes them in at each level. Arrays are extended
568  * by concatenating the elements of object2 onto those of object1.  
569  * 
570  * @static
571  * @param {Object} object1 the target object to extend
572  * @param {Object=} object2 the object to mix in to object1
573  * @return {Object} returns object1
574  */
575 ilib.extend = function (object1, object2) {
576 	var prop = undefined;
577 	if (object2) {
578 		for (prop in object2) {
579 			// don't extend object with undefined or functions
580 			if (prop && typeof(object2[prop]) !== 'undefined' && typeof(object2[prop]) !== "function") {
581 				if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
582 					//console.log("Merging array prop " + prop);
583 					object1[prop] = object1[prop].concat(object2[prop]);
584 				} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
585 					//console.log("Merging object prop " + prop);
586 					if (prop !== "ilib") {
587 						object1[prop] = ilib.extend(object1[prop], object2[prop]);
588 					}
589 				} else {
590 					//console.log("Copying prop " + prop);
591 					// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
592 					object1[prop] = object2[prop];
593 				}
594 			}
595 		}
596 	}
597 	return object1;
598 };
599 
600 ilib.extend2 = function (object1, object2) {
601 	var prop = undefined;
602 	if (object2) {
603 		for (prop in object2) {
604 			// don't extend object with undefined or functions
605 			if (prop && typeof(object2[prop]) !== 'undefined') {
606 				if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
607 					//console.log("Merging array prop " + prop);
608 					object1[prop] = object1[prop].concat(object2[prop]);
609 				} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
610 					//console.log("Merging object prop " + prop);
611 					if (prop !== "ilib") {
612 						object1[prop] = ilib.extend2(object1[prop], object2[prop]);
613 					}
614 				} else {
615 					//console.log("Copying prop " + prop);
616 					// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
617 					object1[prop] = object2[prop];
618 				}
619 			}
620 		}
621 	}
622 	return object1;
623 };
624 
625 /**
626  * If Function.prototype.bind does not exist in this JS engine, this
627  * function reimplements it in terms of older JS functions.
628  * bind() doesn't exist in many older browsers.
629  * 
630  * @static
631  * @param {Object} scope object that the method should operate on
632  * @param {function(...)} method method to call
633  * @return {function(...)|undefined} function that calls the given method 
634  * in the given scope with all of its arguments properly attached, or
635  * undefined if there was a problem with the arguments
636  */
637 ilib.bind = function(scope, method/*, bound arguments*/){
638 	if (!scope || !method) {
639 		return undefined;
640 	}
641 	
642 	/** @protected 
643 	 * @param {Arguments} inArrayLike
644 	 * @param {number=} inOffset
645 	 */
646 	function cloneArray(inArrayLike, inOffset) {
647 		var arr = [];
648 		for(var i = inOffset || 0, l = inArrayLike.length; i<l; i++){
649 			arr.push(inArrayLike[i]);
650 		}
651 		return arr;
652 	}
653 
654 	if (typeof(method) === 'function') {
655 		var func, args = cloneArray(arguments, 2);
656 		if (typeof(method.bind) === 'function') {
657 			func = method.bind.apply(method, [scope].concat(args));
658 		} else {
659 			func = function() {
660 				var nargs = cloneArray(arguments);
661 				// invoke with collected args
662 				return method.apply(scope, args.concat(nargs));
663 			};
664 		}
665 		return func;
666 	}
667 	return undefined;
668 };
669 
670 /**
671  * @private
672  */
673 ilib._dyncode = false;
674 
675 /**
676  * Return true if this copy of ilib is using dynamically loaded code. It returns
677  * false for pre-assembled code.
678  * 
679  * @static
680  * @return {boolean} true if this ilib uses dynamically loaded code, and false otherwise
681  */
682 ilib.isDynCode = function() {
683 	return ilib._dyncode;
684 };
685 
686 /**
687  * @private
688  */
689 ilib._dyndata = false;
690 
691 /**
692  * Return true if this copy of ilib is using dynamically loaded locale data. It returns
693  * false for pre-assembled data.
694  * 
695  * @static
696  * @return {boolean} true if this ilib uses dynamically loaded locale data, and false otherwise
697  */
698 ilib.isDynData = function() {
699 	return ilib._dyndata;
700 };
701 
702 ilib._loadtime = new Date().getTime();
703 /*< JSUtils.js */
704 /*
705  * JSUtils.js - Misc utilities to work around Javascript engine differences
706  * 
707  * Copyright © 2013-2015, JEDLSoft
708  *
709  * Licensed under the Apache License, Version 2.0 (the "License");
710  * you may not use this file except in compliance with the License.
711  * You may obtain a copy of the License at
712  *
713  *     http://www.apache.org/licenses/LICENSE-2.0
714  *
715  * Unless required by applicable law or agreed to in writing, software
716  * distributed under the License is distributed on an "AS IS" BASIS,
717  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
718  *
719  * See the License for the specific language governing permissions and
720  * limitations under the License.
721  */
722 
723 // !depends ilib.js
724 
725 
726 var JSUtils = {};
727 
728 /**
729  * Perform a shallow copy of the source object to the target object. This only 
730  * copies the assignments of the source properties to the target properties, 
731  * but not recursively from there.<p>
732  * 
733  * 
734  * @static
735  * @param {Object} source the source object to copy properties from
736  * @param {Object} target the target object to copy properties into
737  */
738 JSUtils.shallowCopy = function (source, target) {
739 	var prop = undefined;
740 	if (source && target) {
741 		for (prop in source) {
742 			if (prop !== undefined && typeof(source[prop]) !== 'undefined') {
743 				target[prop] = source[prop];
744 			}
745 		}
746 	}
747 };
748 
749 /**
750  * Perform a recursive deep copy from the "from" object to the "deep" object.
751  * 
752  * @static
753  * @param {Object} from the object to copy from
754  * @param {Object} to the object to copy to
755  * @return {Object} a reference to the the "to" object
756  */
757 JSUtils.deepCopy = function(from, to) {
758 	var prop;
759 
760 	for (prop in from) {
761 		if (prop) {
762 			if (typeof(from[prop]) === 'object') {
763 				to[prop] = {};
764 				JSUtils.deepCopy(from[prop], to[prop]);
765 			} else {
766 				to[prop] = from[prop];
767 			}
768 		}
769 	}
770 	return to;
771 };
772 
773 /**
774  * Map a string to the given set of alternate characters. If the target set
775  * does not contain a particular character in the input string, then that
776  * character will be copied to the output unmapped.
777  * 
778  * @static
779  * @param {string} str a string to map to an alternate set of characters
780  * @param {Array.<string>|Object} map a mapping to alternate characters
781  * @return {string} the source string where each character is mapped to alternate characters
782  */
783 JSUtils.mapString = function (str, map) {
784 	var mapped = "";
785 	if (map && str) {
786 		for (var i = 0; i < str.length; i++) {
787 			var c = str.charAt(i); // TODO use a char iterator?
788 			mapped += map[c] || c; 
789 		}
790 	} else {
791 		mapped = str;
792 	}
793 	return mapped;
794 };
795 
796 /**
797  * Check if an object is a member of the given array. If this javascript engine
798  * support indexOf, it is used directly. Otherwise, this function implements it
799  * itself. The idea is to make sure that you can use the quick indexOf if it is
800  * available, but use a slower implementation in older engines as well.
801  * 
802  * @static
803  * @param {Array.<Object>} array array to search
804  * @param {Object} obj object being sought. This should be of the same type as the
805  * members of the array being searched. If not, this function will not return
806  * any results.
807  * @return {number} index of the object in the array, or -1 if it is not in the array.
808  */
809 JSUtils.indexOf = function(array, obj) {
810 	if (!array || !obj) {
811 		return -1;
812 	}
813 	if (typeof(array.indexOf) === 'function') {
814 		return array.indexOf(obj);
815 	} else {
816 		for (var i = 0; i < array.length; i++) {
817 	        if (array[i] === obj) {
818 	            return i;
819 	        }
820 	    }
821 	    return -1;
822 	}
823 };
824 
825 /**
826  * Convert a string into the hexadecimal representation
827  * of the Unicode characters in that string.
828  * 
829  * @static
830  * @param {string} string The string to convert
831  * @param {number=} limit the number of digits to use to represent the character (1 to 8)
832  * @return {string} a hexadecimal representation of the
833  * Unicode characters in the input string
834  */
835 JSUtils.toHexString = function(string, limit) {
836 	var i, 
837 		result = "", 
838 		lim = (limit && limit < 9) ? limit : 4;
839 	
840 	if (!string) {
841 		return "";
842 	}
843 	for (i = 0; i < string.length; i++) {
844 		var ch = string.charCodeAt(i).toString(16);
845 		result += "00000000".substring(0, lim-ch.length) + ch;
846 	}
847 	return result.toUpperCase();
848 };
849 
850 /**
851  * Test whether an object in a Javascript Date. 
852  * 
853  * @static
854  * @param {*} object The object to test
855  * @return {boolean} return true if the object is a Date
856  * and false otherwise
857  */
858 JSUtils.isDate = function(object) {
859 	var o;
860 	if (typeof(object) === 'object') {
861 		o = /** @type {Object|null|undefined} */ object;
862 		return Object.prototype.toString.call(o) === '[object Date]';
863 	}
864 	return false; 
865 };
866 
867 /**
868  * Merge the properties of object2 into object1 in a deep manner and return a merged
869  * object. If the property exists in both objects, the value in object2 will overwrite 
870  * the value in object1. If a property exists in object1, but not in object2, its value
871  * will not be touched. If a property exists in object2, but not in object1, it will be 
872  * added to the merged result.<p>
873  * 
874  * Name1 and name2 are for creating debug output only. They are not necessary.<p>
875  * 
876  * 
877  * @static
878  * @param {*} object1 the object to merge into
879  * @param {*} object2 the object to merge
880  * @param {boolean=} replace if true, replace the array elements in object1 with those in object2.
881  * If false, concatenate array elements in object1 with items in object2.
882  * @param {string=} name1 name of the object being merged into
883  * @param {string=} name2 name of the object being merged in
884  * @return {Object} the merged object
885  */
886 JSUtils.merge = function (object1, object2, replace, name1, name2) {
887 	var prop = undefined,
888 		newObj = {};
889 	for (prop in object1) {
890 		if (prop && typeof(object1[prop]) !== 'undefined') {
891 			newObj[prop] = object1[prop];
892 		}
893 	}
894 	for (prop in object2) {
895 		if (prop && typeof(object2[prop]) !== 'undefined') {
896 			if (ilib.isArray(object1[prop]) && ilib.isArray(object2[prop])) {
897 				if (typeof(replace) !== 'boolean' || !replace) {
898 					newObj[prop] = [].concat(object1[prop]);
899 					newObj[prop] = newObj[prop].concat(object2[prop]);
900 				} else {
901 					newObj[prop] = object2[prop];
902 				}
903 			} else if (typeof(object1[prop]) === 'object' && typeof(object2[prop]) === 'object') {
904 				newObj[prop] = JSUtils.merge(object1[prop], object2[prop], replace);
905 			} else {
906 				// for debugging. Used to determine whether or not json files are overriding their parents unnecessarily
907 				if (name1 && name2 && newObj[prop] == object2[prop]) {
908 					console.log("Property " + prop + " in " + name1 + " is being overridden by the same value in " + name2);
909 				}
910 				newObj[prop] = object2[prop];
911 			}
912 		}
913 	}
914 	return newObj;
915 };
916 
917 /**
918  * Return true if the given object has no properties.<p>
919  * 
920  * 
921  * @static
922  * @param {Object} obj the object to check
923  * @return {boolean} true if the given object has no properties, false otherwise
924  */
925 JSUtils.isEmpty = function (obj) {
926 	var prop = undefined;
927 	
928 	if (!obj) {
929 		return true;
930 	}
931 	
932 	for (prop in obj) {
933 		if (prop && typeof(obj[prop]) !== 'undefined') {
934 			return false;
935 		}
936 	}
937 	return true;
938 };
939 
940 /**
941  * @static
942  */
943 JSUtils.hashCode = function(obj) {
944 	var hash = 0;
945 	
946 	function addHash(hash, newValue) {
947 		// co-prime numbers creates a nicely distributed hash
948 		hash *= 65543;
949 		hash += newValue;
950 		hash %= 2147483647; 
951 		return hash;
952 	}
953 	
954 	function stringHash(str) {
955 		var hash = 0;
956 		for (var i = 0; i < str.length; i++) {
957 			hash = addHash(hash, str.charCodeAt(i));
958 		}
959 		return hash;
960 	}
961 	
962 	switch (typeof(obj)) {
963 		case 'undefined':
964 			hash = 0;
965 			break;
966 		case 'string':
967 			hash = stringHash(obj);
968 			break;
969 		case 'function':
970 		case 'number':
971 		case 'xml':
972 			hash = stringHash(String(obj));
973 			break;
974 		case 'boolean':
975 			hash = obj ? 1 : 0;
976 			break;
977 		case 'object':
978 			var props = [];
979 			for (var p in obj) {
980 				if (obj.hasOwnProperty(p)) {
981 					props.push(p);
982 				}
983 			}
984 			// make sure the order of the properties doesn't matter
985 			props.sort();
986 			for (var i = 0; i < props.length; i++) {
987 				hash = addHash(hash, stringHash(props[i]));
988 				hash = addHash(hash, JSUtils.hashCode(obj[props[i]]));
989 			}
990 			break;
991 	}
992 	
993 	return hash;
994 };
995 
996 
997 
998 
999 /*< Locale.js */
1000 /*
1001  * Locale.js - Locale specifier definition
1002  * 
1003  * Copyright © 2012-2015, JEDLSoft
1004  *
1005  * Licensed under the Apache License, Version 2.0 (the "License");
1006  * you may not use this file except in compliance with the License.
1007  * You may obtain a copy of the License at
1008  *
1009  *     http://www.apache.org/licenses/LICENSE-2.0
1010  *
1011  * Unless required by applicable law or agreed to in writing, software
1012  * distributed under the License is distributed on an "AS IS" BASIS,
1013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1014  *
1015  * See the License for the specific language governing permissions and
1016  * limitations under the License.
1017  */
1018 
1019 // !depends ilib.js JSUtils.js
1020 
1021 
1022 /**
1023  * @class
1024  * Create a new locale instance. Locales are specified either with a specifier string 
1025  * that follows the BCP-47 convention (roughly: "language-region-script-variant") or 
1026  * with 4 parameters that specify the language, region, variant, and script individually.<p>
1027  * 
1028  * The language is given as an ISO 639-1 two-letter, lower-case language code. You
1029  * can find a full list of these codes at 
1030  * <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes</a><p>
1031  * 
1032  * The region is given as an ISO 3166-1 two-letter, upper-case region code. You can
1033  * find a full list of these codes at 
1034  * <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2</a>.<p>
1035  * 
1036  * The variant is any string that does not contain a dash which further differentiates
1037  * locales from each other.<p>
1038  * 
1039  * The script is given as the ISO 15924 four-letter script code. In some locales,
1040  * text may be validly written in more than one script. For example, Serbian is often
1041  * written in both Latin and Cyrillic, though not usually mixed together. You can find a
1042  * full list of these codes at 
1043  * <a href="http://en.wikipedia.org/wiki/ISO_15924#List_of_codes">http://en.wikipedia.org/wiki/ISO_15924#List_of_codes</a>.<p>
1044  * 
1045  * As an example in ilib, the script can be used in the date formatter. Dates formatted 
1046  * in Serbian could have day-of-week names or month names written in the Latin
1047  * or Cyrillic script. Often one script is default such that sr-SR-Latn is the same
1048  * as sr-SR so the script code "Latn" can be left off of the locale spec.<p> 
1049  * 
1050  * Each part is optional, and an empty string in the specifier before or after a 
1051  * dash or as a parameter to the constructor denotes an unspecified value. In this
1052  * case, many of the ilib functions will treat the locale as generic. For example
1053  * the locale "en-" is equivalent to "en" and to "en--" and denotes a locale
1054  * of "English" with an unspecified region and variant, which typically matches
1055  * any region or variant.<p>
1056  * 
1057  * Without any arguments to the constructor, this function returns the locale of
1058  * the host Javascript engine.<p>
1059  * 
1060  * 
1061  * @constructor
1062  * @param {?string|Locale=} language the ISO 639 2-letter code for the language, or a full 
1063  * locale spec in BCP-47 format, or another Locale instance to copy from
1064  * @param {string=} region the ISO 3166 2-letter code for the region
1065  * @param {string=} variant the name of the variant of this locale, if any
1066  * @param {string=} script the ISO 15924 code of the script for this locale, if any
1067  */
1068 var Locale = function(language, region, variant, script) {
1069 	if (typeof(region) === 'undefined') {
1070 		var spec = language || ilib.getLocale();
1071 		if (typeof(spec) === 'string') {
1072 			var parts = spec.split('-');
1073 	        for ( var i = 0; i < parts.length; i++ ) {
1074 	        	if (Locale._isLanguageCode(parts[i])) {
1075 	    			/** 
1076 	    			 * @private
1077 	    			 * @type {string|undefined}
1078 	    			 */
1079 	        		this.language = parts[i];
1080 	        	} else if (Locale._isRegionCode(parts[i])) {
1081 	    			/** 
1082 	    			 * @private
1083 	    			 * @type {string|undefined}
1084 	    			 */
1085 	        		this.region = parts[i];
1086 	        	} else if (Locale._isScriptCode(parts[i])) {
1087 	    			/** 
1088 	    			 * @private
1089 	    			 * @type {string|undefined}
1090 	    			 */
1091 	        		this.script = parts[i];
1092 	        	} else {
1093 	    			/** 
1094 	    			 * @private
1095 	    			 * @type {string|undefined}
1096 	    			 */
1097 	        		this.variant = parts[i];
1098 	        	}
1099 	        }
1100 	        this.language = this.language || undefined;
1101 	        this.region = this.region || undefined;
1102 	        this.script = this.script || undefined;
1103 	        this.variant = this.variant || undefined;
1104 		} else if (typeof(spec) === 'object') {
1105 	        this.language = spec.language || undefined;
1106 	        this.region = spec.region || undefined;
1107 	        this.script = spec.script || undefined;
1108 	        this.variant = spec.variant || undefined;
1109 		}
1110 	} else {
1111 		if (language) {
1112 			language = language.trim();
1113 			this.language = language.length > 0 ? language.toLowerCase() : undefined;
1114 		} else {
1115 			this.language = undefined;
1116 		}
1117 		if (region) {
1118 			region = region.trim();
1119 			this.region = region.length > 0 ? region.toUpperCase() : undefined;
1120 		} else {
1121 			this.region = undefined;
1122 		}
1123 		if (variant) {
1124 			variant = variant.trim();
1125 			this.variant = variant.length > 0 ? variant : undefined;
1126 		} else {
1127 			this.variant = undefined;
1128 		}
1129 		if (script) {
1130 			script = script.trim();
1131 			this.script = script.length > 0 ? script : undefined;
1132 		} else {
1133 			this.script = undefined;
1134 		}
1135 	}
1136 	this._genSpec();
1137 };
1138 
1139 // from http://en.wikipedia.org/wiki/ISO_3166-1
1140 Locale.a2toa3regmap = {
1141 	"AF": "AFG",
1142 	"AX": "ALA",
1143 	"AL": "ALB",
1144 	"DZ": "DZA",
1145 	"AS": "ASM",
1146 	"AD": "AND",
1147 	"AO": "AGO",
1148 	"AI": "AIA",
1149 	"AQ": "ATA",
1150 	"AG": "ATG",
1151 	"AR": "ARG",
1152 	"AM": "ARM",
1153 	"AW": "ABW",
1154 	"AU": "AUS",
1155 	"AT": "AUT",
1156 	"AZ": "AZE",
1157 	"BS": "BHS",
1158 	"BH": "BHR",
1159 	"BD": "BGD",
1160 	"BB": "BRB",
1161 	"BY": "BLR",
1162 	"BE": "BEL",
1163 	"BZ": "BLZ",
1164 	"BJ": "BEN",
1165 	"BM": "BMU",
1166 	"BT": "BTN",
1167 	"BO": "BOL",
1168 	"BQ": "BES",
1169 	"BA": "BIH",
1170 	"BW": "BWA",
1171 	"BV": "BVT",
1172 	"BR": "BRA",
1173 	"IO": "IOT",
1174 	"BN": "BRN",
1175 	"BG": "BGR",
1176 	"BF": "BFA",
1177 	"BI": "BDI",
1178 	"KH": "KHM",
1179 	"CM": "CMR",
1180 	"CA": "CAN",
1181 	"CV": "CPV",
1182 	"KY": "CYM",
1183 	"CF": "CAF",
1184 	"TD": "TCD",
1185 	"CL": "CHL",
1186 	"CN": "CHN",
1187 	"CX": "CXR",
1188 	"CC": "CCK",
1189 	"CO": "COL",
1190 	"KM": "COM",
1191 	"CG": "COG",
1192 	"CD": "COD",
1193 	"CK": "COK",
1194 	"CR": "CRI",
1195 	"CI": "CIV",
1196 	"HR": "HRV",
1197 	"CU": "CUB",
1198 	"CW": "CUW",
1199 	"CY": "CYP",
1200 	"CZ": "CZE",
1201 	"DK": "DNK",
1202 	"DJ": "DJI",
1203 	"DM": "DMA",
1204 	"DO": "DOM",
1205 	"EC": "ECU",
1206 	"EG": "EGY",
1207 	"SV": "SLV",
1208 	"GQ": "GNQ",
1209 	"ER": "ERI",
1210 	"EE": "EST",
1211 	"ET": "ETH",
1212 	"FK": "FLK",
1213 	"FO": "FRO",
1214 	"FJ": "FJI",
1215 	"FI": "FIN",
1216 	"FR": "FRA",
1217 	"GF": "GUF",
1218 	"PF": "PYF",
1219 	"TF": "ATF",
1220 	"GA": "GAB",
1221 	"GM": "GMB",
1222 	"GE": "GEO",
1223 	"DE": "DEU",
1224 	"GH": "GHA",
1225 	"GI": "GIB",
1226 	"GR": "GRC",
1227 	"GL": "GRL",
1228 	"GD": "GRD",
1229 	"GP": "GLP",
1230 	"GU": "GUM",
1231 	"GT": "GTM",
1232 	"GG": "GGY",
1233 	"GN": "GIN",
1234 	"GW": "GNB",
1235 	"GY": "GUY",
1236 	"HT": "HTI",
1237 	"HM": "HMD",
1238 	"VA": "VAT",
1239 	"HN": "HND",
1240 	"HK": "HKG",
1241 	"HU": "HUN",
1242 	"IS": "ISL",
1243 	"IN": "IND",
1244 	"ID": "IDN",
1245 	"IR": "IRN",
1246 	"IQ": "IRQ",
1247 	"IE": "IRL",
1248 	"IM": "IMN",
1249 	"IL": "ISR",
1250 	"IT": "ITA",
1251 	"JM": "JAM",
1252 	"JP": "JPN",
1253 	"JE": "JEY",
1254 	"JO": "JOR",
1255 	"KZ": "KAZ",
1256 	"KE": "KEN",
1257 	"KI": "KIR",
1258 	"KP": "PRK",
1259 	"KR": "KOR",
1260 	"KW": "KWT",
1261 	"KG": "KGZ",
1262 	"LA": "LAO",
1263 	"LV": "LVA",
1264 	"LB": "LBN",
1265 	"LS": "LSO",
1266 	"LR": "LBR",
1267 	"LY": "LBY",
1268 	"LI": "LIE",
1269 	"LT": "LTU",
1270 	"LU": "LUX",
1271 	"MO": "MAC",
1272 	"MK": "MKD",
1273 	"MG": "MDG",
1274 	"MW": "MWI",
1275 	"MY": "MYS",
1276 	"MV": "MDV",
1277 	"ML": "MLI",
1278 	"MT": "MLT",
1279 	"MH": "MHL",
1280 	"MQ": "MTQ",
1281 	"MR": "MRT",
1282 	"MU": "MUS",
1283 	"YT": "MYT",
1284 	"MX": "MEX",
1285 	"FM": "FSM",
1286 	"MD": "MDA",
1287 	"MC": "MCO",
1288 	"MN": "MNG",
1289 	"ME": "MNE",
1290 	"MS": "MSR",
1291 	"MA": "MAR",
1292 	"MZ": "MOZ",
1293 	"MM": "MMR",
1294 	"NA": "NAM",
1295 	"NR": "NRU",
1296 	"NP": "NPL",
1297 	"NL": "NLD",
1298 	"NC": "NCL",
1299 	"NZ": "NZL",
1300 	"NI": "NIC",
1301 	"NE": "NER",
1302 	"NG": "NGA",
1303 	"NU": "NIU",
1304 	"NF": "NFK",
1305 	"MP": "MNP",
1306 	"NO": "NOR",
1307 	"OM": "OMN",
1308 	"PK": "PAK",
1309 	"PW": "PLW",
1310 	"PS": "PSE",
1311 	"PA": "PAN",
1312 	"PG": "PNG",
1313 	"PY": "PRY",
1314 	"PE": "PER",
1315 	"PH": "PHL",
1316 	"PN": "PCN",
1317 	"PL": "POL",
1318 	"PT": "PRT",
1319 	"PR": "PRI",
1320 	"QA": "QAT",
1321 	"RE": "REU",
1322 	"RO": "ROU",
1323 	"RU": "RUS",
1324 	"RW": "RWA",
1325 	"BL": "BLM",
1326 	"SH": "SHN",
1327 	"KN": "KNA",
1328 	"LC": "LCA",
1329 	"MF": "MAF",
1330 	"PM": "SPM",
1331 	"VC": "VCT",
1332 	"WS": "WSM",
1333 	"SM": "SMR",
1334 	"ST": "STP",
1335 	"SA": "SAU",
1336 	"SN": "SEN",
1337 	"RS": "SRB",
1338 	"SC": "SYC",
1339 	"SL": "SLE",
1340 	"SG": "SGP",
1341 	"SX": "SXM",
1342 	"SK": "SVK",
1343 	"SI": "SVN",
1344 	"SB": "SLB",
1345 	"SO": "SOM",
1346 	"ZA": "ZAF",
1347 	"GS": "SGS",
1348 	"SS": "SSD",
1349 	"ES": "ESP",
1350 	"LK": "LKA",
1351 	"SD": "SDN",
1352 	"SR": "SUR",
1353 	"SJ": "SJM",
1354 	"SZ": "SWZ",
1355 	"SE": "SWE",
1356 	"CH": "CHE",
1357 	"SY": "SYR",
1358 	"TW": "TWN",
1359 	"TJ": "TJK",
1360 	"TZ": "TZA",
1361 	"TH": "THA",
1362 	"TL": "TLS",
1363 	"TG": "TGO",
1364 	"TK": "TKL",
1365 	"TO": "TON",
1366 	"TT": "TTO",
1367 	"TN": "TUN",
1368 	"TR": "TUR",
1369 	"TM": "TKM",
1370 	"TC": "TCA",
1371 	"TV": "TUV",
1372 	"UG": "UGA",
1373 	"UA": "UKR",
1374 	"AE": "ARE",
1375 	"GB": "GBR",
1376 	"US": "USA",
1377 	"UM": "UMI",
1378 	"UY": "URY",
1379 	"UZ": "UZB",
1380 	"VU": "VUT",
1381 	"VE": "VEN",
1382 	"VN": "VNM",
1383 	"VG": "VGB",
1384 	"VI": "VIR",
1385 	"WF": "WLF",
1386 	"EH": "ESH",
1387 	"YE": "YEM",
1388 	"ZM": "ZMB",
1389 	"ZW": "ZWE"
1390 };
1391 
1392 
1393 Locale.a1toa3langmap = {
1394 	"ab": "abk",
1395 	"aa": "aar",
1396 	"af": "afr",
1397 	"ak": "aka",
1398 	"sq": "sqi",
1399 	"am": "amh",
1400 	"ar": "ara",
1401 	"an": "arg",
1402 	"hy": "hye",
1403 	"as": "asm",
1404 	"av": "ava",
1405 	"ae": "ave",
1406 	"ay": "aym",
1407 	"az": "aze",
1408 	"bm": "bam",
1409 	"ba": "bak",
1410 	"eu": "eus",
1411 	"be": "bel",
1412 	"bn": "ben",
1413 	"bh": "bih",
1414 	"bi": "bis",
1415 	"bs": "bos",
1416 	"br": "bre",
1417 	"bg": "bul",
1418 	"my": "mya",
1419 	"ca": "cat",
1420 	"ch": "cha",
1421 	"ce": "che",
1422 	"ny": "nya",
1423 	"zh": "zho",
1424 	"cv": "chv",
1425 	"kw": "cor",
1426 	"co": "cos",
1427 	"cr": "cre",
1428 	"hr": "hrv",
1429 	"cs": "ces",
1430 	"da": "dan",
1431 	"dv": "div",
1432 	"nl": "nld",
1433 	"dz": "dzo",
1434 	"en": "eng",
1435 	"eo": "epo",
1436 	"et": "est",
1437 	"ee": "ewe",
1438 	"fo": "fao",
1439 	"fj": "fij",
1440 	"fi": "fin",
1441 	"fr": "fra",
1442 	"ff": "ful",
1443 	"gl": "glg",
1444 	"ka": "kat",
1445 	"de": "deu",
1446 	"el": "ell",
1447 	"gn": "grn",
1448 	"gu": "guj",
1449 	"ht": "hat",
1450 	"ha": "hau",
1451 	"he": "heb",
1452 	"hz": "her",
1453 	"hi": "hin",
1454 	"ho": "hmo",
1455 	"hu": "hun",
1456 	"ia": "ina",
1457 	"id": "ind",
1458 	"ie": "ile",
1459 	"ga": "gle",
1460 	"ig": "ibo",
1461 	"ik": "ipk",
1462 	"io": "ido",
1463 	"is": "isl",
1464 	"it": "ita",
1465 	"iu": "iku",
1466 	"ja": "jpn",
1467 	"jv": "jav",
1468 	"kl": "kal",
1469 	"kn": "kan",
1470 	"kr": "kau",
1471 	"ks": "kas",
1472 	"kk": "kaz",
1473 	"km": "khm",
1474 	"ki": "kik",
1475 	"rw": "kin",
1476 	"ky": "kir",
1477 	"kv": "kom",
1478 	"kg": "kon",
1479 	"ko": "kor",
1480 	"ku": "kur",
1481 	"kj": "kua",
1482 	"la": "lat",
1483 	"lb": "ltz",
1484 	"lg": "lug",
1485 	"li": "lim",
1486 	"ln": "lin",
1487 	"lo": "lao",
1488 	"lt": "lit",
1489 	"lu": "lub",
1490 	"lv": "lav",
1491 	"gv": "glv",
1492 	"mk": "mkd",
1493 	"mg": "mlg",
1494 	"ms": "msa",
1495 	"ml": "mal",
1496 	"mt": "mlt",
1497 	"mi": "mri",
1498 	"mr": "mar",
1499 	"mh": "mah",
1500 	"mn": "mon",
1501 	"na": "nau",
1502 	"nv": "nav",
1503 	"nb": "nob",
1504 	"nd": "nde",
1505 	"ne": "nep",
1506 	"ng": "ndo",
1507 	"nn": "nno",
1508 	"no": "nor",
1509 	"ii": "iii",
1510 	"nr": "nbl",
1511 	"oc": "oci",
1512 	"oj": "oji",
1513 	"cu": "chu",
1514 	"om": "orm",
1515 	"or": "ori",
1516 	"os": "oss",
1517 	"pa": "pan",
1518 	"pi": "pli",
1519 	"fa": "fas",
1520 	"pl": "pol",
1521 	"ps": "pus",
1522 	"pt": "por",
1523 	"qu": "que",
1524 	"rm": "roh",
1525 	"rn": "run",
1526 	"ro": "ron",
1527 	"ru": "rus",
1528 	"sa": "san",
1529 	"sc": "srd",
1530 	"sd": "snd",
1531 	"se": "sme",
1532 	"sm": "smo",
1533 	"sg": "sag",
1534 	"sr": "srp",
1535 	"gd": "gla",
1536 	"sn": "sna",
1537 	"si": "sin",
1538 	"sk": "slk",
1539 	"sl": "slv",
1540 	"so": "som",
1541 	"st": "sot",
1542 	"az": "azb",
1543 	"es": "spa",
1544 	"su": "sun",
1545 	"sw": "swa",
1546 	"ss": "ssw",
1547 	"sv": "swe",
1548 	"ta": "tam",
1549 	"te": "tel",
1550 	"tg": "tgk",
1551 	"th": "tha",
1552 	"ti": "tir",
1553 	"bo": "bod",
1554 	"tk": "tuk",
1555 	"tl": "tgl",
1556 	"tn": "tsn",
1557 	"to": "ton",
1558 	"tr": "tur",
1559 	"ts": "tso",
1560 	"tt": "tat",
1561 	"tw": "twi",
1562 	"ty": "tah",
1563 	"ug": "uig",
1564 	"uk": "ukr",
1565 	"ur": "urd",
1566 	"uz": "uzb",
1567 	"ve": "ven",
1568 	"vi": "vie",
1569 	"vo": "vol",
1570 	"wa": "wln",
1571 	"cy": "cym",
1572 	"wo": "wol",
1573 	"fy": "fry",
1574 	"xh": "xho",
1575 	"yi": "yid",
1576 	"yo": "yor",
1577 	"za": "zha",
1578 	"zu": "zul"
1579 };
1580 
1581 /**
1582  * Tell whether or not the str does not start with a lower case ASCII char.
1583  * @private
1584  * @param {string} str the char to check
1585  * @return {boolean} true if the char is not a lower case ASCII char
1586  */
1587 Locale._notLower = function(str) {
1588 	// do this with ASCII only so we don't have to depend on the CType functions
1589 	var ch = str.charCodeAt(0);
1590 	return ch < 97 || ch > 122;
1591 };
1592 
1593 /**
1594  * Tell whether or not the str does not start with an upper case ASCII char.
1595  * @private
1596  * @param {string} str the char to check
1597  * @return {boolean} true if the char is a not an upper case ASCII char
1598  */
1599 Locale._notUpper = function(str) {
1600 	// do this with ASCII only so we don't have to depend on the CType functions
1601 	var ch = str.charCodeAt(0);
1602 	return ch < 65 || ch > 90;
1603 };
1604 
1605 /**
1606  * Tell whether or not the str does not start with a digit char.
1607  * @private
1608  * @param {string} str the char to check
1609  * @return {boolean} true if the char is a not an upper case ASCII char
1610  */
1611 Locale._notDigit = function(str) {
1612 	// do this with ASCII only so we don't have to depend on the CType functions
1613 	var ch = str.charCodeAt(0);
1614 	return ch < 48 || ch > 57;
1615 };
1616 
1617 /**
1618  * Tell whether or not the given string has the correct syntax to be 
1619  * an ISO 639 language code.
1620  * 
1621  * @private
1622  * @param {string} str the string to parse
1623  * @return {boolean} true if the string could syntactically be a language code.
1624  */
1625 Locale._isLanguageCode = function(str) {
1626 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1627 		return false;
1628 	}
1629 
1630 	for (var i = 0; i < str.length; i++) {
1631 		if (Locale._notLower(str.charAt(i))) {
1632 			return false;
1633 		}
1634 	}
1635 	
1636 	return true;
1637 };
1638 
1639 /**
1640  * Tell whether or not the given string has the correct syntax to be 
1641  * an ISO 3166 2-letter region code or M.49 3-digit region code.
1642  * 
1643  * @private
1644  * @param {string} str the string to parse
1645  * @return {boolean} true if the string could syntactically be a language code.
1646  */
1647 Locale._isRegionCode = function (str) {
1648 	if (typeof(str) === 'undefined' || str.length < 2 || str.length > 3) {
1649 		return false;
1650 	}
1651 	
1652 	if (str.length === 2) {
1653 		for (var i = 0; i < str.length; i++) {
1654 			if (Locale._notUpper(str.charAt(i))) {
1655 				return false;
1656 			}
1657 		}
1658 	} else {
1659 		for (var i = 0; i < str.length; i++) {
1660 			if (Locale._notDigit(str.charAt(i))) {
1661 				return false;
1662 			}
1663 		}
1664 	}
1665 	
1666 	return true;
1667 };
1668 
1669 /**
1670  * Tell whether or not the given string has the correct syntax to be 
1671  * an ISO 639 language code.
1672  * 
1673  * @private
1674  * @param {string} str the string to parse
1675  * @return {boolean} true if the string could syntactically be a language code.
1676  */
1677 Locale._isScriptCode = function(str) {
1678 	if (typeof(str) === 'undefined' || str.length !== 4 || Locale._notUpper(str.charAt(0))) {
1679 		return false;
1680 	}
1681 	
1682 	for (var i = 1; i < 4; i++) {
1683 		if (Locale._notLower(str.charAt(i))) {
1684 			return false;
1685 		}
1686 	}
1687 	
1688 	return true;
1689 };
1690 
1691 /**
1692  * Return the ISO-3166 alpha3 equivalent region code for the given ISO 3166 alpha2
1693  * region code. If the given alpha2 code is not found, this function returns its
1694  * argument unchanged.
1695  * @static
1696  * @param {string|undefined} alpha2 the alpha2 code to map
1697  * @return {string|undefined} the alpha3 equivalent of the given alpha2 code, or the alpha2
1698  * parameter if the alpha2 value is not found
1699  */
1700 Locale.regionAlpha2ToAlpha3 = function(alpha2) {
1701 	return Locale.a2toa3regmap[alpha2] || alpha2;
1702 };
1703 
1704 /**
1705  * Return the ISO-639 alpha3 equivalent language code for the given ISO 639 alpha1
1706  * language code. If the given alpha1 code is not found, this function returns its
1707  * argument unchanged.
1708  * @static
1709  * @param {string|undefined} alpha1 the alpha1 code to map
1710  * @return {string|undefined} the alpha3 equivalent of the given alpha1 code, or the alpha1
1711  * parameter if the alpha1 value is not found
1712  */
1713 Locale.languageAlpha1ToAlpha3 = function(alpha1) {
1714 	return Locale.a1toa3langmap[alpha1] || alpha1;
1715 };
1716 
1717 Locale.prototype = {
1718 	/**
1719 	 * @private
1720 	 */
1721 	_genSpec: function () {
1722 		this.spec = this.language || "";
1723 		
1724 		if (this.script) {
1725 			if (this.spec.length > 0) {
1726 				this.spec += "-";
1727 			}
1728 			this.spec += this.script;
1729 		}
1730 		
1731 		if (this.region) {
1732 			if (this.spec.length > 0) {
1733 				this.spec += "-";
1734 			}
1735 			this.spec += this.region;
1736 		}
1737 		
1738 		if (this.variant) {
1739 			if (this.spec.length > 0) {
1740 				this.spec += "-";
1741 			}
1742 			this.spec += this.variant;
1743 		}
1744 	},
1745 
1746 	/**
1747 	 * Return the ISO 639 language code for this locale. 
1748 	 * @return {string|undefined} the language code for this locale 
1749 	 */
1750 	getLanguage: function() {
1751 		return this.language;
1752 	},
1753 	
1754 	/**
1755 	 * Return the language of this locale as an ISO-639-alpha3 language code
1756 	 * @return {string|undefined} the alpha3 language code of this locale
1757 	 */
1758 	getLanguageAlpha3: function() {
1759 		return Locale.languageAlpha1ToAlpha3(this.language);
1760 	},
1761 	
1762 	/**
1763 	 * Return the ISO 3166 region code for this locale.
1764 	 * @return {string|undefined} the region code of this locale
1765 	 */
1766 	getRegion: function() {
1767 		return this.region;
1768 	},
1769 	
1770 	/**
1771 	 * Return the region of this locale as an ISO-3166-alpha3 region code
1772 	 * @return {string|undefined} the alpha3 region code of this locale
1773 	 */
1774 	getRegionAlpha3: function() {
1775 		return Locale.regionAlpha2ToAlpha3(this.region);
1776 	},
1777 	
1778 	/**
1779 	 * Return the ISO 15924 script code for this locale
1780 	 * @return {string|undefined} the script code of this locale
1781 	 */
1782 	getScript: function () {
1783 		return this.script;
1784 	},
1785 	
1786 	/**
1787 	 * Return the variant code for this locale
1788 	 * @return {string|undefined} the variant code of this locale, if any
1789 	 */
1790 	getVariant: function() {
1791 		return this.variant;
1792 	},
1793 	
1794 	/**
1795 	 * Return the whole locale specifier as a string.
1796 	 * @return {string} the locale specifier
1797 	 */
1798 	getSpec: function() {
1799 		return this.spec;
1800 	},
1801 	
1802 	/**
1803 	 * Express this locale object as a string. Currently, this simply calls the getSpec
1804 	 * function to represent the locale as its specifier.
1805 	 * 
1806 	 * @return {string} the locale specifier
1807 	 */
1808 	toString: function() {
1809 		return this.getSpec();
1810 	},
1811 	
1812 	/**
1813 	 * Return true if the the other locale is exactly equal to the current one.
1814 	 * @return {boolean} whether or not the other locale is equal to the current one 
1815 	 */
1816 	equals: function(other) {
1817 		return this.language === other.language &&
1818 			this.region === other.region &&
1819 			this.script === other.script &&
1820 			this.variant === other.variant;
1821 	},
1822 
1823 	/**
1824 	 * Return true if the current locale is the special pseudo locale.
1825 	 * @return {boolean} true if the current locale is the special pseudo locale
1826 	 */
1827 	isPseudo: function () {
1828 		return JSUtils.indexOf(ilib.pseudoLocales, this.spec) > -1;
1829 	}
1830 };
1831 
1832 // static functions
1833 /**
1834  * @private
1835  */
1836 Locale.locales = [
1837 	
1838 ];
1839 
1840 /**
1841  * Return the list of available locales that this iLib file supports.
1842  * If this copy of ilib is pre-assembled with locale data, then the 
1843  * list locales may be much smaller
1844  * than the list of all available locales in the iLib repository. The
1845  * assembly tool will automatically fill in the list for an assembled
1846  * copy of iLib. If this copy is being used with dynamically loaded 
1847  * data, then you 
1848  * can load any locale that iLib supports. You can form a locale with any 
1849  * combination of a language and region tags that exist in the locale
1850  * data directory. Language tags are in the root of the locale data dir,
1851  * and region tags can be found underneath the "und" directory. (The 
1852  * region tags are separated into a different dir because the region names 
1853  * conflict with language names on file systems that are case-insensitive.) 
1854  * If you have culled the locale data directory to limit the size of
1855  * your app, then this function should return only those files that actually exist
1856  * according to the ilibmanifest.json file in the root of that locale
1857  * data dir. Make sure your ilibmanifest.json file is up-to-date with
1858  * respect to the list of files that exist in the locale data dir.
1859  * 
1860  * @param {boolean} sync if false, load the list of available files from disk
1861  * asynchronously, otherwise load them synchronously. (Default: true/synchronously)
1862  * @param {Function} onLoad a callback function to call if asynchronous
1863  * load was requested and the list of files have been loaded.
1864  * @return {Array.<string>} this is an array of locale specs for which 
1865  * this iLib file has locale data for
1866  */
1867 Locale.getAvailableLocales = function (sync, onLoad) {
1868 	var locales = [];
1869 	if (Locale.locales.length || typeof(ilib._load.listAvailableFiles) !== 'function') {
1870 		locales = Locale.locales;
1871 		if (onLoad && typeof(onLoad) === 'function') {
1872 			onLoad(locales);
1873 		}
1874 	} else {
1875 		if (typeof(sync) === 'undefined') {
1876 			sync = true;
1877 		}
1878 		ilib._load.listAvailableFiles(sync, function(manifest) {
1879 			if (manifest) {
1880 				for (var dir in manifest) {
1881 					var filelist = manifest[dir];
1882 					for (var i = 0; i < filelist.length; i++) {
1883 						if (filelist[i].length > 15 && filelist[i].substr(-15) === "localeinfo.json") {
1884 							locales.push(filelist[i].substring(0,filelist[i].length-16).replace(/\//g, "-"));
1885 						}
1886 					}
1887 				}
1888 			}
1889 			if (onLoad && typeof(onLoad) === 'function') {
1890 				onLoad(locales);
1891 			}
1892 		});
1893 	}
1894 	return locales;
1895 };
1896 
1897 
1898 
1899 /*< Utils.js */
1900 /*
1901  * Utils.js - Core utility routines
1902  * 
1903  * Copyright © 2012-2015, JEDLSoft
1904  *
1905  * Licensed under the Apache License, Version 2.0 (the "License");
1906  * you may not use this file except in compliance with the License.
1907  * You may obtain a copy of the License at
1908  *
1909  *     http://www.apache.org/licenses/LICENSE-2.0
1910  *
1911  * Unless required by applicable law or agreed to in writing, software
1912  * distributed under the License is distributed on an "AS IS" BASIS,
1913  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1914  *
1915  * See the License for the specific language governing permissions and
1916  * limitations under the License.
1917  */
1918 
1919 // !depends ilib.js Locale.js JSUtils.js
1920 
1921 
1922 var Utils = {};
1923 
1924 /**
1925  * Find and merge all the locale data for a particular prefix in the given locale
1926  * and return it as a single javascript object. This merges the data in the 
1927  * correct order:
1928  * 
1929  * <ol>
1930  * <li>shared data (usually English)
1931  * <li>data for language
1932  * <li>data for language + region
1933  * <li>data for language + region + script
1934  * <li>data for language + region + script + variant
1935  * </ol>
1936  * 
1937  * It is okay for any of the above to be missing. This function will just skip the 
1938  * missing data. However, if everything except the shared data is missing, this 
1939  * function returns undefined, allowing the caller to go and dynamically load the
1940  * data instead.
1941  * 
1942  * @static
1943  * @param {string} prefix prefix under ilib.data of the data to merge
1944  * @param {Locale} locale locale of the data being sought
1945  * @param {boolean=} replaceArrays if true, replace the array elements in object1 with those in object2.
1946  * If false, concatenate array elements in object1 with items in object2.
1947  * @param {boolean=} returnOne if true, only return the most locale-specific data. If false,
1948  * merge all the relevant locale data together.
1949  * @return {Object?} the merged locale data
1950  */
1951 Utils.mergeLocData = function (prefix, locale, replaceArrays, returnOne) {
1952 	var data = undefined;
1953 	var loc = locale || new Locale();
1954 	var foundLocaleData = false;
1955 	var property = prefix;
1956 	var mostSpecific;
1957 
1958 	data = ilib.data[prefix] || {};
1959 
1960 	mostSpecific = data;
1961 
1962 	if (loc.getLanguage()) {
1963 		property = prefix + '_' + loc.getLanguage();
1964 		if (ilib.data[property]) {
1965 			foundLocaleData = true;
1966 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
1967 			mostSpecific = ilib.data[property];
1968 		}
1969 	}
1970 	
1971 	if (loc.getRegion()) {
1972 		property = prefix + '_' + loc.getRegion();
1973 		if (ilib.data[property]) {
1974 			foundLocaleData = true;
1975 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
1976 			mostSpecific = ilib.data[property];
1977 		}
1978 	}
1979 	
1980 	if (loc.getLanguage()) {
1981 		property = prefix + '_' + loc.getLanguage();
1982 		
1983 		if (loc.getScript()) {
1984 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript();
1985 			if (ilib.data[property]) {
1986 				foundLocaleData = true;
1987 				data = JSUtils.merge(data, ilib.data[property], replaceArrays);
1988 				mostSpecific = ilib.data[property];
1989 			}
1990 		}
1991 		
1992 		if (loc.getRegion()) {
1993 			property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion();
1994 			if (ilib.data[property]) {
1995 				foundLocaleData = true;
1996 				data = JSUtils.merge(data, ilib.data[property], replaceArrays);
1997 				mostSpecific = ilib.data[property];
1998 			}
1999 		}		
2000 	}
2001 	
2002 	if (loc.getRegion() && loc.getVariant()) {
2003 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getVariant();
2004 		if (ilib.data[property]) {
2005 			foundLocaleData = true;
2006 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2007 			mostSpecific = ilib.data[property];
2008 		}
2009 	}
2010 
2011 	if (loc.getLanguage() && loc.getScript() && loc.getRegion()) {
2012 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion();
2013 		if (ilib.data[property]) {
2014 			foundLocaleData = true;
2015 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2016 			mostSpecific = ilib.data[property];
2017 		}
2018 	}
2019 
2020 	if (loc.getLanguage() && loc.getRegion() && loc.getVariant()) {
2021 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getRegion() + '_' + loc.getVariant();
2022 		if (ilib.data[property]) {
2023 			foundLocaleData = true;
2024 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2025 			mostSpecific = ilib.data[property];
2026 		}
2027 	}
2028 
2029 	if (loc.getLanguage() && loc.getScript() && loc.getRegion() && loc.getVariant()) {
2030 		property = prefix + '_' + loc.getLanguage() + '_' + loc.getScript() + '_' + loc.getRegion() + '_' + loc.getVariant();
2031 		if (ilib.data[property]) {
2032 			foundLocaleData = true;
2033 			data = JSUtils.merge(data, ilib.data[property], replaceArrays);
2034 			mostSpecific = ilib.data[property];
2035 		}
2036 	}
2037 	
2038 	return foundLocaleData ? (returnOne ? mostSpecific : data) : undefined;
2039 };
2040 
2041 /**
2042  * Return an array of relative path names for the
2043  * files that represent the data for the given locale.<p>
2044  * 
2045  * Note that to prevent the situation where a directory for
2046  * a language exists next to the directory for a region where
2047  * the language code and region code differ only by case, the 
2048  * plain region directories are located under the special 
2049  * "undefined" language directory which has the ISO code "und".
2050  * The reason is that some platforms have case-insensitive 
2051  * file systems, and you cannot have 2 directories with the 
2052  * same name which only differ by case. For example, "es" is
2053  * the ISO 639 code for the language "Spanish" and "ES" is
2054  * the ISO 3166 code for the region "Spain", so both the
2055  * directories cannot exist underneath "locale". The region
2056  * therefore will be loaded from "und/ES" instead.<p>  
2057  * 
2058  * <h4>Variations</h4>
2059  * 
2060  * With only language and region specified, the following
2061  * sequence of paths will be generated:<p>
2062  * 
2063  * <pre>
2064  * language
2065  * und/region
2066  * language/region
2067  * </pre>
2068  * 
2069  * With only language and script specified:<p>
2070  * 
2071  * <pre>
2072  * language
2073  * language/script
2074  * </pre>
2075  * 
2076  * With only script and region specified:<p>
2077  * 
2078  * <pre>
2079  * und/region  
2080  * </pre>
2081  * 
2082  * With only region and variant specified:<p>
2083  * 
2084  * <pre>
2085  * und/region
2086  * region/variant
2087  * </pre>
2088  * 
2089  * With only language, script, and region specified:<p>
2090  * 
2091  * <pre>
2092  * language
2093  * und/region
2094  * language/script
2095  * language/region
2096  * language/script/region
2097  * </pre>
2098  * 
2099  * With only language, region, and variant specified:<p>
2100  * 
2101  * <pre>
2102  * language
2103  * und/region
2104  * language/region
2105  * region/variant
2106  * language/region/variant
2107  * </pre>
2108  * 
2109  * With all parts specified:<p>
2110  * 
2111  * <pre>
2112  * language
2113  * und/region
2114  * language/script
2115  * language/region
2116  * region/variant
2117  * language/script/region
2118  * language/region/variant
2119  * language/script/region/variant
2120  * </pre>
2121  * 
2122  * @static
2123  * @param {Locale} locale load the files for this locale
2124  * @param {string?} name the file name of each file to load without
2125  * any path
2126  * @return {Array.<string>} An array of relative path names
2127  * for the files that contain the locale data
2128  */
2129 Utils.getLocFiles = function(locale, name) {
2130 	var dir = "";
2131 	var files = [];
2132 	var filename = name || "resources.json";
2133 	var loc = locale || new Locale();
2134 	
2135 	var language = loc.getLanguage();
2136 	var region = loc.getRegion();
2137 	var script = loc.getScript();
2138 	var variant = loc.getVariant();
2139 	
2140 	files.push(filename); // generic shared file
2141 	
2142 	if (language) {
2143 		dir = language + "/";
2144 		files.push(dir + filename);
2145 	}
2146 	
2147 	if (region) {
2148 		dir = "und/" + region + "/";
2149 		files.push(dir + filename);
2150 	}
2151 	
2152 	if (language) {
2153 		if (script) {
2154 			dir = language + "/" + script + "/";
2155 			files.push(dir + filename);
2156 		}
2157 		if (region) {
2158 			dir = language + "/" + region + "/";
2159 			files.push(dir + filename);
2160 		}
2161 	}
2162 	
2163 	if (region && variant) {
2164 		dir = "und/" + region + "/" + variant + "/";
2165 		files.push(dir + filename);
2166 	}
2167 
2168 	if (language && script && region) {
2169 		dir = language + "/" + script + "/" + region + "/";
2170 		files.push(dir + filename);
2171 	}
2172 
2173 	if (language && region && variant) {
2174 		dir = language + "/" + region + "/" + variant + "/";
2175 		files.push(dir + filename);
2176 	}
2177 
2178 	if (language && script && region && variant) {
2179 		dir = language + "/" + script + "/" + region + "/" + variant + "/";
2180 		files.push(dir + filename);
2181 	}
2182 	
2183 	return files;
2184 };
2185 
2186 /**
2187  * Load data using the new loader object or via the old function callback.
2188  * @static
2189  * @private
2190  */
2191 Utils._callLoadData = function (files, sync, params, callback) {
2192 	// console.log("Utils._callLoadData called");
2193 	if (typeof(ilib._load) === 'function') {
2194 		// console.log("Utils._callLoadData: calling as a regular function");
2195 		return ilib._load(files, sync, params, callback);
2196 	} else if (typeof(ilib._load) === 'object' && typeof(ilib._load.loadFiles) === 'function') {
2197 		// console.log("Utils._callLoadData: calling as an object");
2198 		return ilib._load.loadFiles(files, sync, params, callback);
2199 	}
2200 	
2201 	// console.log("Utils._callLoadData: not calling. Type is " + typeof(ilib._load) + " and instanceof says " + (ilib._load instanceof Loader));
2202 	return undefined;
2203 };
2204 
2205 /**
2206  * Find locale data or load it in. If the data with the given name is preassembled, it will
2207  * find the data in ilib.data. If the data is not preassembled but there is a loader function,
2208  * this function will call it to load the data. Otherwise, the callback will be called with
2209  * undefined as the data. This function will create a cache under the given class object.
2210  * If data was successfully loaded, it will be set into the cache so that future access to 
2211  * the same data for the same locale is much quicker.<p>
2212  * 
2213  * The parameters can specify any of the following properties:<p>
2214  * 
2215  * <ul>
2216  * <li><i>name</i> - String. The name of the file being loaded. Default: ResBundle.json
2217  * <li><i>object</i> - Object. The class attempting to load data. The cache is stored inside of here.
2218  * <li><i>locale</i> - Locale. The locale for which data is loaded. Default is the current locale.
2219  * <li><i>nonlocale</i> - boolean. If true, the data being loaded is not locale-specific.
2220  * <li><i>type</i> - String. Type of file to load. This can be "json" or "other" type. Default: "json" 
2221  * <li><i>replace</i> - boolean. When merging json objects, this parameter controls whether to merge arrays
2222  * or have arrays replace each other. If true, arrays in child objects replace the arrays in parent 
2223  * objects. When false, the arrays in child objects are concatenated with the arrays in parent objects.  
2224  * <li><i>loadParams</i> - Object. An object with parameters to pass to the loader function
2225  * <li><i>sync</i> - boolean. Whether or not to load the data synchronously
2226  * <li><i>callback</i> - function(?)=. callback Call back function to call when the data is available.
2227  * Data is not returned from this method, so a callback function is mandatory.
2228  * </ul>
2229  * 
2230  * @static
2231  * @param {Object} params Parameters configuring how to load the files (see above)
2232  */
2233 Utils.loadData = function(params) {
2234 	var name = "resources.json",
2235 		object = undefined, 
2236 		locale = new Locale(ilib.getLocale()), 
2237 		sync = false, 
2238 		type = undefined,
2239 		loadParams = {},
2240 		callback = undefined,
2241 		nonlocale = false,
2242 		replace = false,
2243 		basename;
2244 	
2245 	if (!params || typeof(params.callback) !== 'function') {
2246 		return;
2247 	}
2248 
2249 	if (params.name) {
2250 		name = params.name;
2251 	}
2252 	if (params.object) {
2253 		object = params.object;
2254 	}
2255 	if (params.locale) {
2256 		locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
2257 	}			
2258 	if (params.type) {
2259 		type = params.type;
2260 	}
2261 	if (params.loadParams) {
2262 		loadParams = params.loadParams;
2263 	}
2264 	if (params.sync) {
2265 		sync = params.sync;
2266 	}
2267 	if (params.nonlocale) {
2268 		nonlocale = !!params.nonlocale;
2269 	}
2270 	if (typeof(params.replace) === 'boolean') {
2271 		replace = params.replace;
2272 	}
2273 	
2274 	callback = params.callback;
2275 	
2276 	if (object && !object.cache) {
2277 		object.cache = {};
2278 	}
2279 	
2280 	if (!type) {
2281 		var dot = name.lastIndexOf(".");
2282 		type = (dot !== -1) ? name.substring(dot+1) : "text";
2283 	}
2284 
2285 	var spec = ((!nonlocale && locale.getSpec().replace(/-/g, '_')) || "root") + "," + name + "," + String(JSUtils.hashCode(loadParams));
2286 	if (!object || typeof(object.cache[spec]) === 'undefined') {
2287 		var data, returnOne = (loadParams && loadParams.returnOne);
2288 		
2289 		if (type === "json") {
2290 			// console.log("type is json");
2291 			basename = name.substring(0, name.lastIndexOf("."));
2292 			if (nonlocale) {
2293 				basename = basename.replace(/\//g, '.').replace(/[\\\+\-]/g, "_");
2294 				data = ilib.data[basename];
2295 			} else {
2296 				data = Utils.mergeLocData(basename, locale, replace, returnOne);
2297 			}
2298 			if (data) {
2299 				// console.log("found assembled data");
2300 				if (object) {
2301 					object.cache[spec] = data;
2302 				}
2303 				callback(data);
2304 				return;
2305 			}
2306 		}
2307 		
2308 		// console.log("ilib._load is " + typeof(ilib._load));
2309 		if (typeof(ilib._load) !== 'undefined') {
2310 			// the data is not preassembled, so attempt to load it dynamically
2311 			var files = nonlocale ? [ name || "resources.json" ] : Utils.getLocFiles(locale, name);
2312 			if (type !== "json") {
2313 				loadParams.returnOne = true;
2314 			}
2315 			
2316 			Utils._callLoadData(files, sync, loadParams, ilib.bind(this, function(arr) {
2317 				if (type === "json") {
2318 					data = ilib.data[basename] || {};
2319 					for (var i = 0; i < arr.length; i++) {
2320 						if (typeof(arr[i]) !== 'undefined') {
2321 							data = loadParams.returnOne ? arr[i] : JSUtils.merge(data, arr[i], replace);
2322 						}
2323 					}
2324 					
2325 					if (object) {
2326 						object.cache[spec] = data;
2327 					}
2328 					callback(data);
2329 				} else {
2330 					var i = arr.length-1; 
2331 					while (i > -1 && !arr[i]) {
2332 						i--;
2333 					}
2334 					if (i > -1) {
2335 						if (object) {
2336 							object.cache[spec] = arr[i];
2337 						}
2338 						callback(arr[i]);
2339 					} else {
2340 						callback(undefined);
2341 					}
2342 				}
2343 			}));
2344 		} else {
2345 			// no data other than the generic shared data
2346 			if (type === "json") {
2347 				data = ilib.data[basename];
2348 			}
2349 			if (object && data) {
2350 				object.cache[spec] = data;
2351 			}
2352 			callback(data);
2353 		}
2354 	} else {
2355 		callback(object.cache[spec]);
2356 	}
2357 };
2358 
2359 
2360 /*< LocaleInfo.js */
2361 /*
2362  * LocaleInfo.js - Encode locale-specific defaults
2363  * 
2364  * Copyright © 2012-2015, JEDLSoft
2365  *
2366  * Licensed under the Apache License, Version 2.0 (the "License");
2367  * you may not use this file except in compliance with the License.
2368  * You may obtain a copy of the License at
2369  *
2370  *     http://www.apache.org/licenses/LICENSE-2.0
2371  *
2372  * Unless required by applicable law or agreed to in writing, software
2373  * distributed under the License is distributed on an "AS IS" BASIS,
2374  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2375  *
2376  * See the License for the specific language governing permissions and
2377  * limitations under the License.
2378  */
2379 
2380 // !depends ilib.js Locale.js Utils.js
2381 
2382 // !data localeinfo
2383 
2384 
2385 /**
2386  * @class
2387  * Create a new locale info instance. Locale info instances give information about
2388  * the default settings for a particular locale. These settings may be overridden
2389  * by various parts of the code, and should be used as a fall-back setting of last
2390  * resort. <p>
2391  * 
2392  * The optional options object holds extra parameters if they are necessary. The
2393  * current list of supported options are:
2394  * 
2395  * <ul>
2396  * <li><i>onLoad</i> - a callback function to call when the locale info object is fully 
2397  * loaded. When the onLoad option is given, the localeinfo object will attempt to
2398  * load any missing locale data using the ilib loader callback.
2399  * When the constructor is done (even if the data is already preassembled), the 
2400  * onLoad function is called with the current instance as a parameter, so this
2401  * callback can be used with preassembled or dynamic loading or a mix of the two.
2402  * 
2403  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
2404  * asynchronously. If this option is given as "false", then the "onLoad"
2405  * callback must be given, as the instance returned from this constructor will
2406  * not be usable for a while. 
2407  *
2408  * <li><i>loadParams</i> - an object containing parameters to pass to the 
2409  * loader callback function when locale data is missing. The parameters are not
2410  * interpretted or modified in any way. They are simply passed along. The object 
2411  * may contain any property/value pairs as long as the calling code is in
2412  * agreement with the loader callback function as to what those parameters mean.
2413  * </ul>
2414  * 
2415  * If this copy of ilib is pre-assembled and all the data is already available, 
2416  * or if the data was already previously loaded, then this constructor will call
2417  * the onLoad callback immediately when the initialization is done. 
2418  * If the onLoad option is not given, this class will only attempt to load any
2419  * missing locale data synchronously.
2420  * 
2421  * 
2422  * @constructor
2423  * @see {ilib.setLoaderCallback} for information about registering a loader callback
2424  * function
2425  * @param {Locale|string=} locale the locale for which the info is sought, or undefined for
2426  * @param {Object=} options the locale for which the info is sought, or undefined for
2427  * the current locale
2428  */
2429 var LocaleInfo = function(locale, options) {
2430 	var sync = true,
2431 	    loadParams = undefined;
2432 	
2433 	/* these are all the defaults. Essentially, en-US */
2434 	/**
2435 	  @private 
2436 	  @type {{
2437 		scripts:Array.<string>,
2438 		timezone:string,
2439 		units:string,
2440 		calendar:string,
2441 		clock:string,
2442 		currency:string,
2443 		firstDayOfWeek:number,
2444 		weekendStart:number,
2445 		weekendEnd:number,
2446 		meridiems:string,
2447 		unitfmt: {long:string,short:string},
2448 		numfmt:Object.<{
2449 			currencyFormats:Object.<{common:string,commonNegative:string,iso:string,isoNegative:string}>,
2450 			script:string,
2451 			decimalChar:string,
2452 			groupChar:string,
2453 			prigroupSize:number,
2454 			secgroupSize:number,
2455 			negativenumFmt:string,
2456 			pctFmt:string,
2457 			negativepctFmt:string,
2458 			pctChar:string,
2459 			roundingMode:string,
2460 			exponential:string,
2461 			digits:string
2462 		}>
2463 	  }}
2464 	*/
2465 	this.info = LocaleInfo.defaultInfo;
2466 	
2467 	switch (typeof(locale)) {
2468 		case "string":
2469 			this.locale = new Locale(locale);
2470 			break;
2471 		default:
2472 		case "undefined":
2473 			this.locale = new Locale();
2474 			break;
2475 		case "object":
2476 			this.locale = locale;
2477 			break;
2478 	}
2479 	
2480 	if (options) {
2481 		if (typeof(options.sync) !== 'undefined') {
2482 			sync = (options.sync == true);
2483 		}
2484 		
2485 		if (typeof(options.loadParams) !== 'undefined') {
2486 			loadParams = options.loadParams;
2487 		}
2488 	}
2489 
2490 	if (!LocaleInfo.cache) {
2491 		LocaleInfo.cache = {};
2492 	}
2493 
2494 	Utils.loadData({
2495 		object: LocaleInfo, 
2496 		locale: this.locale, 
2497 		name: "localeinfo.json", 
2498 		sync: sync, 
2499 		loadParams: loadParams, 
2500 		callback: ilib.bind(this, function (info) {
2501 			if (!info) {
2502 				info = LocaleInfo.defaultInfo;
2503 				var spec = this.locale.getSpec().replace(/-/g, "_");
2504 				LocaleInfo.cache[spec] = info;
2505 			}
2506 			this.info = info;
2507 			if (options && typeof(options.onLoad) === 'function') {
2508 				options.onLoad(this);
2509 			}
2510 		})
2511 	});
2512 };
2513 
2514 LocaleInfo.defaultInfo = /** @type {{
2515 	scripts:Array.<string>,
2516 	timezone:string,
2517 	units:string,
2518 	calendar:string,
2519 	clock:string,
2520 	currency:string,
2521 	firstDayOfWeek:number,
2522 	weekendStart:number,
2523 	weekendEnd:number,
2524 	meridiems:string,
2525 	unitfmt: {long:string,short:string},
2526 	numfmt:Object.<{
2527 		currencyFormats:Object.<{
2528 			common:string,
2529 			commonNegative:string,
2530 			iso:string,
2531 			isoNegative:string
2532 		}>,
2533 		script:string,
2534 		decimalChar:string,
2535 		groupChar:string,
2536 		prigroupSize:number,
2537 		secgroupSize:number,
2538 		negativenumFmt:string,
2539 		pctFmt:string,
2540 		negativepctFmt:string,
2541 		pctChar:string,
2542 		roundingMode:string,
2543 		exponential:string,
2544 		digits:string
2545 	}>
2546 }}*/ ilib.data.localeinfo;
2547 LocaleInfo.defaultInfo = LocaleInfo.defaultInfo || {
2548 	"scripts": ["Latn"],
2549     "timezone": "Etc/UTC",
2550     "units": "metric",
2551     "calendar": "gregorian",
2552     "clock": "24",
2553     "currency": "USD",
2554     "firstDayOfWeek": 1,
2555     "meridiems": "gregorian",
2556     "numfmt": {
2557         "currencyFormats": {
2558             "common": "{s}{n}",
2559             "commonNegative": "{s}-{n}",
2560             "iso": "{s}{n}",
2561             "isoNegative": "{s}-{n}"
2562         },
2563         "script": "Latn",
2564         "decimalChar": ",",
2565         "groupChar": ".",
2566         "prigroupSize": 3,
2567         "secgroupSize": 0,
2568         "pctFmt": "{n}%",
2569         "negativepctFmt": "-{n}%",
2570         "pctChar": "%",
2571         "roundingMode": "halfdown",
2572         "exponential": "e",
2573         "digits": ""
2574     }
2575 };
2576 
2577 LocaleInfo.prototype = {
2578     /**
2579      * Return the name of the locale's language in English.
2580      * @returns {string} the name of the locale's language in English
2581      */
2582     getLanguageName: function () {
2583     	return this.info["language.name"];	
2584     },
2585     
2586     /**
2587      * Return the name of the locale's region in English. If the locale
2588      * has no region, this returns undefined.
2589      * 
2590      * @returns {string|undefined} the name of the locale's region in English
2591      */
2592     getRegionName: function () {
2593     	return this.info["region.name"];	
2594     },
2595 
2596     /**
2597 	 * Return whether this locale commonly uses the 12- or the 24-hour clock.
2598 	 *  
2599 	 * @returns {string} "12" if the locale commonly uses a 12-hour clock, or "24"
2600 	 * if the locale commonly uses a 24-hour clock. 
2601 	 */
2602 	getClock: function() {
2603 		return this.info.clock;
2604 	},
2605 
2606 	/**
2607 	 * Return the locale that this info object was created with.
2608 	 * @returns {Locale} The locale spec of the locale used to construct this info instance
2609 	 */
2610 	getLocale: function () {
2611 		return this.locale;
2612 	},
2613 	
2614 	/**
2615 	 * Return the name of the measuring system that is commonly used in the given locale.
2616 	 * Valid values are "uscustomary", "imperial", and "metric".
2617 	 * 
2618 	 * @returns {string} The name of the measuring system commonly used in the locale
2619 	 */
2620 	getUnits: function () {
2621 		return this.info.units;
2622 	},
2623         
2624         getUnitFormat: function () {
2625                 return this.info.unitfmt;
2626         },
2627 	
2628 	/**
2629 	 * Return the name of the calendar that is commonly used in the given locale.
2630 	 * 
2631 	 * @returns {string} The name of the calendar commonly used in the locale
2632 	 */
2633 	getCalendar: function () {
2634 		return this.info.calendar;
2635 	},
2636 	
2637 	/**
2638 	 * Return the day of week that starts weeks in the current locale. Days are still
2639 	 * numbered the standard way with 0 for Sunday through 6 for Saturday, but calendars 
2640 	 * should be displayed and weeks calculated with the day of week returned from this 
2641 	 * function as the first day of the week.
2642 	 * 
2643 	 * @returns {number} the day of the week that starts weeks in the current locale.
2644 	 */
2645 	getFirstDayOfWeek: function () {
2646 		return this.info.firstDayOfWeek;
2647 	},
2648 	
2649 	/**
2650 	 * Return the day of week that starts weekend in the current locale. Days are still
2651 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
2652 	 * 
2653 	 * @returns {number} the day of the week that starts weeks in the current locale.
2654 	 */
2655 	getWeekEndStart: function () {
2656 		return this.info.weekendStart;
2657 	},
2658 
2659 	/**
2660 	 * Return the day of week that starts weekend in the current locale. Days are still
2661 	 * numbered the standard way with 0 for Sunday through 6 for Saturday.
2662 	 * 
2663 	 * @returns {number} the day of the week that starts weeks in the current locale.
2664 	 */
2665 	getWeekEndEnd: function () {
2666 		return this.info.weekendEnd;
2667 	},
2668 
2669 	/**
2670 	 * Return the default time zone for this locale. Many locales span across multiple
2671 	 * time zones. In this case, the time zone with the largest population is chosen
2672 	 * to represent the locale. This is obviously not that accurate, but then again,
2673 	 * this method's return value should only be used as a default anyways.
2674 	 * @returns {string} the default time zone for this locale.
2675 	 */
2676 	getTimeZone: function () {
2677 		return this.info.timezone;
2678 	},
2679 	
2680 	/**
2681 	 * Return the decimal separator for formatted numbers in this locale.
2682 	 * @returns {string} the decimal separator char
2683 	 */
2684 	getDecimalSeparator: function () {
2685 		return this.info.numfmt.decimalChar;
2686 	},
2687 	
2688 	/**
2689 	 * Return the decimal separator for formatted numbers in this locale for native script.
2690 	 * @returns {string} the decimal separator char
2691 	 */
2692 	getNativeDecimalSeparator: function () {
2693 		return (this.info.native_numfmt && this.info.native_numfmt.decimalChar) || this.info.numfmt.decimalChar;
2694 	},
2695 	
2696 	/**
2697 	 * Return the separator character used to separate groups of digits on the 
2698 	 * integer side of the decimal character.
2699 	 * @returns {string} the grouping separator char
2700 	 */
2701 	getGroupingSeparator: function () {
2702 		return this.info.numfmt.groupChar;
2703 	},
2704 
2705 	/**
2706 	 * Return the separator character used to separate groups of digits on the 
2707 	 * integer side of the decimal character for the native script if present other than the default script.
2708 	 * @returns {string} the grouping separator char
2709 	 */
2710 	getNativeGroupingSeparator: function () {
2711 		return (this.info.native_numfmt && this.info.native_numfmt.groupChar) || this.info.numfmt.groupChar;
2712 	},
2713 	
2714 	/**
2715 	 * Return the minimum number of digits grouped together on the integer side 
2716 	 * for the first (primary) group. 
2717 	 * In western European cultures, groupings are in 1000s, so the number of digits
2718 	 * is 3. 
2719 	 * @returns {number} the number of digits in a primary grouping, or 0 for no grouping
2720 	 */
2721 	getPrimaryGroupingDigits: function () {
2722 		return (typeof(this.info.numfmt.prigroupSize) !== 'undefined' && this.info.numfmt.prigroupSize) || 0;
2723 	},
2724 
2725 	/**
2726 	 * Return the minimum number of digits grouped together on the integer side
2727 	 * for the second or more (secondary) group.<p>
2728 	 *   
2729 	 * In western European cultures, all groupings are by 1000s, so the secondary
2730 	 * size should be 0 because there is no secondary size. In general, if this 
2731 	 * method returns 0, then all groupings are of the primary size.<p> 
2732 	 * 
2733 	 * For some other cultures, the first grouping (primary)
2734 	 * is 3 and any subsequent groupings (secondary) are two. So, 100000 would be
2735 	 * written as: "1,00,000".
2736 	 * 
2737 	 * @returns {number} the number of digits in a secondary grouping, or 0 for no 
2738 	 * secondary grouping. 
2739 	 */
2740 	getSecondaryGroupingDigits: function () {
2741 		return this.info.numfmt.secgroupSize || 0;
2742 	},
2743 
2744 	/**
2745 	 * Return the format template used to format percentages in this locale.
2746 	 * @returns {string} the format template for formatting percentages
2747 	 */
2748 	getPercentageFormat: function () {
2749 		return this.info.numfmt.pctFmt;
2750 	},
2751 
2752 	/**
2753 	 * Return the format template used to format percentages in this locale
2754 	 * with negative amounts.
2755 	 * @returns {string} the format template for formatting percentages
2756 	 */
2757 	getNegativePercentageFormat: function () {
2758 		return this.info.numfmt.negativepctFmt;
2759 	},
2760 
2761 	/**
2762 	 * Return the symbol used for percentages in this locale.
2763 	 * @returns {string} the symbol used for percentages in this locale
2764 	 */
2765 	getPercentageSymbol: function () {
2766 		return this.info.numfmt.pctChar || "%";
2767 	},
2768 
2769 	/**
2770 	 * Return the symbol used for exponential in this locale.
2771 	 * @returns {string} the symbol used for exponential in this locale
2772 	 */
2773 	getExponential: function () {
2774 		return this.info.numfmt.exponential;
2775 	},
2776 
2777 	/**
2778 	 * Return the symbol used for exponential in this locale for native script.
2779 	 * @returns {string} the symbol used for exponential in this locale for native script
2780 	 */
2781 	getNativeExponential: function () {
2782 		return (this.info.native_numfmt && this.info.native_numfmt.exponential) || this.info.numfmt.exponential;
2783 	},
2784 
2785 	/**
2786 	 * Return the symbol used for percentages in this locale for native script.
2787 	 * @returns {string} the symbol used for percentages in this locale for native script
2788 	 */
2789 	getNativePercentageSymbol: function () {
2790 		return (this.info.native_numfmt && this.info.native_numfmt.pctChar) || this.info.numfmt.pctChar || "%";
2791 	
2792 	},
2793 	/**
2794 	 * Return the format template used to format negative numbers in this locale.
2795 	 * @returns {string} the format template for formatting negative numbers
2796 	 */
2797 	getNegativeNumberFormat: function () { 
2798 		return this.info.numfmt.negativenumFmt;
2799 	},
2800 	
2801 	/**
2802 	 * Return an object containing the format templates for formatting currencies
2803 	 * in this locale. The object has a number of properties in it that each are
2804 	 * a particular style of format. Normally, this contains a "common" and an "iso"
2805 	 * style, but may contain others in the future.
2806 	 * @returns {Object} an object containing the format templates for currencies
2807 	 */
2808 	getCurrencyFormats: function () {
2809 		return this.info.numfmt.currencyFormats;
2810 	},
2811 	
2812 	/**
2813 	 * Return the currency that is legal in the locale, or which is most commonly 
2814 	 * used in regular commerce.
2815 	 * @returns {string} the ISO 4217 code for the currency of this locale
2816 	 */
2817 	getCurrency: function () {
2818 		return this.info.currency;
2819 	},
2820 	
2821 	/**
2822 	 * Return a string that describes the style of digits used by this locale.
2823 	 * Possible return values are:
2824 	 * <ul>
2825 	 * <li><i>western</i> - uses the regular western 10-based digits 0 through 9
2826 	 * <li><i>optional</i> - native 10-based digits exist, but in modern usage,
2827 	 * this locale most often uses western digits
2828 	 * <li><i>native</i> - native 10-based native digits exist and are used
2829 	 * regularly by this locale
2830 	 * <li><i>custom</i> - uses native digits by default that are not 10-based
2831 	 * </ul>
2832 	 * @returns {string} string that describes the style of digits used in this locale
2833 	 */
2834 	getDigitsStyle: function () {
2835 		if (this.info.numfmt.useNative) {
2836 			return "native";
2837 		}
2838 		if (typeof(this.info.native_numfmt) !== 'undefined') {
2839 			return "optional";
2840 		}
2841 		return "western";
2842 	},
2843 	
2844 	/**
2845 	 * Return the digits of the default script if they are defined.
2846 	 * If not defined, the default should be the regular "Arabic numerals"
2847 	 * used in the Latin script. (0-9)
2848 	 * @returns {string|undefined} the digits used in the default script 
2849 	 */
2850 	getDigits: function () {
2851 		return this.info.numfmt.digits;
2852 	},
2853 	
2854 	/**
2855 	 * Return the digits of the native script if they are defined. 
2856 	 * @returns {string|undefined} the digits used in the default script 
2857 	 */
2858 	getNativeDigits: function () {
2859 		return (this.info.numfmt.useNative && this.info.numfmt.digits) || (this.info.native_numfmt && this.info.native_numfmt.digits);
2860 	},
2861 	
2862 	/**
2863 	 * If this locale typically uses a different type of rounding for numeric
2864 	 * formatting other than halfdown, especially for currency, then it can be 
2865 	 * specified in the localeinfo. If the locale uses the default, then this 
2866 	 * method returns undefined. The locale's rounding method overrides the 
2867 	 * rounding method for the currency itself, which can sometimes shared 
2868 	 * between various locales so it is less specific.
2869 	 * @returns {string} the name of the rounding mode typically used in this
2870 	 * locale, or "halfdown" if the locale does not override the default
2871 	 */
2872 	getRoundingMode: function () {
2873 		return this.info.numfmt.roundingMode;
2874 	},
2875 	
2876 	/**
2877 	 * Return the default script used to write text in the language of this 
2878 	 * locale. Text for most languages is written in only one script, but there
2879 	 * are some languages where the text can be written in a number of scripts,
2880 	 * depending on a variety of things such as the region, ethnicity, religion, 
2881 	 * etc. of the author. This method returns the default script for the
2882 	 * locale, in which the language is most commonly written.<p> 
2883 	 * 
2884 	 * The script is returned as an ISO 15924 4-letter code.
2885 	 * 
2886 	 * @returns {string} the ISO 15924 code for the default script used to write
2887 	 * text in this locale 
2888 	 */
2889 	getDefaultScript: function() {
2890 		return (this.info.scripts) ? this.info.scripts[0] : "Latn";
2891 	},
2892 	
2893 	/**
2894 	 * Return the script used for the current locale. If the current locale
2895 	 * explicitly defines a script, then this script is returned. If not, then 
2896 	 * the default script for the locale is returned.
2897 	 * 
2898 	 * @see LocaleInfo.getDefaultScript
2899 	 * @returns {string} the ISO 15924 code for the script used to write
2900 	 * text in this locale
2901 	 */
2902 	getScript: function() {
2903 		return this.locale.getScript() || this.getDefaultScript(); 
2904 	},
2905 	
2906 	/**
2907 	 * Return an array of script codes which are used to write text in the current
2908 	 * language. Text for most languages is written in only one script, but there
2909 	 * are some languages where the text can be written in a number of scripts,
2910 	 * depending on a variety of things such as the region, ethnicity, religion, 
2911 	 * etc. of the author. This method returns an array of script codes in which 
2912 	 * the language is commonly written.
2913 	 * 
2914 	 * @returns {Array.<string>} an array of ISO 15924 codes for the scripts used 
2915 	 * to write text in this language
2916 	 */
2917 	getAllScripts: function() {
2918 		return this.info.scripts || ["Latn"];
2919 	},
2920 	
2921 	/**
2922 	 * Return the default style of meridiems used in this locale. Meridiems are 
2923 	 * times of day like AM/PM. In a few locales with some calendars, for example
2924 	 * Amharic/Ethiopia using the Ethiopic calendar, the times of day may be
2925 	 * split into different segments than simple AM/PM as in the Gregorian 
2926 	 * calendar. Only a few locales are like that. For most locales, formatting 
2927 	 * a Gregorian date will use the regular Gregorian AM/PM meridiems.
2928 	 *  
2929 	 * @returns {string} the default meridiems style used in this locale. Possible
2930 	 * values are "gregorian", "chinese", and "ethiopic"
2931 	 */
2932 	getMeridiemsStyle: function () {
2933 		return this.info.meridiems || "gregorian";
2934 	}	
2935 };
2936 
2937 
2938 
2939 /*< IDate.js */
2940 /*
2941  * IDate.js - Represent a date in any calendar. This class is subclassed for each 
2942  * calendar and includes some shared functionality.
2943  * 
2944  * Copyright © 2012-2015, JEDLSoft
2945  *
2946  * Licensed under the Apache License, Version 2.0 (the "License");
2947  * you may not use this file except in compliance with the License.
2948  * You may obtain a copy of the License at
2949  *
2950  *     http://www.apache.org/licenses/LICENSE-2.0
2951  *
2952  * Unless required by applicable law or agreed to in writing, software
2953  * distributed under the License is distributed on an "AS IS" BASIS,
2954  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2955  *
2956  * See the License for the specific language governing permissions and
2957  * limitations under the License.
2958  */
2959 
2960 /* !depends LocaleInfo.js */
2961 
2962 
2963 /**
2964  * @class
2965  * Superclass for all the calendar date classes that contains shared 
2966  * functionality. This class is never instantiated on its own. Instead,
2967  * you should use the {@link DateFactory} function to manufacture a new
2968  * instance of a subclass of IDate. This class is called IDate for "ilib
2969  * date" so that it does not conflict with the built-in Javascript Date
2970  * class.
2971  * 
2972  * @private
2973  * @constructor
2974  * @param {Object=} options The date components to initialize this date with
2975  */
2976 var IDate = function(options) {
2977 };
2978 
2979 /* place for the subclasses to put their constructors so that the factory method
2980  * can find them. Do this to add your date after it's defined: 
2981  * IDate._constructors["mytype"] = IDate.MyTypeConstructor;
2982  */
2983 IDate._constructors = {};
2984 
2985 IDate.prototype = {
2986 	getType: function() {
2987 		return "date";
2988 	},
2989 	
2990 	/**
2991 	 * Return the unix time equivalent to this date instance. Unix time is
2992 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC (Gregorian). This 
2993 	 * method only returns a valid number for dates between midnight, 
2994 	 * Jan 1, 1970 UTC (Gregorian) and Jan 19, 2038 at 3:14:07am UTC (Gregorian) when 
2995 	 * the unix time runs out. If this instance encodes a date outside of that range, 
2996 	 * this method will return -1. For date types that are not Gregorian, the point 
2997 	 * in time represented by this date object will only give a return value if it
2998 	 * is in the correct range in the Gregorian calendar as given previously.
2999 	 * 
3000 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
3001 	 * valid unix time range
3002 	 */
3003 	getTime: function() {
3004 		return this.rd.getTime(); 
3005 	},
3006 	
3007 	/**
3008 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
3009 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
3010 	 * (or the type "time_t" in C/C++) is only encoded with an unsigned 32 bit integer, and thus 
3011 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
3012 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
3013 	 * after Jan 1, 1970, and even more interestingly, 100 million days worth of time before
3014 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
3015 	 * range. If this instance encodes a date outside of that range, this method will return
3016 	 * NaN.
3017 	 * 
3018 	 * @return {number} a number giving the extended unix time, or Nan if the date is outside 
3019 	 * the valid extended unix time range
3020 	 */
3021 	getTimeExtended: function() {
3022 		return this.rd.getTimeExtended();
3023 	},
3024 
3025 	/**
3026 	 * Set the time of this instance according to the given unix time. Unix time is
3027 	 * the number of milliseconds since midnight on Jan 1, 1970.
3028 	 * 
3029 	 * @param {number} millis the unix time to set this date to in milliseconds 
3030 	 */
3031 	setTime: function(millis) {
3032 		this.rd = this.newRd({
3033 			unixtime: millis,
3034 			cal: this.cal
3035 		});
3036 		this._calcDateComponents();
3037 	},
3038 	
3039 	getDays: function() {
3040 		return this.day;
3041 	},
3042 	getMonths: function() {
3043 		return this.month;
3044 	},
3045 	getYears: function() {
3046 		return this.year;
3047 	},
3048 	getHours: function() {
3049 		return this.hour;
3050 	},
3051 	getMinutes: function() {
3052 		return this.minute;
3053 	},
3054 	getSeconds: function() {
3055 		return this.second;
3056 	},
3057 	getMilliseconds: function() {
3058 		return this.millisecond;
3059 	},
3060 	getEra: function() {
3061 		return (this.year < 1) ? -1 : 1;
3062 	},
3063 
3064 	setDays: function(day) {
3065 		this.day = parseInt(day, 10) || 1;
3066 		this.rd._setDateComponents(this);
3067 	},
3068 	setMonths: function(month) {
3069 		this.month = parseInt(month, 10) || 1;
3070 		this.rd._setDateComponents(this);
3071 	},
3072 	setYears: function(year) {
3073 		this.year = parseInt(year, 10) || 0;
3074 		this.rd._setDateComponents(this);
3075 	},
3076 	
3077 	setHours: function(hour) {
3078 		this.hour = parseInt(hour, 10) || 0;
3079 		this.rd._setDateComponents(this);
3080 	},
3081 	setMinutes: function(minute) {
3082 		this.minute = parseInt(minute, 10) || 0;
3083 		this.rd._setDateComponents(this);
3084 	},
3085 	setSeconds: function(second) {
3086 		this.second = parseInt(second, 10) || 0;
3087 		this.rd._setDateComponents(this);
3088 	},
3089 	setMilliseconds: function(milli) {
3090 		this.millisecond = parseInt(milli, 10) || 0;
3091 		this.rd._setDateComponents(this);
3092 	},
3093 	
3094 	/**
3095 	 * Return a new date instance in the current calendar that represents the first instance 
3096 	 * of the given day of the week before the current date. The day of the week is encoded
3097 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3098 	 * 
3099 	 * @param {number} dow the day of the week before the current date that is being sought
3100 	 * @return {IDate} the date being sought
3101 	 */
3102 	before: function (dow) {
3103 		return new this.constructor({
3104 			rd: this.rd.before(dow, this.offset),
3105 			timezone: this.timezone
3106 		});
3107 	},
3108 	
3109 	/**
3110 	 * Return a new date instance in the current calendar that represents the first instance 
3111 	 * of the given day of the week after the current date. The day of the week is encoded
3112 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3113 	 * 
3114 	 * @param {number} dow the day of the week after the current date that is being sought
3115 	 * @return {IDate} the date being sought
3116 	 */
3117 	after: function (dow) {
3118 		return new this.constructor({
3119 			rd: this.rd.after(dow, this.offset),
3120 			timezone: this.timezone
3121 		});
3122 	},
3123 
3124 	/**
3125 	 * Return a new Gregorian date instance that represents the first instance of the 
3126 	 * given day of the week on or before the current date. The day of the week is encoded
3127 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3128 	 * 
3129 	 * @param {number} dow the day of the week on or before the current date that is being sought
3130 	 * @return {IDate} the date being sought
3131 	 */
3132 	onOrBefore: function (dow) {
3133 		return new this.constructor({
3134 			rd: this.rd.onOrBefore(dow, this.offset),
3135 			timezone: this.timezone
3136 		});
3137 	},
3138 
3139 	/**
3140 	 * Return a new Gregorian date instance that represents the first instance of the 
3141 	 * given day of the week on or after the current date. The day of the week is encoded
3142 	 * as a number where 0 = Sunday, 1 = Monday, etc.
3143 	 * 
3144 	 * @param {number} dow the day of the week on or after the current date that is being sought
3145 	 * @return {IDate} the date being sought
3146 	 */
3147 	onOrAfter: function (dow) {
3148 		return new this.constructor({
3149 			rd: this.rd.onOrAfter(dow, this.offset),
3150 			timezone: this.timezone
3151 		});
3152 	},
3153 	
3154 	/**
3155 	 * Return a Javascript Date object that is equivalent to this date
3156 	 * object.
3157 	 * 
3158 	 * @return {Date|undefined} a javascript Date object
3159 	 */
3160 	getJSDate: function() {
3161 		var unix = this.rd.getTimeExtended();
3162 		return isNaN(unix) ? undefined : new Date(unix); 
3163 	},
3164 	
3165 	/**
3166 	 * Return the Rata Die (fixed day) number of this date.
3167 	 * 
3168 	 * @protected
3169 	 * @return {number} the rd date as a number
3170 	 */
3171 	getRataDie: function() {
3172 		return this.rd.getRataDie();
3173 	},
3174 	
3175 	/**
3176 	 * Set the date components of this instance based on the given rd.
3177 	 * @protected
3178 	 * @param {number} rd the rata die date to set
3179 	 */
3180 	setRd: function (rd) {
3181 		this.rd = this.newRd({
3182 			rd: rd,
3183 			cal: this.cal
3184 		});
3185 		this._calcDateComponents();
3186 	},
3187 	
3188 	/**
3189 	 * Return the Julian Day equivalent to this calendar date as a number.
3190 	 * 
3191 	 * @return {number} the julian date equivalent of this date
3192 	 */
3193 	getJulianDay: function() {
3194 		return this.rd.getJulianDay();
3195 	},
3196 	
3197 	/**
3198 	 * Set the date of this instance using a Julian Day.
3199 	 * @param {number|JulianDay} date the Julian Day to use to set this date
3200 	 */
3201 	setJulianDay: function (date) {
3202 		this.rd = this.newRd({
3203 			julianday: (typeof(date) === 'object') ? date.getDate() : date,
3204 			cal: this.cal
3205 		});
3206 		this._calcDateComponents();
3207 	},
3208 
3209 	/**
3210 	 * Return the time zone associated with this date, or 
3211 	 * undefined if none was specified in the constructor.
3212 	 * 
3213 	 * @return {string|undefined} the name of the time zone for this date instance
3214 	 */
3215 	getTimeZone: function() {
3216 		return this.timezone || "local";
3217 	},
3218 	
3219 	/**
3220 	 * Set the time zone associated with this date.
3221 	 * @param {string=} tzName the name of the time zone to set into this date instance,
3222 	 * or "undefined" to unset the time zone 
3223 	 */
3224 	setTimeZone: function (tzName) {
3225 		if (!tzName || tzName === "") {
3226 			// same as undefining it
3227 			this.timezone = undefined;
3228 			this.tz = undefined;
3229 		} else if (typeof(tzName) === 'string') {
3230 			this.timezone = tzName;
3231 			this.tz = undefined;
3232 			// assuming the same UTC time, but a new time zone, now we have to 
3233 			// recalculate what the date components are
3234 			this._calcDateComponents();
3235 		}
3236 	},
3237 	
3238 	/**
3239 	 * Return the rd number of the first Sunday of the given ISO year.
3240 	 * @protected
3241 	 * @param {number} year the year for which the first Sunday is being sought
3242 	 * @return {number} the rd of the first Sunday of the ISO year
3243 	 */
3244 	firstSunday: function (year) {
3245 		var firstDay = this.newRd({
3246 			year: year,
3247 			month: 1,
3248 			day: 1,
3249 			hour: 0,
3250 			minute: 0,
3251 			second: 0,
3252 			millisecond: 0,
3253 			cal: this.cal
3254 		});
3255 		var firstThu = this.newRd({
3256 			rd: firstDay.onOrAfter(4),
3257 			cal: this.cal
3258 		});
3259 		return firstThu.before(0);
3260 	},
3261 	
3262 	/**
3263 	 * Return the ISO 8601 week number in the current year for the current date. The week
3264 	 * number ranges from 0 to 55, as some years have 55 weeks assigned to them in some
3265 	 * calendars.
3266 	 * 
3267 	 * @return {number} the week number for the current date
3268 	 */
3269 	getWeekOfYear: function() {
3270 		var rd = Math.floor(this.rd.getRataDie());
3271 		var year = this._calcYear(rd + this.offset);
3272 		var yearStart = this.firstSunday(year);
3273 		var nextYear;
3274 		
3275 		// if we have a January date, it may be in this ISO year or the previous year
3276 		if (rd < yearStart) {
3277 			yearStart = this.firstSunday(year-1);
3278 		} else {
3279 			// if we have a late December date, it may be in this ISO year, or the next year
3280 			nextYear = this.firstSunday(year+1);
3281 			if (rd >= nextYear) {
3282 				yearStart = nextYear;
3283 			}
3284 		}
3285 		
3286 		return Math.floor((rd-yearStart)/7) + 1;
3287 	},
3288 	
3289 	/**
3290 	 * Return the ordinal number of the week within the month. The first week of a month is
3291 	 * the first one that contains 4 or more days in that month. If any days precede this
3292 	 * first week, they are marked as being in week 0. This function returns values from 0
3293 	 * through 6.<p>
3294 	 * 
3295 	 * The locale is a required parameter because different locales that use the same 
3296 	 * Gregorian calendar consider different days of the week to be the beginning of
3297 	 * the week. This can affect the week of the month in which some days are located.
3298 	 * 
3299 	 * @param {Locale|string} locale the locale or locale spec to use when figuring out 
3300 	 * the first day of the week
3301 	 * @return {number} the ordinal number of the week within the current month
3302 	 */
3303 	getWeekOfMonth: function(locale) {
3304 		var li = new LocaleInfo(locale);
3305 		
3306 		var first = this.newRd({
3307 			year: this._calcYear(this.rd.getRataDie()+this.offset),
3308 			month: this.getMonths(),
3309 			day: 1,
3310 			hour: 0,
3311 			minute: 0,
3312 			second: 0,
3313 			millisecond: 0,
3314 			cal: this.cal
3315 		});
3316 		var weekStart = first.onOrAfter(li.getFirstDayOfWeek());
3317 		
3318 		if (weekStart - first.getRataDie() > 3) {
3319 			// if the first week has 4 or more days in it of the current month, then consider
3320 			// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
3321 			// one week earlier.
3322 			weekStart -= 7;
3323 		}
3324 		return Math.floor((this.rd.getRataDie() - weekStart) / 7) + 1;
3325 	}
3326 };
3327 
3328 
3329 /*< MathUtils.js */
3330 /*
3331  * MathUtils.js - Misc math utility routines
3332  * 
3333  * Copyright © 2013-2015, JEDLSoft
3334  *
3335  * Licensed under the Apache License, Version 2.0 (the "License");
3336  * you may not use this file except in compliance with the License.
3337  * You may obtain a copy of the License at
3338  *
3339  *     http://www.apache.org/licenses/LICENSE-2.0
3340  *
3341  * Unless required by applicable law or agreed to in writing, software
3342  * distributed under the License is distributed on an "AS IS" BASIS,
3343  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3344  *
3345  * See the License for the specific language governing permissions and
3346  * limitations under the License.
3347  */
3348 
3349 var MathUtils = {};
3350 
3351 /**
3352  * Return the sign of the given number. If the sign is negative, this function
3353  * returns -1. If the sign is positive or zero, this function returns 1.
3354  * @static
3355  * @param {number} num the number to test
3356  * @return {number} -1 if the number is negative, and 1 otherwise
3357  */
3358 MathUtils.signum = function (num) {
3359 	var n = num;
3360 	if (typeof(num) === 'string') {
3361 		n = parseInt(num, 10);
3362 	} else if (typeof(num) !== 'number') {
3363 		return 1;
3364 	}
3365 	return (n < 0) ? -1 : 1;
3366 };
3367 
3368 /**
3369  * @static
3370  * @protected
3371  * @param {number} num number to round
3372  * @return {number} rounded number
3373  */
3374 MathUtils.floor = function (num) {
3375 	return Math.floor(num);
3376 };
3377 
3378 /**
3379  * @static
3380  * @protected
3381  * @param {number} num number to round
3382  * @return {number} rounded number
3383  */
3384 MathUtils.ceiling = function (num) {
3385 	return Math.ceil(num);
3386 };
3387 
3388 /**
3389  * @static
3390  * @protected
3391  * @param {number} num number to round
3392  * @return {number} rounded number
3393  */
3394 MathUtils.down = function (num) {
3395 	return (num < 0) ? Math.ceil(num) : Math.floor(num);
3396 };
3397 
3398 /**
3399  * @static
3400  * @protected
3401  * @param {number} num number to round
3402  * @return {number} rounded number
3403  */
3404 MathUtils.up = function (num) {
3405 	return (num < 0) ? Math.floor(num) : Math.ceil(num);
3406 };
3407 
3408 /**
3409  * @static
3410  * @protected
3411  * @param {number} num number to round
3412  * @return {number} rounded number
3413  */
3414 MathUtils.halfup = function (num) {
3415 	return (num < 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3416 };
3417 
3418 /**
3419  * @static
3420  * @protected
3421  * @param {number} num number to round
3422  * @return {number} rounded number
3423  */
3424 MathUtils.halfdown = function (num) {
3425 	return (num < 0) ? Math.floor(num + 0.5) : Math.ceil(num - 0.5);
3426 };
3427 
3428 /**
3429  * @static
3430  * @protected
3431  * @param {number} num number to round
3432  * @return {number} rounded number
3433  */
3434 MathUtils.halfeven = function (num) {
3435 	return (Math.floor(num) % 2 === 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3436 };
3437 
3438 /**
3439  * @static
3440  * @protected
3441  * @param {number} num number to round
3442  * @return {number} rounded number
3443  */
3444 MathUtils.halfodd = function (num) {
3445 	return (Math.floor(num) % 2 !== 0) ? Math.ceil(num - 0.5) : Math.floor(num + 0.5);
3446 };
3447 
3448 /**
3449  * Do a proper modulo function. The Javascript % operator will give the truncated
3450  * division algorithm, but for calendrical calculations, we need the Euclidean
3451  * division algorithm where the remainder of any division, whether the dividend
3452  * is negative or not, is always a positive number in the range [0, modulus).<p>
3453  * 
3454  * 
3455  * @static
3456  * @param {number} dividend the number being divided
3457  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3458  * @return the remainder of dividing the dividend by the modulus.  
3459  */
3460 MathUtils.mod = function (dividend, modulus) {
3461 	if (modulus == 0) {
3462 		return 0;
3463 	}
3464 	var x = dividend % modulus;
3465 	return (x < 0) ? x + modulus : x;
3466 };
3467 
3468 /**
3469  * Do a proper adjusted modulo function. The Javascript % operator will give the truncated
3470  * division algorithm, but for calendrical calculations, we need the Euclidean
3471  * division algorithm where the remainder of any division, whether the dividend
3472  * is negative or not, is always a positive number in the range (0, modulus]. The adjusted
3473  * modulo function differs from the regular modulo function in that when the remainder is
3474  * zero, the modulus should be returned instead.<p>
3475  * 
3476  * 
3477  * @static
3478  * @param {number} dividend the number being divided
3479  * @param {number} modulus the number dividing the dividend. This should always be a positive number.
3480  * @return the remainder of dividing the dividend by the modulus.  
3481  */
3482 MathUtils.amod = function (dividend, modulus) {
3483 	if (modulus == 0) {
3484 		return 0;
3485 	}
3486 	var x = dividend % modulus;
3487 	return (x <= 0) ? x + modulus : x;
3488 };
3489 
3490 
3491 
3492 /*< IString.js */
3493 /*
3494  * IString.js - ilib string subclass definition
3495  * 
3496  * Copyright © 2012-2015, JEDLSoft
3497  *
3498  * Licensed under the Apache License, Version 2.0 (the "License");
3499  * you may not use this file except in compliance with the License.
3500  * You may obtain a copy of the License at
3501  *
3502  *     http://www.apache.org/licenses/LICENSE-2.0
3503  *
3504  * Unless required by applicable law or agreed to in writing, software
3505  * distributed under the License is distributed on an "AS IS" BASIS,
3506  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3507  *
3508  * See the License for the specific language governing permissions and
3509  * limitations under the License.
3510  */
3511 
3512 // !depends ilib.js Utils.js Locale.js MathUtils.js
3513 
3514 // !data plurals
3515 
3516 
3517 /**
3518  * @class
3519  * Create a new ilib string instance. This string inherits from and
3520  * extends the Javascript String class. It can be
3521  * used almost anywhere that a normal Javascript string is used, though in
3522  * some instances you will need to call the {@link #toString} method when
3523  * a built-in Javascript string is needed. The formatting methods are 
3524  * methods that are not in the intrinsic String class and are most useful
3525  * when localizing strings in an app or web site in combination with 
3526  * the ResBundle class.<p>
3527  * 
3528  * This class is named IString ("ilib string") so as not to conflict with the 
3529  * built-in Javascript String class.
3530  * 
3531  * @constructor
3532  * @param {string|IString=} string initialize this instance with this string 
3533  */
3534 var IString = function (string) {
3535 	if (typeof(string) === 'object') {
3536 		if (string instanceof IString) {
3537 			this.str = string.str;	
3538 		} else {
3539 			this.str = string.toString();
3540 		}
3541 	} else if (typeof(string) === 'string') {
3542 		this.str = new String(string);
3543 	} else {
3544 		this.str = "";
3545 	}
3546 	this.length = this.str.length;
3547 	this.cpLength = -1;
3548 	this.localeSpec = ilib.getLocale();
3549 };
3550 
3551 /**
3552  * Return true if the given character is a Unicode surrogate character,
3553  * either high or low.
3554  * 
3555  * @private
3556  * @static
3557  * @param {string} ch character to check
3558  * @return {boolean} true if the character is a surrogate
3559  */
3560 IString._isSurrogate = function (ch) {
3561 	var n = ch.charCodeAt(0);
3562 	return ((n >= 0xDC00 && n <= 0xDFFF) || (n >= 0xD800 && n <= 0xDBFF));
3563 };
3564 
3565 /**
3566  * Convert a UCS-4 code point to a Javascript string. The codepoint can be any valid 
3567  * UCS-4 Unicode character, including supplementary characters. Standard Javascript
3568  * only supports supplementary characters using the UTF-16 encoding, which has 
3569  * values in the range 0x0000-0xFFFF. String.fromCharCode() will only
3570  * give you a string containing 16-bit characters, and will not properly convert 
3571  * the code point for a supplementary character (which has a value > 0xFFFF) into 
3572  * two UTF-16 surrogate characters. Instead, it will just just give you whatever
3573  * single character happens to be the same as your code point modulo 0x10000, which
3574  * is almost never what you want.<p> 
3575  * 
3576  * Similarly, that means if you use String.charCodeAt()
3577  * you will only retrieve a 16-bit value, which may possibly be a single
3578  * surrogate character that is part of a surrogate pair representing a character
3579  * in the supplementary plane. It will not give you a code point. Use 
3580  * IString.codePointAt() to access code points in a string, or use 
3581  * an iterator to walk through the code points in a string. 
3582  * 
3583  * @static
3584  * @param {number} codepoint UCS-4 code point to convert to a character
3585  * @return {string} a string containing the character represented by the codepoint
3586  */
3587 IString.fromCodePoint = function (codepoint) {
3588 	if (codepoint < 0x10000) {
3589 		return String.fromCharCode(codepoint);
3590 	} else {
3591 		var high = Math.floor(codepoint / 0x10000) - 1;
3592 		var low = codepoint & 0xFFFF;
3593 		
3594 		return String.fromCharCode(0xD800 | ((high & 0x000F) << 6) |  ((low & 0xFC00) >> 10)) +
3595 			String.fromCharCode(0xDC00 | (low & 0x3FF));
3596 	}
3597 };
3598 
3599 /**
3600  * Convert the character or the surrogate pair at the given
3601  * index into the intrinsic Javascript string to a Unicode 
3602  * UCS-4 code point.
3603  * 
3604  * @param {string} str string to get the code point from
3605  * @param {number} index index into the string
3606  * @return {number} code point of the character at the
3607  * given index into the string
3608  */
3609 IString.toCodePoint = function(str, index) {
3610 	if (!str || str.length === 0) {
3611 		return -1;
3612 	}
3613 	var code = -1, high = str.charCodeAt(index);
3614 	if (high >= 0xD800 && high <= 0xDBFF) {
3615 		if (str.length > index+1) {
3616 			var low = str.charCodeAt(index+1);
3617 			if (low >= 0xDC00 && low <= 0xDFFF) {
3618 				code = (((high & 0x3C0) >> 6) + 1) << 16 |
3619 					(((high & 0x3F) << 10) | (low & 0x3FF));
3620 			}
3621 		}
3622 	} else {
3623 		code = high;
3624 	}
3625 	
3626 	return code;
3627 };
3628 
3629 /**
3630  * Load the plural the definitions of plurals for the locale.
3631  * @param {boolean=} sync
3632  * @param {Locale|string=} locale
3633  * @param {Object=} loadParams
3634  * @param {function(*)=} onLoad
3635  */
3636 IString.loadPlurals = function (sync, locale, loadParams, onLoad) {
3637 	var loc;
3638 	if (locale) {
3639 		loc = (typeof(locale) === 'string') ? new Locale(locale) : locale;
3640 	} else {
3641 		loc = new Locale(ilib.getLocale());
3642 	}
3643 	var spec = loc.getLanguage();
3644 	if (!ilib.data["plurals_" + spec]) {
3645 		Utils.loadData({
3646 			name: "plurals.json",
3647 			object: IString,
3648 			locale: loc,
3649 			sync: sync,
3650 			loadParams: loadParams,
3651 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(plurals) {
3652 				if (!plurals) {
3653 					IString.cache[spec] = {};
3654 				}
3655 				ilib.data["plurals_" + spec] = plurals || {};
3656 				if (onLoad && typeof(onLoad) === 'function') {
3657 					onLoad(ilib.data["plurals_" + spec]);
3658 				}
3659 			})
3660 		});
3661 	} else {
3662 		if (onLoad && typeof(onLoad) === 'function') {
3663 			onLoad(ilib.data["plurals_" + spec]);
3664 		}
3665 	}
3666 };
3667 
3668 /**
3669  * @private
3670  * @static
3671  */
3672 IString._fncs = {
3673 	/**
3674 	 * @private
3675 	 * @param {Object} obj
3676 	 * @return {string|undefined}
3677 	 */
3678 	firstProp: function (obj) {
3679 		for (var p in obj) {
3680 			if (p && obj[p]) {
3681 				return p;
3682 			}
3683 		}
3684 		return undefined; // should never get here
3685 	},
3686 	
3687 	/**
3688 	 * @private
3689 	 * @param {Object} obj
3690 	 * @param {number} n
3691 	 * @return {?}
3692 	 */
3693 	getValue: function (obj, n) {
3694 		if (typeof(obj) === 'object') {
3695 			var subrule = IString._fncs.firstProp(obj);
3696 			return IString._fncs[subrule](obj[subrule], n);
3697 		} else if (typeof(obj) === 'string') {
3698 			return n;
3699 		} else {
3700 			return obj;
3701 		}
3702 	},
3703 	
3704 	/**
3705 	 * @private
3706 	 * @param {number} n
3707 	 * @param {Array.<number|Array.<number>>} range
3708 	 * @return {boolean}
3709 	 */
3710 	matchRangeContinuous: function(n, range) {
3711 		for (var num in range) {
3712 			if (typeof(num) !== 'undefined' && typeof(range[num]) !== 'undefined') {
3713 				var obj = /** @type {Object|null|undefined} */ range[num];
3714 				if (typeof(obj) === 'number') {
3715 					if (n === range[num]) {
3716 						return true;
3717 					}
3718 				} else if (Object.prototype.toString.call(obj) === '[object Array]') {
3719 					if (n >= obj[0] && n <= obj[1]) {
3720 						return true;
3721 					}
3722 				}
3723 			}
3724 		}
3725 		return false;
3726 	},
3727 
3728 	/**
3729 	 * @private
3730 	 * @param {number} n
3731 	 * @param {Array.<number|Array.<number>>} range
3732 	 * @return {boolean}
3733 	 */
3734 	matchRange: function(n, range) {
3735 		if (Math.floor(n) !== n) {
3736 			return false;
3737 		}
3738 		return IString._fncs.matchRangeContinuous(n, range);
3739 	},
3740 	
3741 	/**
3742 	 * @private
3743 	 * @param {Object} rule
3744 	 * @param {number} n
3745 	 * @return {boolean}
3746 	 */
3747 	is: function(rule, n) {
3748 		var left = IString._fncs.getValue(rule[0], n);
3749 		var right = IString._fncs.getValue(rule[1], n);
3750 		return left == right;
3751 		// return IString._fncs.getValue(rule[0]) == IString._fncs.getValue(rule[1]);
3752 	},
3753 	
3754 	/**
3755 	 * @private
3756 	 * @param {Object} rule
3757 	 * @param {number} n
3758 	 * @return {boolean}
3759 	 */
3760 	isnot: function(rule, n) {
3761 		return IString._fncs.getValue(rule[0], n) != IString._fncs.getValue(rule[1], n);
3762 	},
3763 	
3764 	/**
3765 	 * @private
3766 	 * @param {Object} rule
3767 	 * @param {number} n
3768 	 * @return {boolean}
3769 	 */
3770 	inrange: function(rule, n) {
3771 		return IString._fncs.matchRange(IString._fncs.getValue(rule[0], n), rule[1]);
3772 	},
3773 	
3774 	/**
3775 	 * @private
3776 	 * @param {Object} rule
3777 	 * @param {number} n
3778 	 * @return {boolean}
3779 	 */
3780 	notin: function(rule, n) {
3781 		return !IString._fncs.matchRange(IString._fncs.getValue(rule[0], n), rule[1]);
3782 	},
3783 	
3784 	/**
3785 	 * @private
3786 	 * @param {Object} rule
3787 	 * @param {number} n
3788 	 * @return {boolean}
3789 	 */
3790 	within: function(rule, n) {
3791 		return IString._fncs.matchRangeContinuous(IString._fncs.getValue(rule[0], n), rule[1]);		
3792 	},
3793 	
3794 	/**
3795 	 * @private
3796 	 * @param {Object} rule
3797 	 * @param {number} n
3798 	 * @return {number}
3799 	 */
3800 	mod: function(rule, n) {
3801 		return MathUtils.mod(IString._fncs.getValue(rule[0], n), IString._fncs.getValue(rule[1], n));
3802 	},
3803 	
3804 	/**
3805 	 * @private
3806 	 * @param {Object} rule
3807 	 * @param {number} n
3808 	 * @return {number}
3809 	 */
3810 	n: function(rule, n) {
3811 		return n;
3812 	},
3813 	
3814 	/**
3815 	 * @private
3816 	 * @param {Object} rule
3817 	 * @param {number} n
3818 	 * @return {boolean}
3819 	 */
3820 	or: function(rule, n) {
3821 		return IString._fncs.getValue(rule[0], n) || IString._fncs.getValue(rule[1], n);
3822 	},
3823 	
3824 	/**
3825 	 * @private
3826 	 * @param {Object} rule
3827 	 * @param {number} n
3828 	 * @return {boolean}
3829 	 */
3830 	and: function(rule, n) {
3831 		return IString._fncs.getValue(rule[0], n) && IString._fncs.getValue(rule[1], n);
3832 	}
3833 };
3834 
3835 IString.prototype = {
3836 	/**
3837 	 * Return the length of this string in characters. This function defers to the regular
3838 	 * Javascript string class in order to perform the length function. Please note that this
3839 	 * method is a real method, whereas the length property of Javascript strings is 
3840 	 * implemented by native code and appears as a property.<p>
3841 	 * 
3842 	 * Example:
3843 	 * 
3844 	 * <pre>
3845 	 * var str = new IString("this is a string");
3846 	 * console.log("String is " + str._length() + " characters long.");
3847 	 * </pre>
3848 	 * @private
3849 	 */
3850 	_length: function () {
3851 		return this.str.length;
3852 	},
3853 	
3854 	/**
3855 	 * Format this string instance as a message, replacing the parameters with 
3856 	 * the given values.<p>
3857 	 * 
3858 	 * The string can contain any text that a regular Javascript string can
3859 	 * contain. Replacement parameters have the syntax:
3860 	 * 
3861 	 * <pre>
3862 	 * {name}
3863 	 * </pre>
3864 	 * 
3865 	 * Where "name" can be any string surrounded by curly brackets. The value of 
3866 	 * "name" is taken from the parameters argument.<p>
3867 	 * 
3868 	 * Example:
3869 	 * 
3870 	 * <pre>
3871 	 * var str = new IString("There are {num} objects.");
3872 	 * console.log(str.format({
3873 	 *   num: 12
3874 	 * });
3875 	 * </pre>
3876 	 * 
3877 	 * Would give the output:
3878 	 * 
3879 	 * <pre>
3880 	 * There are 12 objects.
3881 	 * </pre>
3882 	 * 
3883 	 * If a property is missing from the parameter block, the replacement
3884 	 * parameter substring is left untouched in the string, and a different
3885 	 * set of parameters may be applied a second time. This way, different
3886 	 * parts of the code may format different parts of the message that they
3887 	 * happen to know about.<p>
3888 	 * 
3889 	 * Example:
3890 	 * 
3891 	 * <pre>
3892 	 * var str = new IString("There are {num} objects in the {container}.");
3893 	 * console.log(str.format({
3894 	 *   num: 12
3895 	 * });
3896 	 * </pre>
3897 	 * 
3898 	 * Would give the output:<p>
3899 	 * 
3900 	 * <pre>
3901 	 * There are 12 objects in the {container}.
3902 	 * </pre>
3903 	 * 
3904 	 * The result can then be formatted again with a different parameter block that
3905 	 * specifies a value for the container property.
3906 	 * 
3907 	 * @param params a Javascript object containing values for the replacement 
3908 	 * parameters in the current string
3909 	 * @return a new IString instance with as many replacement parameters filled
3910 	 * out as possible with real values.
3911 	 */
3912 	format: function (params) {
3913 		var formatted = this.str;
3914 		if (params) {
3915 			var regex;
3916 			for (var p in params) {
3917 				if (typeof(params[p]) !== 'undefined') {
3918 					regex = new RegExp("\{"+p+"\}", "g");
3919 					formatted = formatted.replace(regex, params[p]);
3920 				}
3921 			}
3922 		}
3923 		return formatted.toString();
3924 	},
3925 	
3926 	/**
3927 	 * Format a string as one of a choice of strings dependent on the value of
3928 	 * a particular argument index.<p>
3929 	 * 
3930 	 * The syntax of the choice string is as follows. The string contains a
3931 	 * series of choices separated by a vertical bar character "|". Each choice
3932 	 * has a value or range of values to match followed by a hash character "#"
3933 	 * followed by the string to use if the variable matches the criteria.<p>
3934 	 * 
3935 	 * Example string:
3936 	 * 
3937 	 * <pre>
3938 	 * var num = 2;
3939 	 * var str = new IString("0#There are no objects.|1#There is one object.|2#There are {number} objects.");
3940 	 * console.log(str.formatChoice(num, {
3941 	 *   number: num
3942 	 * }));
3943 	 * </pre>
3944 	 * 
3945 	 * Gives the output:
3946 	 * 
3947 	 * <pre>
3948 	 * "There are 2 objects."
3949 	 * </pre>
3950 	 * 
3951 	 * The strings to format may contain replacement variables that will be formatted
3952 	 * using the format() method above and the params argument as a source of values
3953 	 * to use while formatting those variables.<p>
3954 	 * 
3955 	 * If the criterion for a particular choice is empty, that choice will be used
3956 	 * as the default one for use when none of the other choice's criteria match.<p>
3957 	 * 
3958 	 * Example string:
3959 	 * 
3960 	 * <pre>
3961 	 * var num = 22;
3962 	 * var str = new IString("0#There are no objects.|1#There is one object.|#There are {number} objects.");
3963 	 * console.log(str.formatChoice(num, {
3964 	 *   number: num
3965 	 * }));
3966 	 * </pre>
3967 	 * 
3968 	 * Gives the output:
3969 	 * 
3970 	 * <pre>
3971 	 * "There are 22 objects."
3972 	 * </pre>
3973 	 * 
3974 	 * If multiple choice patterns can match a given argument index, the first one 
3975 	 * encountered in the string will be used. If no choice patterns match the 
3976 	 * argument index, then the default choice will be used. If there is no default
3977 	 * choice defined, then this method will return an empty string.<p>
3978 	 * 
3979 	 * <b>Special Syntax</b><p>
3980 	 * 
3981 	 * For any choice format string, all of the patterns in the string should be
3982 	 * of a single type: numeric, boolean, or string/regexp. The type of the 
3983 	 * patterns is determined by the type of the argument index parameter.<p>
3984 	 * 
3985 	 * If the argument index is numeric, then some special syntax can be used 
3986 	 * in the patterns to match numeric ranges.<p>
3987 	 * 
3988 	 * <ul>
3989 	 * <li><i>>x</i> - match any number that is greater than x 
3990 	 * <li><i>>=x</i> - match any number that is greater than or equal to x
3991 	 * <li><i><x</i> - match any number that is less than x
3992 	 * <li><i><=x</i> - match any number that is less than or equal to x
3993 	 * <li><i>start-end</i> - match any number in the range [start,end)
3994 	 * <li><i>zero</i> - match any number in the class "zero". (See below for
3995 	 * a description of number classes.)
3996 	 * <li><i>one</i> - match any number in the class "one"
3997 	 * <li><i>two</i> - match any number in the class "two"
3998 	 * <li><i>few</i> - match any number in the class "few"
3999 	 * <li><i>many</i> - match any number in the class "many"
4000 	 * </ul>
4001 	 * 
4002 	 * A number class defines a set of numbers that receive a particular syntax
4003 	 * in the strings. For example, in Slovenian, integers ending in the digit
4004 	 * "1" are in the "one" class, including 1, 21, 31, ... 101, 111, etc.
4005 	 * Similarly, integers ending in the digit "2" are in the "two" class. 
4006 	 * Integers ending in the digits "3" or "4" are in the "few" class, and
4007 	 * every other integer is handled by the default string.<p>
4008 	 * 
4009 	 * The definition of what numbers are included in a class is locale-dependent.
4010 	 * They are defined in the data file plurals.json. If your string is in a
4011 	 * different locale than the default for ilib, you should call the setLocale()
4012 	 * method of the string instance before calling this method.<p> 
4013 	 * 
4014 	 * <b>Other Pattern Types</b><p>
4015 	 * 
4016 	 * If the argument index is a boolean, the string values "true" and "false" 
4017 	 * may appear as the choice patterns.<p>
4018 	 * 
4019 	 * If the argument index is of type string, then the choice patterns may contain
4020 	 * regular expressions, or static strings as degenerate regexps.
4021 	 * 
4022 	 * @param {*} argIndex The index into the choice array of the current parameter
4023 	 * @param {Object} params The hash of parameter values that replace the replacement 
4024 	 * variables in the string
4025 	 * @throws "syntax error in choice format pattern: " if there is a syntax error
4026 	 * @return {string} the formatted string
4027 	 */
4028 	formatChoice: function(argIndex, params) {
4029 		var choices = this.str.split("|");
4030 		var type = typeof(argIndex);
4031 		var limits = [];
4032 		var strings = [];
4033 		var i;
4034 		var parts;
4035 		var limit;
4036 		var arg;
4037 		var result = undefined;
4038 		var defaultCase = "";
4039 	
4040 		if (this.str.length === 0) {
4041 			// nothing to do
4042 			return "";
4043 		}
4044 		
4045 		// first parse all the choices
4046 		for (i = 0; i < choices.length; i++) {		
4047 			parts = choices[i].split("#");		
4048 			if (parts.length > 2) {
4049 				limits[i] = parts[0];
4050 				parts = parts.shift();			
4051 				strings[i] = parts.join("#");
4052 			} else if (parts.length === 2) {
4053 				limits[i] = parts[0];
4054 				strings[i] = parts[1];
4055 			} else {
4056 				// syntax error
4057 				throw "syntax error in choice format pattern: " + choices[i];
4058 			}		
4059 		}
4060 		
4061 		// then apply the argument index
4062 		for (i = 0; i < limits.length; i++) {
4063 			if (limits[i].length === 0) {
4064 				// this is default case
4065 				defaultCase = new IString(strings[i]);			
4066 			} else {
4067 				switch (type) {
4068 					case 'number':
4069 						arg = parseInt(argIndex, 10);
4070 											
4071 						if (limits[i].substring(0,2) === "<=") {						
4072 							limit = parseFloat(limits[i].substring(2));
4073 							if (arg <= limit) {
4074 								result = new IString(strings[i]);
4075 								i = limits.length;
4076 							}
4077 						} else if (limits[i].substring(0,2) === ">=") {						
4078 							limit = parseFloat(limits[i].substring(2));
4079 							if (arg >= limit) {
4080 								result = new IString(strings[i]);
4081 								i = limits.length;
4082 							}
4083 						} else if (limits[i].charAt(0) === "<") {						
4084 							limit = parseFloat(limits[i].substring(1));
4085 							if (arg < limit) {
4086 								result = new IString(strings[i]);
4087 								i = limits.length;
4088 							}
4089 						} else if (limits[i].charAt(0) === ">") {						
4090 							limit = parseFloat(limits[i].substring(1));
4091 							if (arg > limit) {
4092 								result = new IString(strings[i]);
4093 								i = limits.length;
4094 							}
4095 						} else {
4096 							this.locale = this.locale || new Locale(this.localeSpec);
4097 							switch (limits[i]) {
4098 								case "zero":
4099 								case "one":
4100 								case "two":
4101 								case "few":
4102 								case "many":
4103 									// CLDR locale-dependent number classes
4104 									var ruleset = ilib.data["plurals_" + this.locale.getLanguage()];
4105 									if (ruleset) {
4106 										var rule = ruleset[limits[i]];
4107 										if (IString._fncs.getValue(rule, arg)) {
4108 											result = new IString(strings[i]);
4109 											i = limits.length;
4110 										}
4111 									}
4112 									break;
4113 								default:
4114 									var dash = limits[i].indexOf("-");
4115 									if (dash !== -1) {							
4116 										// range
4117 										var start = limits[i].substring(0, dash);
4118 										var end = limits[i].substring(dash+1);							
4119 										if (arg >= parseInt(start, 10) && arg <= parseInt(end, 10)) {								
4120 											result = new IString(strings[i]);
4121 											i = limits.length;
4122 										}
4123 									} else if (arg === parseInt(limits[i], 10)) {							
4124 										// exact amount
4125 										result = new IString(strings[i]);
4126 										i = limits.length;
4127 									}
4128 									break;
4129 							}
4130 						}
4131 						break;
4132 					case 'boolean':					
4133 						if (limits[i] === "true" && argIndex === true) {						
4134 							result = new IString(strings[i]);
4135 							i = limits.length;
4136 						} else if (limits[i] === "false" && argIndex === false) {						
4137 							result = new IString(strings[i]);
4138 							i = limits.length;
4139 						}
4140 						break;
4141 					case 'string':					
4142 						var regexp = new RegExp(limits[i], "i");
4143 						if (regexp.test(argIndex)) {
4144 							result = new IString(strings[i]);
4145 							i = limits.length;
4146 						}
4147 						break;
4148 					case 'object':
4149 						throw "syntax error: fmtChoice parameter for the argument index cannot be an object";
4150 				}
4151 			}
4152 		}
4153 		
4154 		if (!result) {		
4155 			result = defaultCase || new IString("");
4156 		}
4157 		
4158 		result = result.format(params);
4159 		
4160 		return result.toString();
4161 	},
4162 	
4163 	// delegates
4164 	/**
4165 	 * Same as String.toString()
4166 	 * @return {string} this instance as regular Javascript string
4167 	 */
4168 	toString: function () {
4169 		return this.str.toString();
4170 	},
4171 	
4172 	/**
4173 	 * Same as String.valueOf()
4174 	 * @return {string} this instance as a regular Javascript string
4175 	 */
4176 	valueOf: function () {
4177 		return this.str.valueOf();
4178 	},
4179 	
4180 	/**
4181 	 * Same as String.charAt()
4182 	 * @param {number} index the index of the character being sought
4183 	 * @return {IString} the character at the given index
4184 	 */
4185 	charAt: function(index) {
4186 		return new IString(this.str.charAt(index));
4187 	},
4188 	
4189 	/**
4190 	 * Same as String.charCodeAt(). This only reports on 
4191 	 * 2-byte UCS-2 Unicode values, and does not take into
4192 	 * account supplementary characters encoded in UTF-16.
4193 	 * If you would like to take account of those characters,
4194 	 * use codePointAt() instead.
4195 	 * @param {number} index the index of the character being sought
4196 	 * @return {number} the character code of the character at the 
4197 	 * given index in the string 
4198 	 */
4199 	charCodeAt: function(index) {
4200 		return this.str.charCodeAt(index);
4201 	},
4202 	
4203 	/**
4204 	 * Same as String.concat()
4205 	 * @param {string} strings strings to concatenate to the current one
4206 	 * @return {IString} a concatenation of the given strings
4207 	 */
4208 	concat: function(strings) {
4209 		return new IString(this.str.concat(strings));
4210 	},
4211 	
4212 	/**
4213 	 * Same as String.indexOf()
4214 	 * @param {string} searchValue string to search for
4215 	 * @param {number} start index into the string to start searching, or
4216 	 * undefined to search the entire string
4217 	 * @return {number} index into the string of the string being sought,
4218 	 * or -1 if the string is not found 
4219 	 */
4220 	indexOf: function(searchValue, start) {
4221 		return this.str.indexOf(searchValue, start);
4222 	},
4223 	
4224 	/**
4225 	 * Same as String.lastIndexOf()
4226 	 * @param {string} searchValue string to search for
4227 	 * @param {number} start index into the string to start searching, or
4228 	 * undefined to search the entire string
4229 	 * @return {number} index into the string of the string being sought,
4230 	 * or -1 if the string is not found 
4231 	 */
4232 	lastIndexOf: function(searchValue, start) {
4233 		return this.str.lastIndexOf(searchValue, start);
4234 	},
4235 	
4236 	/**
4237 	 * Same as String.match()
4238 	 * @param {string} regexp the regular expression to match
4239 	 * @return {Array.<string>} an array of matches
4240 	 */
4241 	match: function(regexp) {
4242 		return this.str.match(regexp);
4243 	},
4244 	
4245 	/**
4246 	 * Same as String.replace()
4247 	 * @param {string} searchValue a regular expression to search for
4248 	 * @param {string} newValue the string to replace the matches with
4249 	 * @return {IString} a new string with all the matches replaced
4250 	 * with the new value
4251 	 */
4252 	replace: function(searchValue, newValue) {
4253 		return new IString(this.str.replace(searchValue, newValue));
4254 	},
4255 	
4256 	/**
4257 	 * Same as String.search()
4258 	 * @param {string} regexp the regular expression to search for
4259 	 * @return {number} position of the match, or -1 for no match
4260 	 */
4261 	search: function(regexp) {
4262 		return this.str.search(regexp);
4263 	},
4264 	
4265 	/**
4266 	 * Same as String.slice()
4267 	 * @param {number} start first character to include in the string
4268 	 * @param {number} end include all characters up to, but not including
4269 	 * the end character
4270 	 * @return {IString} a slice of the current string
4271 	 */
4272 	slice: function(start, end) {
4273 		return new IString(this.str.slice(start, end));
4274 	},
4275 	
4276 	/**
4277 	 * Same as String.split()
4278 	 * @param {string} separator regular expression to match to find
4279 	 * separations between the parts of the text
4280 	 * @param {number} limit maximum number of items in the final 
4281 	 * output array. Any items beyond that limit will be ignored.
4282 	 * @return {Array.<string>} the parts of the current string split 
4283 	 * by the separator
4284 	 */
4285 	split: function(separator, limit) {
4286 		return this.str.split(separator, limit);
4287 	},
4288 	
4289 	/**
4290 	 * Same as String.substr()
4291 	 * @param {number} start the index of the character that should 
4292 	 * begin the returned substring
4293 	 * @param {number} length the number of characters to return after
4294 	 * the start character.
4295 	 * @return {IString} the requested substring 
4296 	 */
4297 	substr: function(start, length) {
4298 		var plat = ilib._getPlatform();
4299 		if (plat === "qt" || plat === "rhino" || plat === "trireme") {
4300 			// qt and rhino have a broken implementation of substr(), so
4301 			// work around it
4302 			if (typeof(length) === "undefined") {
4303 				length = this.str.length - start;
4304 			}
4305 		}
4306 		return new IString(this.str.substr(start, length));
4307 	},
4308 	
4309 	/**
4310 	 * Same as String.substring()
4311 	 * @param {number} from the index of the character that should 
4312 	 * begin the returned substring
4313 	 * @param {number} to the index where to stop the extraction. If
4314 	 * omitted, extracts the rest of the string
4315 	 * @return {IString} the requested substring 
4316 	 */
4317 	substring: function(from, to) {
4318 		return this.str.substring(from, to);
4319 	},
4320 	
4321 	/**
4322 	 * Same as String.toLowerCase(). Note that this method is
4323 	 * not locale-sensitive. 
4324 	 * @return {IString} a string with the first character
4325 	 * lower-cased
4326 	 */
4327 	toLowerCase: function() {
4328 		return this.str.toLowerCase();
4329 	},
4330 	
4331 	/**
4332 	 * Same as String.toUpperCase(). Note that this method is
4333 	 * not locale-sensitive. Use toLocaleUpperCase() instead
4334 	 * to get locale-sensitive behaviour. 
4335 	 * @return {IString} a string with the first character
4336 	 * upper-cased
4337 	 */
4338 	toUpperCase: function() {
4339 		return this.str.toUpperCase();
4340 	},
4341 	
4342 	/**
4343 	 * Convert the character or the surrogate pair at the given
4344 	 * index into the string to a Unicode UCS-4 code point.
4345 	 * @protected
4346 	 * @param {number} index index into the string
4347 	 * @return {number} code point of the character at the
4348 	 * given index into the string
4349 	 */
4350 	_toCodePoint: function (index) {
4351 		return IString.toCodePoint(this.str, index);
4352 	},
4353 	
4354 	/**
4355 	 * Call the callback with each character in the string one at 
4356 	 * a time, taking care to step through the surrogate pairs in 
4357 	 * the UTF-16 encoding properly.<p>
4358 	 * 
4359 	 * The standard Javascript String's charAt() method only
4360 	 * returns a particular 16-bit character in the 
4361 	 * UTF-16 encoding scheme.
4362 	 * If the index to charAt() is pointing to a low- or 
4363 	 * high-surrogate character,
4364 	 * it will return the surrogate character rather 
4365 	 * than the the character 
4366 	 * in the supplementary planes that the two surrogates together 
4367 	 * encode. This function will call the callback with the full
4368 	 * character, making sure to join two  
4369 	 * surrogates into one character in the supplementary planes
4370 	 * where necessary.<p>
4371 	 * 
4372 	 * @param {function(string)} callback a callback function to call with each
4373 	 * full character in the current string
4374 	 */
4375 	forEach: function(callback) {
4376 		if (typeof(callback) === 'function') {
4377 			var it = this.charIterator();
4378 			while (it.hasNext()) {
4379 				callback(it.next());
4380 			}
4381 		}
4382 	},
4383 
4384 	/**
4385 	 * Call the callback with each numeric code point in the string one at 
4386 	 * a time, taking care to step through the surrogate pairs in 
4387 	 * the UTF-16 encoding properly.<p>
4388 	 * 
4389 	 * The standard Javascript String's charCodeAt() method only
4390 	 * returns information about a particular 16-bit character in the 
4391 	 * UTF-16 encoding scheme.
4392 	 * If the index to charCodeAt() is pointing to a low- or 
4393 	 * high-surrogate character,
4394 	 * it will return the code point of the surrogate character rather 
4395 	 * than the code point of the character 
4396 	 * in the supplementary planes that the two surrogates together 
4397 	 * encode. This function will call the callback with the full
4398 	 * code point of each character, making sure to join two  
4399 	 * surrogates into one code point in the supplementary planes.<p>
4400 	 * 
4401 	 * @param {function(string)} callback a callback function to call with each
4402 	 * code point in the current string
4403 	 */
4404 	forEachCodePoint: function(callback) {
4405 		if (typeof(callback) === 'function') {
4406 			var it = this.iterator();
4407 			while (it.hasNext()) {
4408 				callback(it.next());
4409 			}
4410 		}
4411 	},
4412 
4413 	/**
4414 	 * Return an iterator that will step through all of the characters
4415 	 * in the string one at a time and return their code points, taking 
4416 	 * care to step through the surrogate pairs in UTF-16 encoding 
4417 	 * properly.<p>
4418 	 * 
4419 	 * The standard Javascript String's charCodeAt() method only
4420 	 * returns information about a particular 16-bit character in the 
4421 	 * UTF-16 encoding scheme.
4422 	 * If the index is pointing to a low- or high-surrogate character,
4423 	 * it will return a code point of the surrogate character rather 
4424 	 * than the code point of the character 
4425 	 * in the supplementary planes that the two surrogates together 
4426 	 * encode.<p>
4427 	 * 
4428 	 * The iterator instance returned has two methods, hasNext() which
4429 	 * returns true if the iterator has more code points to iterate through,
4430 	 * and next() which returns the next code point as a number.<p>
4431 	 * 
4432 	 * @return {Object} an iterator 
4433 	 * that iterates through all the code points in the string
4434 	 */
4435 	iterator: function() {
4436 		/**
4437 		 * @constructor
4438 		 */
4439 		function _iterator (istring) {
4440 			this.index = 0;
4441 			this.hasNext = function () {
4442 				return (this.index < istring.str.length);
4443 			};
4444 			this.next = function () {
4445 				if (this.index < istring.str.length) {
4446 					var num = istring._toCodePoint(this.index);
4447 					this.index += ((num > 0xFFFF) ? 2 : 1);
4448 				} else {
4449 					num = -1;
4450 				}
4451 				return num;
4452 			};
4453 		};
4454 		return new _iterator(this);
4455 	},
4456 
4457 	/**
4458 	 * Return an iterator that will step through all of the characters
4459 	 * in the string one at a time, taking 
4460 	 * care to step through the surrogate pairs in UTF-16 encoding 
4461 	 * properly.<p>
4462 	 * 
4463 	 * The standard Javascript String's charAt() method only
4464 	 * returns information about a particular 16-bit character in the 
4465 	 * UTF-16 encoding scheme.
4466 	 * If the index is pointing to a low- or high-surrogate character,
4467 	 * it will return that surrogate character rather 
4468 	 * than the surrogate pair which represents a character 
4469 	 * in the supplementary planes.<p>
4470 	 * 
4471 	 * The iterator instance returned has two methods, hasNext() which
4472 	 * returns true if the iterator has more characters to iterate through,
4473 	 * and next() which returns the next character.<p>
4474 	 * 
4475 	 * @return {Object} an iterator 
4476 	 * that iterates through all the characters in the string
4477 	 */
4478 	charIterator: function() {
4479 		/**
4480 		 * @constructor
4481 		 */
4482 		function _chiterator (istring) {
4483 			this.index = 0;
4484 			this.hasNext = function () {
4485 				return (this.index < istring.str.length);
4486 			};
4487 			this.next = function () {
4488 				var ch;
4489 				if (this.index < istring.str.length) {
4490 					ch = istring.str.charAt(this.index);
4491 					if (IString._isSurrogate(ch) && 
4492 							this.index+1 < istring.str.length && 
4493 							IString._isSurrogate(istring.str.charAt(this.index+1))) {
4494 						this.index++;
4495 						ch += istring.str.charAt(this.index);
4496 					}
4497 					this.index++;
4498 				}
4499 				return ch;
4500 			};
4501 		};
4502 		return new _chiterator(this);
4503 	},
4504 	
4505 	/**
4506 	 * Return the code point at the given index when the string is viewed 
4507 	 * as an array of code points. If the index is beyond the end of the
4508 	 * array of code points or if the index is negative, -1 is returned.
4509 	 * @param {number} index index of the code point 
4510 	 * @return {number} code point of the character at the given index into
4511 	 * the string
4512 	 */
4513 	codePointAt: function (index) {
4514 		if (index < 0) {
4515 			return -1;
4516 		}
4517 		var count,
4518 			it = this.iterator(),
4519 			ch;
4520 		for (count = index; count >= 0 && it.hasNext(); count--) {
4521 			ch = it.next();
4522 		}
4523 		return (count < 0) ? ch : -1;
4524 	},
4525 	
4526 	/**
4527 	 * Set the locale to use when processing choice formats. The locale
4528 	 * affects how number classes are interpretted. In some cultures,
4529 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4530 	 * in yet others, "few" maps to "any integer that ends in the digits
4531 	 * 3 or 4".
4532 	 * @param {Locale|string} locale locale to use when processing choice
4533 	 * formats with this string
4534 	 * @param {boolean=} sync [optional] whether to load the locale data synchronously 
4535 	 * or not
4536 	 * @param {Object=} loadParams [optional] parameters to pass to the loader function
4537 	 * @param {function(*)=} onLoad [optional] function to call when the loading is done
4538 	 */
4539 	setLocale: function (locale, sync, loadParams, onLoad) {
4540 		if (typeof(locale) === 'object') {
4541 			this.locale = locale;
4542 		} else {
4543 			this.localeSpec = locale;
4544 			this.locale = new Locale(locale);
4545 		}
4546 		
4547 		IString.loadPlurals(typeof(sync) !== 'undefined' ? sync : true, this.locale, loadParams, onLoad);
4548 	},
4549 
4550 	/**
4551 	 * Return the locale to use when processing choice formats. The locale
4552 	 * affects how number classes are interpretted. In some cultures,
4553 	 * the limit "few" maps to "any integer that ends in the digits 2 to 9" and
4554 	 * in yet others, "few" maps to "any integer that ends in the digits
4555 	 * 3 or 4".
4556 	 * @return {string} localespec to use when processing choice
4557 	 * formats with this string
4558 	 */
4559 	getLocale: function () {
4560 		return (this.locale ? this.locale.getSpec() : this.localeSpec) || ilib.getLocale();
4561 	},
4562 
4563 	/**
4564 	 * Return the number of code points in this string. This may be different
4565 	 * than the number of characters, as the UTF-16 encoding that Javascript
4566 	 * uses for its basis returns surrogate pairs separately. Two 2-byte 
4567 	 * surrogate characters together make up one character/code point in 
4568 	 * the supplementary character planes. If your string contains no
4569 	 * characters in the supplementary planes, this method will return the
4570 	 * same thing as the length() method.
4571 	 * @return {number} the number of code points in this string
4572 	 */
4573 	codePointLength: function () {
4574 		if (this.cpLength === -1) {
4575 			var it = this.iterator();
4576 			this.cpLength = 0;
4577 			while (it.hasNext()) { 
4578 				this.cpLength++;
4579 				it.next();
4580 			};
4581 		}
4582 		return this.cpLength;	
4583 	}
4584 };
4585 
4586 
4587 /*< Calendar.js */
4588 /*
4589  * Calendar.js - Represent a calendar object.
4590  * 
4591  * Copyright © 2012-2015, JEDLSoft
4592  *
4593  * Licensed under the Apache License, Version 2.0 (the "License");
4594  * you may not use this file except in compliance with the License.
4595  * You may obtain a copy of the License at
4596  *
4597  *     http://www.apache.org/licenses/LICENSE-2.0
4598  *
4599  * Unless required by applicable law or agreed to in writing, software
4600  * distributed under the License is distributed on an "AS IS" BASIS,
4601  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4602  *
4603  * See the License for the specific language governing permissions and
4604  * limitations under the License.
4605  */
4606 
4607 /**
4608  * @class
4609  * Superclass for all calendar subclasses that contains shared 
4610  * functionality. This class is never instantiated on its own. Instead,
4611  * you should use the {@link CalendarFactory} function to manufacture a new
4612  * instance of a subclass of Calendar. 
4613  * 
4614  * @private
4615  * @constructor
4616  */
4617 var Calendar = function() {
4618 };
4619 
4620 /* place for the subclasses to put their constructors so that the factory method
4621  * can find them. Do this to add your calendar after it's defined: 
4622  * Calendar._constructors["mytype"] = Calendar.MyTypeConstructor;
4623  */
4624 Calendar._constructors = {};
4625 
4626 Calendar.prototype = {
4627 	/**
4628 	 * Return the type of this calendar.
4629 	 * 
4630 	 * @return {string} the name of the type of this calendar 
4631 	 */
4632 	getType: function() {
4633 		throw "Cannot call methods of abstract class Calendar";
4634 	},
4635 	
4636 	/**
4637 	 * Return the number of months in the given year. The number of months in a year varies
4638 	 * for some luni-solar calendars because in some years, an extra month is needed to extend the 
4639 	 * days in a year to an entire solar year. The month is represented as a 1-based number
4640 	 * where 1=first month, 2=second month, etc.
4641 	 * 
4642 	 * @param {number} year a year for which the number of months is sought
4643 	 * @return {number} The number of months in the given year
4644 	 */
4645 	getNumMonths: function(year) {
4646 		throw "Cannot call methods of abstract class Calendar";
4647 	},
4648 	
4649 	/**
4650 	 * Return the number of days in a particular month in a particular year. This function
4651 	 * can return a different number for a month depending on the year because of things
4652 	 * like leap years.
4653 	 * 
4654 	 * @param {number} month the month for which the length is sought
4655 	 * @param {number} year the year within which that month can be found
4656 	 * @return {number} the number of days within the given month in the given year
4657 	 */
4658 	getMonLength: function(month, year) {
4659 		throw "Cannot call methods of abstract class Calendar";
4660 	},
4661 	
4662 	/**
4663 	 * Return true if the given year is a leap year in this calendar.
4664 	 * The year parameter may be given as a number.
4665 	 * 
4666 	 * @param {number} year the year for which the leap year information is being sought
4667 	 * @return {boolean} true if the given year is a leap year
4668 	 */
4669 	isLeapYear: function(year) {
4670 		throw "Cannot call methods of abstract class Calendar";
4671 	}
4672 };
4673 
4674 
4675 /*< CalendarFactory.js */
4676 /*
4677  * CalendarFactory.js - Constructs new instances of the right subclass of Calendar
4678  * 
4679  * Copyright © 2015, JEDLSoft
4680  *
4681  * Licensed under the Apache License, Version 2.0 (the "License");
4682  * you may not use this file except in compliance with the License.
4683  * You may obtain a copy of the License at
4684  *
4685  *     http://www.apache.org/licenses/LICENSE-2.0
4686  *
4687  * Unless required by applicable law or agreed to in writing, software
4688  * distributed under the License is distributed on an "AS IS" BASIS,
4689  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4690  *
4691  * See the License for the specific language governing permissions and
4692  * limitations under the License.
4693  */
4694 
4695 /* !depends
4696 ilib.js
4697 Locale.js
4698 LocaleInfo.js
4699 Calendar.js
4700 */
4701 
4702 
4703 /**
4704  * Factory method to create a new instance of a calendar subclass.<p>
4705  * 
4706  * The options parameter can be an object that contains the following
4707  * properties:
4708  * 
4709  * <ul>
4710  * <li><i>type</i> - specify the type of the calendar desired. The
4711  * list of valid values changes depending on which calendars are 
4712  * defined. When assembling your iliball.js, include those calendars 
4713  * you wish to use in your program or web page, and they will register 
4714  * themselves with this factory method. The "official", "gregorian",
4715  * and "julian" calendars are all included by default, as they are the
4716  * standard calendars for much of the world.
4717  * <li><i>locale</i> - some calendars vary depending on the locale.
4718  * For example, the "official" calendar transitions from a Julian-style
4719  * calendar to a Gregorian-style calendar on a different date for
4720  * each country, as the governments of those countries decided to
4721  * adopt the Gregorian calendar at different times.
4722  *  
4723  * <li><i>onLoad</i> - a callback function to call when the calendar object is fully 
4724  * loaded. When the onLoad option is given, the calendar factory will attempt to
4725  * load any missing locale data using the ilib loader callback.
4726  * When the constructor is done (even if the data is already preassembled), the 
4727  * onLoad function is called with the current instance as a parameter, so this
4728  * callback can be used with preassembled or dynamic loading or a mix of the two.
4729  * 
4730  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
4731  * asynchronously. If this option is given as "false", then the "onLoad"
4732  * callback must be given, as the instance returned from this constructor will
4733  * not be usable for a while.
4734  *  
4735  * <li><i>loadParams</i> - an object containing parameters to pass to the 
4736  * loader callback function when locale data is missing. The parameters are not
4737  * interpretted or modified in any way. They are simply passed along. The object 
4738  * may contain any property/value pairs as long as the calling code is in
4739  * agreement with the loader callback function as to what those parameters mean.
4740  * </ul>
4741  * 
4742  * If a locale is specified, but no type, then the calendar that is default for
4743  * the locale will be instantiated and returned. If neither the type nor
4744  * the locale are specified, then the calendar for the default locale will
4745  * be used. 
4746  * 
4747  * @static
4748  * @param {Object=} options options controlling the construction of this instance, or
4749  * undefined to use the default options
4750  * @return {Calendar} an instance of a calendar object of the appropriate type
4751  */
4752 var CalendarFactory = function (options) {
4753 	var locale,
4754 		type,
4755 		sync = true,
4756 		instance;
4757 
4758 	if (options) {
4759 		if (options.locale) {
4760 			locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
4761 		}
4762 		
4763 		type = options.type || options.calendar;
4764 		
4765 		if (typeof(options.sync) === 'boolean') {
4766 			sync = options.sync;
4767 		}
4768 	}
4769 	
4770 	if (!locale) {
4771 		locale = new Locale();	// default locale
4772 	}
4773 	
4774 	if (!type) {
4775 		new LocaleInfo(locale, {
4776 			sync: sync,
4777 			loadParams: options && options.loadParams,
4778 			onLoad: ilib.bind(this, function(info) {
4779 				type = info.getCalendar();
4780 				
4781 				instance = CalendarFactory._init(type, options);
4782 				
4783 				if (options && typeof(options.onLoad) === 'function') {
4784 					options.onLoad(instance);
4785 				}
4786 			})
4787 		});
4788 	} else {
4789 		instance = CalendarFactory._init(type, options);
4790 	}
4791 	
4792 	return instance;
4793 };
4794 
4795 /**
4796  * Map calendar names to classes to initialize in the dynamic code model.
4797  * TODO: Need to figure out some way that this doesn't have to be updated by hand.
4798  * @private
4799  */
4800 CalendarFactory._dynMap = {
4801 	"coptic":       "Coptic",
4802 	"ethiopic":     "Ethiopic",
4803 	"gregorian":    "Gregorian",
4804 	"han":          "Han",
4805 	"hebrew":       "Hebrew",
4806 	"islamic":      "Islamic",
4807 	"julian":       "Julian",
4808 	"persian":      "Persian",
4809 	"persian-algo": "PersianAlgo",
4810 	"thaisolar":    "ThaiSolar"
4811 };
4812 
4813 /**
4814  * Dynamically load the code for a calendar and calendar class if necessary.
4815  * @protected
4816  */
4817 CalendarFactory._dynLoadCalendar = function (name) {
4818 	if (!Calendar._constructors[name]) {
4819 		var entry = CalendarFactory._dynMap[name];
4820 		if (entry) {
4821 			Calendar._constructors[name] = require("./" + entry + "Cal.js");
4822 		}
4823 	}
4824 	return Calendar._constructors[name];
4825 };
4826 
4827 /** @private */
4828 CalendarFactory._init = function(type, options) {
4829 	var cons;
4830 	
4831 	if (ilib.isDynCode()) {
4832 		CalendarFactory._dynLoadCalendar(type);
4833 	}
4834 	
4835 	cons = Calendar._constructors[type];
4836 	
4837 	// pass the same options through to the constructor so the subclass
4838 	// has the ability to do something with if it needs to
4839 	return cons && new cons(options);
4840 };
4841 
4842 /**
4843  * Return an array of known calendar types that the factory method can instantiate.
4844  * 
4845  * @return {Array.<string>} an array of calendar types
4846  */
4847 CalendarFactory.getCalendars = function () {
4848 	var arr = [],
4849 		c;
4850 	
4851 	if (ilib.isDynCode()) {
4852 		for (c in CalendarFactory._dynMap) {
4853 			CalendarFactory._dynLoadCalendar(c);
4854 		}
4855 	}
4856 	
4857 	for (c in Calendar._constructors) {
4858 		if (c && Calendar._constructors[c]) {
4859 			arr.push(c); // code like a pirate
4860 		}
4861 	}
4862 	
4863 	return arr;
4864 };
4865 
4866 
4867 /*< GregorianCal.js */
4868 /*
4869  * gregorian.js - Represent a Gregorian calendar object.
4870  * 
4871  * Copyright © 2012-2015, JEDLSoft
4872  *
4873  * Licensed under the Apache License, Version 2.0 (the "License");
4874  * you may not use this file except in compliance with the License.
4875  * You may obtain a copy of the License at
4876  *
4877  *     http://www.apache.org/licenses/LICENSE-2.0
4878  *
4879  * Unless required by applicable law or agreed to in writing, software
4880  * distributed under the License is distributed on an "AS IS" BASIS,
4881  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4882  *
4883  * See the License for the specific language governing permissions and
4884  * limitations under the License.
4885  */
4886 
4887 
4888 /* !depends ilib.js Calendar.js Utils.js MathUtils.js */
4889 
4890 
4891 /**
4892  * @class
4893  * Construct a new Gregorian calendar object. This class encodes information about
4894  * a Gregorian calendar.<p>
4895  * 
4896  * 
4897  * @constructor
4898  * @param {{noinstance:boolean}=} options
4899  * @extends Calendar
4900  */
4901 var GregorianCal = function(options) {
4902 	if (!options || !options.noinstance) {
4903 		this.type = "gregorian";
4904 	}
4905 };
4906 
4907 /**
4908  * the lengths of each month 
4909  * @private
4910  * @const
4911  * @type Array.<number> 
4912  */
4913 GregorianCal.monthLengths = [
4914 	31,  /* Jan */
4915 	28,  /* Feb */
4916 	31,  /* Mar */
4917 	30,  /* Apr */
4918 	31,  /* May */
4919 	30,  /* Jun */
4920 	31,  /* Jul */
4921 	31,  /* Aug */
4922 	30,  /* Sep */
4923 	31,  /* Oct */
4924 	30,  /* Nov */
4925 	31   /* Dec */
4926 ];
4927 
4928 /**
4929  * Return the number of months in the given year. The number of months in a year varies
4930  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
4931  * days in a year to an entire solar year. The month is represented as a 1-based number
4932  * where 1=first month, 2=second month, etc.
4933  * 
4934  * @param {number} year a year for which the number of months is sought
4935  * @return {number} The number of months in the given year
4936  */
4937 GregorianCal.prototype.getNumMonths = function(year) {
4938 	return 12;
4939 };
4940 
4941 /**
4942  * Return the number of days in a particular month in a particular year. This function
4943  * can return a different number for a month depending on the year because of things
4944  * like leap years.
4945  * 
4946  * @param {number} month the month for which the length is sought
4947  * @param {number} year the year within which that month can be found
4948  * @return {number} the number of days within the given month in the given year
4949  */
4950 GregorianCal.prototype.getMonLength = function(month, year) {
4951 	if (month !== 2 || !this.isLeapYear(year)) {
4952 		return GregorianCal.monthLengths[month-1];
4953 	} else {
4954 		return 29;
4955 	}
4956 };
4957 
4958 /**
4959  * Return true if the given year is a leap year in the Gregorian calendar.
4960  * The year parameter may be given as a number, or as a GregDate object.
4961  * @param {number|GregorianDate} year the year for which the leap year information is being sought
4962  * @return {boolean} true if the given year is a leap year
4963  */
4964 GregorianCal.prototype.isLeapYear = function(year) {
4965 	var y = (typeof(year) === 'number' ? year : year.getYears());
4966 	var centuries = MathUtils.mod(y, 400);
4967 	return (MathUtils.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
4968 };
4969 
4970 /**
4971  * Return the type of this calendar.
4972  * 
4973  * @return {string} the name of the type of this calendar 
4974  */
4975 GregorianCal.prototype.getType = function() {
4976 	return this.type;
4977 };
4978 
4979 /**
4980  * Return a date instance for this calendar type using the given
4981  * options.
4982  * @param {Object} options options controlling the construction of 
4983  * the date instance
4984  * @return {IDate} a date appropriate for this calendar type
4985  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
4986  */
4987 GregorianCal.prototype.newDateInstance = function (options) {
4988 		return new GregorianDate(options);
4989 };
4990 
4991 /* register this calendar for the factory method */
4992 Calendar._constructors["gregorian"] = GregorianCal;
4993 
4994 
4995 /*< JulianDay.js */
4996 /*
4997  * JulianDay.js - A Julian Day object.
4998  * 
4999  * Copyright © 2012-2015, JEDLSoft
5000  *
5001  * Licensed under the Apache License, Version 2.0 (the "License");
5002  * you may not use this file except in compliance with the License.
5003  * You may obtain a copy of the License at
5004  *
5005  *     http://www.apache.org/licenses/LICENSE-2.0
5006  *
5007  * Unless required by applicable law or agreed to in writing, software
5008  * distributed under the License is distributed on an "AS IS" BASIS,
5009  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5010  *
5011  * See the License for the specific language governing permissions and
5012  * limitations under the License.
5013  */
5014 
5015 /**
5016  * @class
5017  * A Julian Day class. A Julian Day is a date based on the Julian Day count
5018  * of time invented by Joseph Scaliger in 1583 for use with astronomical calculations. 
5019  * Do not confuse it with a date in the Julian calendar, which it has very
5020  * little in common with. The naming is unfortunately close, and comes from history.<p>
5021  * 
5022  * 
5023  * @constructor
5024  * @param {number} num the Julian Day expressed as a floating point number 
5025  */
5026 var JulianDay = function(num) {
5027 	this.jd = num;
5028 	this.days = Math.floor(this.jd);
5029 	this.frac = num - this.days;
5030 };
5031 
5032 JulianDay.prototype = {
5033 	/**
5034 	 * Return the integral portion of this Julian Day instance. This corresponds to
5035 	 * the number of days since the beginning of the epoch.
5036 	 * 
5037 	 * @return {number} the integral portion of this Julian Day
5038 	 */
5039 	getDays: function() {
5040 		return this.days;
5041 	},
5042 	
5043 	/**
5044 	 * Set the date of this Julian Day instance.
5045 	 * 
5046 	 * @param {number} days the julian date expressed as a floating point number
5047 	 */
5048 	setDays: function(days) {
5049 		this.days = Math.floor(days);
5050 		this.jd = this.days + this.frac;
5051 	},
5052 	
5053 	/**
5054 	 * Return the fractional portion of this Julian Day instance. This portion 
5055 	 * corresponds to the time of day for the instance.
5056 	 */
5057 	getDayFraction: function() {
5058 		return this.frac;
5059 	},
5060 	
5061 	/**
5062 	 * Set the fractional part of the Julian Day. The fractional part represents
5063 	 * the portion of a fully day. Julian dates start at noon, and proceed until
5064 	 * noon of the next day. That would mean midnight is represented as a fractional
5065 	 * part of 0.5.
5066 	 * 
5067 	 * @param {number} fraction The fractional part of the Julian date
5068 	 */
5069 	setDayFraction: function(fraction) {
5070 		var t = Math.floor(fraction);
5071 		this.frac = fraction - t;
5072 		this.jd = this.days + this.frac;
5073 	},
5074 	
5075 	/** 
5076 	 * Return the Julian Day expressed as a floating point number.
5077 	 * @return {number} the Julian Day as a number
5078 	 */
5079 	getDate: function () {
5080 		return this.jd;
5081 	},
5082 	
5083 	/**
5084 	 * Set the date of this Julian Day instance.
5085 	 * 
5086 	 * @param {number} num the numeric Julian Day to set into this instance
5087 	 */
5088 	setDate: function (num) {
5089 		this.jd = num;
5090 	},
5091 	
5092 	/**
5093 	 * Add an offset to the current date instance. The offset should be expressed in
5094 	 * terms of Julian days. That is, each integral unit represents one day of time, and
5095 	 * fractional part represents a fraction of a regular 24-hour day.
5096 	 * 
5097 	 * @param {number} offset an amount to add (or subtract) to the current result instance.
5098 	 */
5099 	addDate: function(offset) {
5100 		if (typeof(offset) === 'number') {
5101 			this.jd += offset;
5102 			this.days = Math.floor(this.jd);
5103 			this.frac = this.jd - this.days;
5104 		}
5105 	}
5106 };
5107 
5108 
5109 
5110 /*< RataDie.js */
5111 /*
5112  * ratadie.js - Represent the RD date number in the calendar
5113  * 
5114  * Copyright © 2014-2015, JEDLSoft
5115  *
5116  * Licensed under the Apache License, Version 2.0 (the "License");
5117  * you may not use this file except in compliance with the License.
5118  * You may obtain a copy of the License at
5119  *
5120  *     http://www.apache.org/licenses/LICENSE-2.0
5121  *
5122  * Unless required by applicable law or agreed to in writing, software
5123  * distributed under the License is distributed on an "AS IS" BASIS,
5124  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5125  *
5126  * See the License for the specific language governing permissions and
5127  * limitations under the License.
5128  */
5129 
5130 /* !depends 
5131 ilib.js
5132 JulianDay.js
5133 MathUtils.js
5134 JSUtils.js
5135 */
5136 
5137 
5138 /**
5139  * @class
5140  * Construct a new RD date number object. The constructor parameters can 
5141  * contain any of the following properties:
5142  * 
5143  * <ul>
5144  * <li><i>unixtime<i> - sets the time of this instance according to the given 
5145  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
5146  * 
5147  * <li><i>julianday</i> - sets the time of this instance according to the given
5148  * Julian Day instance or the Julian Day given as a float
5149  * 
5150  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
5151  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
5152  * linear count of years since the beginning of the epoch, much like other calendars. This linear
5153  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
5154  * to 60 and treated as if it were a year in the regular 60-year cycle.
5155  * 
5156  * <li><i>year</i> - any integer, including 0
5157  * 
5158  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
5159  * 
5160  * <li><i>day</i> - 1 to 31
5161  * 
5162  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
5163  * is always done with an unambiguous 24 hour representation
5164  * 
5165  * <li><i>minute</i> - 0 to 59
5166  * 
5167  * <li><i>second</i> - 0 to 59
5168  * 
5169  * <li><i>millisecond</i> - 0 to 999
5170  * 
5171  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
5172  * the parts or specify the minutes, seconds, and milliseconds, but not both. This is only used
5173  * in the Hebrew calendar. 
5174  * 
5175  * <li><i>minute</i> - 0 to 59
5176  * 
5177  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
5178  * </ul>
5179  *
5180  * If the constructor is called with another date instance instead of
5181  * a parameter block, the other instance acts as a parameter block and its
5182  * settings are copied into the current instance.<p>
5183  * 
5184  * If the constructor is called with no arguments at all or if none of the 
5185  * properties listed above are present, then the RD is calculate based on 
5186  * the current date at the time of instantiation. <p>
5187  * 
5188  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
5189  * specified in the params, it is assumed that they have the smallest possible
5190  * value in the range for the property (zero or one).<p>
5191  * 
5192  * 
5193  * @private
5194  * @constructor
5195  * @param {Object=} params parameters that govern the settings and behaviour of this RD date
5196  */
5197 var RataDie = function(params) {
5198 	if (params) {
5199 		if (typeof(params.date) !== 'undefined') {
5200 			// accept JS Date classes or strings
5201 			var date = params.date;
5202 			if (!(JSUtils.isDate(date))) {
5203 				date = new Date(date); // maybe a string initializer?
5204 			}
5205 			this._setTime(date.getTime());
5206 		} else if (typeof(params.unixtime) !== 'undefined') {
5207 			this._setTime(parseInt(params.unixtime, 10));
5208 		} else if (typeof(params.julianday) !== 'undefined') {
5209 			// JD time is defined to be UTC
5210 			this._setJulianDay(parseFloat(params.julianday));
5211 		} else if (params.year || params.month || params.day || params.hour ||
5212 				params.minute || params.second || params.millisecond || params.parts || params.cycle) {
5213 			this._setDateComponents(params);
5214 		} else if (typeof(params.rd) !== 'undefined') {
5215 			this.rd = (typeof(params.rd) === 'object' && params.rd instanceof RataDie) ? params.rd.rd : params.rd;
5216 		}
5217 	}
5218 	
5219 	/**
5220 	 * @type {number} the Rata Die number of this date for this calendar type
5221 	 */
5222 	if (typeof(this.rd) === 'undefined') {
5223 		var now = new Date();
5224 		this._setTime(now.getTime());
5225 	}
5226 };
5227 
5228 /**
5229  * @private
5230  * @const
5231  * @type {number}
5232  */
5233 RataDie.gregorianEpoch = 1721424.5;
5234 
5235 RataDie.prototype = {
5236 	/**
5237 	 * @protected
5238 	 * @const
5239 	 * @type {number}
5240 	 * the difference between a zero Julian day and the zero Gregorian date. 
5241 	 */
5242 	epoch: RataDie.gregorianEpoch,
5243 	
5244 	/**
5245 	 * Set the RD of this instance according to the given unix time. Unix time is
5246 	 * the number of milliseconds since midnight on Jan 1, 1970.
5247 	 *
5248 	 * @protected
5249 	 * @param {number} millis the unix time to set this date to in milliseconds 
5250 	 */
5251 	_setTime: function(millis) {
5252 		// 2440587.5 is the julian day of midnight Jan 1, 1970, UTC (Gregorian)
5253 		this._setJulianDay(2440587.5 + millis / 86400000);
5254 	},
5255 
5256 	/**
5257 	 * Set the date of this instance using a Julian Day.
5258 	 * @protected
5259 	 * @param {number} date the Julian Day to use to set this date
5260 	 */
5261 	_setJulianDay: function (date) {
5262 		var jd = (typeof(date) === 'number') ? new JulianDay(date) : date;
5263 		// round to the nearest millisecond
5264 		this.rd = MathUtils.halfup((jd.getDate() - this.epoch) * 86400000) / 86400000;
5265 	},
5266 
5267 	/**
5268 	 * Return the rd number of the particular day of the week on or before the 
5269 	 * given rd. eg. The Sunday on or before the given rd.
5270 	 * @protected
5271 	 * @param {number} rd the rata die date of the reference date
5272 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5273 	 * to the current date
5274 	 * @return {number} the rd of the day of the week
5275 	 */
5276 	_onOrBefore: function(rd, dayOfWeek) {
5277 		return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 2, 7);
5278 	},
5279 	
5280 	/**
5281 	 * Return the rd number of the particular day of the week on or before the current rd.
5282 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
5283 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5284 	 * wall time, so it it would give the wrong day of the week if this calculation was
5285 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5286 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5287 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5288 	 * to the current date
5289 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5290 	 * not given
5291 	 * @return {number} the rd of the day of the week
5292 	 */
5293 	onOrBefore: function(dayOfWeek, offset) {
5294 		offset = offset || 0;
5295 		return this._onOrBefore(this.rd + offset, dayOfWeek) - offset;
5296 	},
5297 	
5298 	/**
5299 	 * Return the rd number of the particular day of the week on or before the current rd.
5300 	 * eg. The Sunday on or before the current rd. If the offset is given, the calculation
5301 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5302 	 * wall time, so it it would give the wrong day of the week if this calculation was
5303 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5304 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5305 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5306 	 * to the reference date
5307 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5308 	 * not given
5309 	 * @return {number} the day of the week
5310 	 */
5311 	onOrAfter: function(dayOfWeek, offset) {
5312 		offset = offset || 0;
5313 		return this._onOrBefore(this.rd+6+offset, dayOfWeek) - offset;
5314 	},
5315 	
5316 	/**
5317 	 * Return the rd number of the particular day of the week before the current rd.
5318 	 * eg. The Sunday before the current rd. If the offset is given, the calculation
5319 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5320 	 * wall time, so it it would give the wrong day of the week if this calculation was
5321 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5322 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5323 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5324 	 * to the reference date
5325 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5326 	 * not given
5327 	 * @return {number} the day of the week
5328 	 */
5329 	before: function(dayOfWeek, offset) {
5330 		offset = offset || 0;
5331 		return this._onOrBefore(this.rd-1+offset, dayOfWeek) - offset;
5332 	},
5333 	
5334 	/**
5335 	 * Return the rd number of the particular day of the week after the current rd.
5336 	 * eg. The Sunday after the current rd. If the offset is given, the calculation
5337 	 * happens in wall time instead of UTC. UTC time may be a day before or day behind 
5338 	 * wall time, so it it would give the wrong day of the week if this calculation was
5339 	 * done in UTC time when the caller really wanted wall time. Even though the calculation
5340 	 * may be done in wall time, the return value is nonetheless always given in UTC.
5341 	 * @param {number} dayOfWeek the day of the week that is being sought relative 
5342 	 * to the reference date
5343 	 * @param {number=} offset RD offset for the time zone. Zero is assumed if this param is
5344 	 * not given
5345 	 * @return {number} the day of the week
5346 	 */
5347 	after: function(dayOfWeek, offset) {
5348 		offset = offset || 0;
5349 		return this._onOrBefore(this.rd+7+offset, dayOfWeek) - offset;
5350 	},
5351 
5352 	/**
5353 	 * Return the unix time equivalent to this Gregorian date instance. Unix time is
5354 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. This method only
5355 	 * returns a valid number for dates between midnight, Jan 1, 1970 and  
5356 	 * Jan 19, 2038 at 3:14:07am when the unix time runs out. If this instance 
5357 	 * encodes a date outside of that range, this method will return -1.
5358 	 * 
5359 	 * @return {number} a number giving the unix time, or -1 if the date is outside the
5360 	 * valid unix time range
5361 	 */
5362 	getTime: function() {
5363 		// earlier than Jan 1, 1970
5364 		// or later than Jan 19, 2038 at 3:14:07am
5365 		var jd = this.getJulianDay();
5366 		if (jd < 2440587.5 || jd > 2465442.634803241) { 
5367 			return -1;
5368 		}
5369 	
5370 		// avoid the rounding errors in the floating point math by only using
5371 		// the whole days from the rd, and then calculating the milliseconds directly
5372 		return Math.round((jd - 2440587.5) * 86400000);
5373 	},
5374 
5375 	/**
5376 	 * Return the extended unix time equivalent to this Gregorian date instance. Unix time is
5377 	 * the number of milliseconds since midnight on Jan 1, 1970 UTC. Traditionally unix time
5378 	 * (or the type "time_t" in C/C++) is only encoded with a unsigned 32 bit integer, and thus 
5379 	 * runs out on Jan 19, 2038. However, most Javascript engines encode numbers well above 
5380 	 * 32 bits and the Date object allows you to encode up to 100 million days worth of time 
5381 	 * after Jan 1, 1970, and even more interestingly 100 million days worth of time before
5382 	 * Jan 1, 1970 as well. This method returns the number of milliseconds in that extended 
5383 	 * range. If this instance encodes a date outside of that range, this method will return
5384 	 * NaN.
5385 	 * 
5386 	 * @return {number} a number giving the extended unix time, or NaN if the date is outside 
5387 	 * the valid extended unix time range
5388 	 */
5389 	getTimeExtended: function() {
5390 		var jd = this.getJulianDay();
5391 		
5392 		// test if earlier than Jan 1, 1970 - 100 million days
5393 		// or later than Jan 1, 1970 + 100 million days
5394 		if (jd < -97559412.5 || jd > 102440587.5) { 
5395 			return NaN;
5396 		}
5397 	
5398 		// avoid the rounding errors in the floating point math by only using
5399 		// the whole days from the rd, and then calculating the milliseconds directly
5400 		return Math.round((jd - 2440587.5) * 86400000);
5401 	},
5402 
5403 	/**
5404 	 * Return the Julian Day equivalent to this calendar date as a number.
5405 	 * This returns the julian day in UTC.
5406 	 * 
5407 	 * @return {number} the julian date equivalent of this date
5408 	 */
5409 	getJulianDay: function() {
5410 		return this.rd + this.epoch;
5411 	},
5412 
5413 	/**
5414 	 * Return the Rata Die (fixed day) number of this RD date.
5415 	 * 
5416 	 * @return {number} the rd date as a number
5417 	 */
5418 	getRataDie: function() {
5419 		return this.rd;
5420 	}
5421 };
5422 
5423 
5424 /*< GregRataDie.js */
5425 /*
5426  * gregratadie.js - Represent the RD date number in the Gregorian calendar
5427  * 
5428  * Copyright © 2014-2015, JEDLSoft
5429  *
5430  * Licensed under the Apache License, Version 2.0 (the "License");
5431  * you may not use this file except in compliance with the License.
5432  * You may obtain a copy of the License at
5433  *
5434  *     http://www.apache.org/licenses/LICENSE-2.0
5435  *
5436  * Unless required by applicable law or agreed to in writing, software
5437  * distributed under the License is distributed on an "AS IS" BASIS,
5438  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5439  *
5440  * See the License for the specific language governing permissions and
5441  * limitations under the License.
5442  */
5443 
5444 /* !depends 
5445 ilib.js
5446 GregorianCal.js
5447 RataDie.js
5448 MathUtils.js
5449 */
5450 
5451 
5452 /**
5453  * @class
5454  * Construct a new Gregorian RD date number object. The constructor parameters can 
5455  * contain any of the following properties:
5456  * 
5457  * <ul>
5458  * <li><i>unixtime<i> - sets the time of this instance according to the given 
5459  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
5460  * 
5461  * <li><i>julianday</i> - sets the time of this instance according to the given
5462  * Julian Day instance or the Julian Day given as a float
5463  * 
5464  * <li><i>year</i> - any integer, including 0
5465  * 
5466  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
5467  * 
5468  * <li><i>day</i> - 1 to 31
5469  * 
5470  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
5471  * is always done with an unambiguous 24 hour representation
5472  * 
5473  * <li><i>minute</i> - 0 to 59
5474  * 
5475  * <li><i>second</i> - 0 to 59
5476  * 
5477  * <li><i>millisecond</i> - 0 to 999
5478  * 
5479  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
5480  * </ul>
5481  *
5482  * If the constructor is called with another Gregorian date instance instead of
5483  * a parameter block, the other instance acts as a parameter block and its
5484  * settings are copied into the current instance.<p>
5485  * 
5486  * If the constructor is called with no arguments at all or if none of the 
5487  * properties listed above are present, then the RD is calculate based on 
5488  * the current date at the time of instantiation. <p>
5489  * 
5490  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
5491  * specified in the params, it is assumed that they have the smallest possible
5492  * value in the range for the property (zero or one).<p>
5493  * 
5494  * 
5495  * @private
5496  * @constructor
5497  * @extends RataDie
5498  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian RD date
5499  */
5500 var GregRataDie = function(params) {
5501 	this.cal = params && params.cal || new GregorianCal();
5502 	/** @type {number|undefined} */
5503 	this.rd = undefined;
5504 	RataDie.call(this, params);
5505 };
5506 
5507 GregRataDie.prototype = new RataDie();
5508 GregRataDie.prototype.parent = RataDie;
5509 GregRataDie.prototype.constructor = GregRataDie;
5510 
5511 /**
5512  * the cumulative lengths of each month, for a non-leap year 
5513  * @private
5514  * @const
5515  * @type Array.<number>
5516  */
5517 GregRataDie.cumMonthLengths = [
5518     0,   /* Jan */
5519 	31,  /* Feb */
5520 	59,  /* Mar */
5521 	90,  /* Apr */
5522 	120, /* May */
5523 	151, /* Jun */
5524 	181, /* Jul */
5525 	212, /* Aug */
5526 	243, /* Sep */
5527 	273, /* Oct */
5528 	304, /* Nov */
5529 	334, /* Dec */
5530 	365
5531 ];
5532 
5533 /**
5534  * the cumulative lengths of each month, for a leap year 
5535  * @private
5536  * @const
5537  * @type Array.<number>
5538  */
5539 GregRataDie.cumMonthLengthsLeap = [
5540 	0,   /* Jan */
5541 	31,  /* Feb */
5542 	60,  /* Mar */
5543 	91,  /* Apr */
5544 	121, /* May */
5545 	152, /* Jun */
5546 	182, /* Jul */
5547 	213, /* Aug */
5548 	244, /* Sep */
5549 	274, /* Oct */
5550 	305, /* Nov */
5551 	335, /* Dec */
5552 	366
5553 ];
5554 
5555 /**
5556  * Calculate the Rata Die (fixed day) number of the given date.
5557  * 
5558  * @private
5559  * @param {Object} date the date components to calculate the RD from
5560  */
5561 GregRataDie.prototype._setDateComponents = function(date) {
5562 	var year = parseInt(date.year, 10) || 0;
5563 	var month = parseInt(date.month, 10) || 1;
5564 	var day = parseInt(date.day, 10) || 1;
5565 	var hour = parseInt(date.hour, 10) || 0;
5566 	var minute = parseInt(date.minute, 10) || 0;
5567 	var second = parseInt(date.second, 10) || 0;
5568 	var millisecond = parseInt(date.millisecond, 10) || 0;
5569 
5570 	var years = 365 * (year - 1) +
5571 		Math.floor((year-1)/4) -
5572 		Math.floor((year-1)/100) +
5573 		Math.floor((year-1)/400);
5574 	
5575 	var dayInYear = (month > 1 ? GregRataDie.cumMonthLengths[month-1] : 0) +
5576 		day +
5577 		(GregorianCal.prototype.isLeapYear.call(this.cal, year) && month > 2 ? 1 : 0);
5578 	var rdtime = (hour * 3600000 +
5579 		minute * 60000 +
5580 		second * 1000 +
5581 		millisecond) / 
5582 		86400000; 
5583 	/*
5584 	debug("getRataDie: converting " +  JSON.stringify(this));
5585 	debug("getRataDie: year is " +  years);
5586 	debug("getRataDie: day in year is " +  dayInYear);
5587 	debug("getRataDie: rdtime is " +  rdtime);
5588 	debug("getRataDie: rd is " +  (years + dayInYear + rdtime));
5589 	*/
5590 	
5591 	/**
5592 	 * @type {number|undefined} the RD number of this Gregorian date
5593 	 */
5594 	this.rd = years + dayInYear + rdtime;
5595 };
5596 
5597 /**
5598  * Return the rd number of the particular day of the week on or before the 
5599  * given rd. eg. The Sunday on or before the given rd.
5600  * @private
5601  * @param {number} rd the rata die date of the reference date
5602  * @param {number} dayOfWeek the day of the week that is being sought relative 
5603  * to the current date
5604  * @return {number} the rd of the day of the week
5605  */
5606 GregRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
5607 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7);
5608 };
5609 
5610 
5611 /*< TimeZone.js */
5612 /*
5613  * TimeZone.js - Definition of a time zone class
5614  * 
5615  * Copyright © 2012-2015, JEDLSoft
5616  *
5617  * Licensed under the Apache License, Version 2.0 (the "License");
5618  * you may not use this file except in compliance with the License.
5619  * You may obtain a copy of the License at
5620  *
5621  *     http://www.apache.org/licenses/LICENSE-2.0
5622  *
5623  * Unless required by applicable law or agreed to in writing, software
5624  * distributed under the License is distributed on an "AS IS" BASIS,
5625  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5626  *
5627  * See the License for the specific language governing permissions and
5628  * limitations under the License.
5629  */
5630 
5631 /*
5632 !depends 
5633 ilib.js 
5634 Locale.js
5635 LocaleInfo.js
5636 Utils.js
5637 MathUtils.js
5638 JSUtils.js
5639 GregRataDie.js
5640 IString.js
5641 CalendarFactory.js
5642 */
5643 
5644 // !data localeinfo zoneinfo
5645 
5646 
5647 
5648 
5649 /**
5650  * @class
5651  * Create a time zone instance. 
5652  * 
5653  * This class reports and transforms
5654  * information about particular time zones.<p>
5655  * 
5656  * The options parameter may contain any of the following properties:
5657  * 
5658  * <ul>
5659  * <li><i>id</i> - The id of the requested time zone such as "Europe/London" or 
5660  * "America/Los_Angeles". These are taken from the IANA time zone database. (See
5661  * http://www.iana.org/time-zones for more information.) <p>
5662  * 
5663  * There is one special 
5664  * time zone that is not taken from the IANA database called simply "local". In
5665  * this case, this class will attempt to discover the current time zone and
5666  * daylight savings time settings by calling standard Javascript classes to 
5667  * determine the offsets from UTC. 
5668  * 
5669  * <li><i>locale</i> - The locale for this time zone.
5670  * 
5671  * <li><i>offset</i> - Choose the time zone based on the offset from UTC given in
5672  * number of minutes (negative is west, positive is east).
5673  * 
5674  * <li><i>onLoad</i> - a callback function to call when the data is fully 
5675  * loaded. When the onLoad option is given, this class will attempt to
5676  * load any missing locale data using the ilib loader callback.
5677  * When the data is loaded, the onLoad function is called with the current 
5678  * instance as a parameter. 
5679  * 
5680  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
5681  * asynchronously. If this option is given as "false", then the "onLoad"
5682  * callback must be given, as the instance returned from this constructor will
5683  * not be usable for a while.
5684  *  
5685  * <li><i>loadParams</i> - an object containing parameters to pass to the 
5686  * loader callback function when locale data is missing. The parameters are not
5687  * interpretted or modified in any way. They are simply passed along. The object 
5688  * may contain any property/value pairs as long as the calling code is in
5689  * agreement with the loader callback function as to what those parameters mean.
5690  * </ul>
5691  * 
5692  * There is currently no way in the ECMAscript
5693  * standard to tell which exact time zone is currently in use. Choosing the
5694  * id "locale" or specifying an explicit offset will not give a specific time zone, 
5695  * as it is impossible to tell with certainty which zone the offsets 
5696  * match.<p>
5697  * 
5698  * When the id "local" is given or the offset option is specified, this class will
5699  * have the following behaviours:
5700  * <ul>
5701  * <li>The display name will always be given as the RFC822 style, no matter what
5702  * style is requested
5703  * <li>The id will also be returned as the RFC822 style display name
5704  * <li>When the offset is explicitly given, this class will assume the time zone 
5705  * does not support daylight savings time, and the offsets will be calculated 
5706  * the same way year round.
5707  * <li>When the offset is explicitly given, the inDaylightSavings() method will 
5708  * always return false.
5709  * <li>When the id "local" is given, this class will attempt to determine the 
5710  * daylight savings time settings by examining the offset from UTC on Jan 1
5711  * and June 1 of the current year. If they are different, this class assumes
5712  * that the local time zone uses DST. When the offset for a particular date is
5713  * requested, it will use the built-in Javascript support to determine the 
5714  * offset for that date.
5715  * </ul> 
5716  * 
5717  * If a more specific time zone is 
5718  * needed with display names and known start/stop times for DST, use the "id" 
5719  * property instead to specify the time zone exactly. You can perhaps ask the
5720  * user which time zone they prefer so that your app does not need to guess.<p>
5721  * 
5722  * If the id and the offset are both not given, the default time zone for the 
5723  * locale is retrieved from
5724  * the locale info. If the locale is not specified, the default locale for the
5725  * library is used.<p>
5726  * 
5727  * Because this class was designed for use in web sites, and the vast majority
5728  * of dates and times being formatted are recent date/times, this class is simplified
5729  * by not implementing historical time zones. That is, when governments change the 
5730  * time zone rules for a particular zone, only the latest such rule is implemented 
5731  * in this class. That means that determining the offset for a date that is prior 
5732  * to the last change may give the wrong result. Historical time zone calculations
5733  * may be implemented in a later version of iLib if there is enough demand for it,
5734  * but it would entail a much larger set of time zone data that would have to be
5735  * loaded.  
5736  * 
5737  * 
5738  * @constructor
5739  * @param {Object} options Options guiding the construction of this time zone instance
5740  */
5741 var TimeZone = function(options) {
5742 	this.sync = true;
5743 	this.locale = new Locale();
5744 	this.isLocal = false;
5745 	
5746 	if (options) {
5747 		if (options.locale) {
5748 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
5749 		}
5750 		
5751 		if (options.id) {
5752 			var id = options.id.toString();
5753 			if (id === 'local') {
5754 				this.isLocal = true;
5755 				
5756 				// use standard Javascript Date to figure out the time zone offsets
5757 				var now = new Date(), 
5758 					jan1 = new Date(now.getFullYear(), 0, 1),  // months in std JS Date object are 0-based
5759 					jun1 = new Date(now.getFullYear(), 5, 1);
5760 				
5761 				// Javascript's method returns the offset backwards, so we have to
5762 				// take the negative to get the correct offset
5763 				this.offsetJan1 = -jan1.getTimezoneOffset();
5764 				this.offsetJun1 = -jun1.getTimezoneOffset();
5765 				// the offset of the standard time for the time zone is always the one that is closest 
5766 				// to negative infinity of the two, no matter whether you are in the northern or southern 
5767 				// hemisphere, east or west
5768 				this.offset = Math.min(this.offsetJan1, this.offsetJun1);
5769 			}
5770 			this.id = id;
5771 		} else if (options.offset) {
5772 			this.offset = (typeof(options.offset) === 'string') ? parseInt(options.offset, 10) : options.offset;
5773 			this.id = this.getDisplayName(undefined, undefined);
5774 		}
5775 		
5776 		if (typeof(options.sync) !== 'undefined') {
5777 			this.sync = !!options.sync;
5778 		}
5779 		
5780 		this.loadParams = options.loadParams;
5781 		this.onLoad = options.onLoad;
5782 	}
5783 
5784 	//console.log("timezone: locale is " + this.locale);
5785 	
5786 	if (!this.id) {
5787 		new LocaleInfo(this.locale, {
5788 			sync: this.sync,
5789 			onLoad: ilib.bind(this, function (li) {
5790 				this.id = li.getTimeZone() || "Etc/UTC";
5791 				this._loadtzdata();
5792 			})
5793 		});
5794 	} else {
5795 		this._loadtzdata();
5796 	}
5797 
5798 	//console.log("localeinfo is: " + JSON.stringify(this.locinfo));
5799 	//console.log("id is: " + JSON.stringify(this.id));
5800 };
5801 
5802 /*
5803  * Explanation of the compressed time zone info properties.
5804  * {
5805  *     "o": "8:0",      // offset from UTC
5806  *     "f": "W{c}T",    // standard abbreviation. For time zones that observe DST, the {c} replacement is replaced with the 
5807  *                      // letter in the e.c or s.c properties below 
5808  *     "e": {           // info about the end of DST
5809  *         "j": 78322.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
5810  *                      // "t" properties, but not both sets.
5811  *         "m": 3,      // month that it ends
5812  *         "r": "l0",   // rule for the day it ends "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7". 
5813  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
5814  *         "t": "2:0",  // time of day that the DST turns off, hours:minutes
5815  *         "c": "S"     // character to replace into the abbreviation for standard time 
5816  *     },
5817  *     "s": {           // info about the start of DST
5818  *         "j": 78189.5 // Julian day when the transition happens. Either specify the "j" property or all of the "m", "r", and 
5819  *                      // "t" properties, but not both sets.
5820  *         "m": 10,     // month that it starts
5821  *         "r": "l0",   // rule for the day it starts "l" = "last", numbers are Sun=0 through Sat=6. Other syntax is "0>7".
5822  *                      // This means the 0-day (Sun) after the 7th of the month. Other possible operators are <, >, <=, >=
5823  *         "t": "2:0",  // time of day that the DST turns on, hours:minutes
5824  *         "v": "1:0",  // amount of time saved in hours:minutes
5825  *         "c": "D"     // character to replace into the abbreviation for daylight time
5826  *     },
5827  *     "c": "AU",       // ISO code for the country that contains this time zone
5828  *     "n": "W. Australia {c} Time"
5829  *                      // long English name of the zone. The {c} replacement is for the word "Standard" or "Daylight" as appropriate
5830  * }
5831  */
5832 TimeZone.prototype._loadtzdata = function () {
5833 	// console.log("id is: " + JSON.stringify(this.id));
5834 	// console.log("zoneinfo is: " + JSON.stringify(ilib.data.zoneinfo[this.id]));
5835 	if (!ilib.data.zoneinfo[this.id] && typeof(this.offset) === 'undefined') {
5836 		Utils.loadData({
5837 			object: TimeZone, 
5838 			nonlocale: true,	// locale independent 
5839 			name: "zoneinfo/" + this.id + ".json", 
5840 			sync: this.sync, 
5841 			loadParams: this.loadParams, 
5842 			callback: ilib.bind(this, function (tzdata) {
5843 				if (tzdata && !JSUtils.isEmpty(tzdata)) {
5844 					ilib.data.zoneinfo[this.id] = tzdata;
5845 				}
5846 				this._initZone();
5847 			})
5848 		});
5849 	} else {
5850 		this._initZone();
5851 	}
5852 };
5853 
5854 TimeZone.prototype._initZone = function() {
5855 	/** 
5856 	 * @private
5857 	 * @type {{o:string,f:string,e:Object.<{m:number,r:string,t:string,z:string}>,s:Object.<{m:number,r:string,t:string,z:string,v:string,c:string}>,c:string,n:string}} 
5858 	 */
5859 	this.zone = ilib.data.zoneinfo[this.id];
5860 	if (!this.zone && typeof(this.offset) === 'undefined') {
5861 		this.id = "Etc/UTC";
5862 		this.zone = ilib.data.zoneinfo[this.id];
5863 	}
5864 	
5865 	this._calcDSTSavings();
5866 	
5867 	if (typeof(this.offset) === 'undefined' && this.zone.o) {
5868 		var offsetParts = this._offsetStringToObj(this.zone.o);
5869 		/**
5870 		 * @private
5871 		 * @type {number} raw offset from UTC without DST, in minutes
5872 		 */
5873 		this.offset = (Math.abs(offsetParts.h || 0) * 60 + (offsetParts.m || 0)) * MathUtils.signum(offsetParts.h || 0);
5874 	}
5875 	
5876 	if (this.onLoad && typeof(this.onLoad) === 'function') {
5877 		this.onLoad(this);
5878 	}
5879 };
5880 
5881 /** @private */
5882 TimeZone._marshallIds = function (country, sync, callback) {
5883 	var tz, ids = [];
5884 	
5885 	if (!country) {
5886 		// local is a special zone meaning "the local time zone according to the JS engine we are running upon"
5887 		ids.push("local");
5888 		for (tz in ilib.data.timezones) {
5889 			if (ilib.data.timezones[tz]) {
5890 				ids.push(ilib.data.timezones[tz]);
5891 			}
5892 		}
5893 		if (typeof(callback) === 'function') {
5894 			callback(ids);
5895 		}
5896 	} else {
5897 		if (!ilib.data.zoneinfo.zonetab) {
5898 			Utils.loadData({
5899 				object: TimeZone, 
5900 				nonlocale: true,	// locale independent 
5901 				name: "zoneinfo/zonetab.json", 
5902 				sync: sync, 
5903 				callback: ilib.bind(this, function (tzdata) {
5904 					if (tzdata) {
5905 						ilib.data.zoneinfo.zonetab = tzdata;
5906 					}
5907 					
5908 					ids = ilib.data.zoneinfo.zonetab[country];
5909 					
5910 					if (typeof(callback) === 'function') {
5911 						callback(ids);
5912 					}
5913 				})
5914 			});
5915 		} else {
5916 			ids = ilib.data.zoneinfo.zonetab[country];
5917 			if (typeof(callback) === 'function') {
5918 				callback(ids);
5919 			}
5920 		}
5921 	}
5922 	
5923 	return ids;
5924 };
5925 
5926 /**
5927  * Return an array of available zone ids that the constructor knows about.
5928  * The country parameter is optional. If it is not given, all time zones will
5929  * be returned. If it specifies a country code, then only time zones for that
5930  * country will be returned.
5931  * 
5932  * @param {string|undefined} country country code for which time zones are being sought
5933  * @param {boolean} sync whether to find the available ids synchronously (true) or asynchronously (false)
5934  * @param {function(Array.<string>)} onLoad callback function to call when the data is finished loading
5935  * @return {Array.<string>} an array of zone id strings
5936  */
5937 TimeZone.getAvailableIds = function (country, sync, onLoad) {
5938 	var tz, ids = [];
5939 	
5940 	if (typeof(sync) !== 'boolean') {
5941 		sync = true;
5942 	}
5943 	
5944 	if (ilib.data.timezones.length === 0) {
5945 		if (typeof(ilib._load) !== 'undefined' && typeof(ilib._load.listAvailableFiles) === 'function') {
5946 			ilib._load.listAvailableFiles(sync, function(hash) {
5947 				for (var dir in hash) {
5948 					var files = hash[dir];
5949 					if (ilib.isArray(files)) {
5950 						files.forEach(function (filename) {
5951 							if (filename && filename.match(/^zoneinfo/)) {
5952 								ilib.data.timezones.push(filename.replace(/^zoneinfo\//, "").replace(/\.json$/, ""));
5953 							}
5954 						});
5955 					}
5956 				}
5957 				ids = TimeZone._marshallIds(country, sync, onLoad);
5958 			});
5959 		} else {
5960 			for (tz in ilib.data.zoneinfo) {
5961 				if (ilib.data.zoneinfo[tz]) {
5962 					ilib.data.timezones.push(tz);
5963 				}
5964 			}
5965 			ids = TimeZone._marshallIds(country, sync, onLoad);
5966 		}
5967 	} else {
5968 		ids = TimeZone._marshallIds(country, sync, onLoad);
5969 	}
5970 	
5971 	return ids;
5972 };
5973 
5974 /**
5975  * Return the id used to uniquely identify this time zone.
5976  * @return {string} a unique id for this time zone
5977  */
5978 TimeZone.prototype.getId = function () {
5979 	return this.id.toString();
5980 };
5981 
5982 /**
5983  * Return the abbrevi