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 abbreviation that is used for the current time zone on the given date.
5984  * The date may be in DST or during standard time, and many zone names have different
5985  * abbreviations depending on whether or not the date is falls within DST.<p>
5986  * 
5987  * There are two styles that are supported:
5988  * 
5989  * <ol>
5990  * <li>standard - returns the 3 to 5 letter abbreviation of the time zone name such 
5991  * as "CET" for "Central European Time" or "PDT" for "Pacific Daylight Time"
5992  * <li>rfc822 - returns an RFC 822 style time zone specifier, which specifies more
5993  * explicitly what the offset is from UTC
5994  * <li>long - returns the long name of the zone in English
5995  * </ol>
5996  *  
5997  * @param {IDate=} date a date to determine if it is in daylight time or standard time
5998  * @param {string=} style one of "standard" or "rfc822". Default if not specified is "standard"
5999  * @return {string} the name of the time zone, abbreviated according to the style 
6000  */
6001 TimeZone.prototype.getDisplayName = function (date, style) {
6002 	style = (this.isLocal || typeof(this.zone) === 'undefined') ? "rfc822" : (style || "standard");
6003 	switch (style) {
6004 		default:
6005 		case 'standard':
6006 			if (this.zone.f && this.zone.f !== "zzz") {
6007 				if (this.zone.f.indexOf("{c}") !== -1) {
6008 					var letter = "";
6009 					letter = this.inDaylightTime(date) ? this.zone.s && this.zone.s.c : this.zone.e && this.zone.e.c; 
6010 					var temp = new IString(this.zone.f);
6011 					return temp.format({c: letter || ""});
6012 				}
6013 				return this.zone.f;
6014 			} 
6015 			var temp = "GMT" + this.zone.o;
6016 			if (this.inDaylightTime(date)) {
6017 				temp += "+" + this.zone.s.v;
6018 			}
6019 			return temp;
6020 			break;
6021 		case 'rfc822':
6022 			var offset = this.getOffset(date), // includes the DST if applicable
6023 				ret = "UTC",
6024 				hour = offset.h || 0,
6025 				minute = offset.m || 0;
6026 			
6027 			if (hour !== 0) {
6028 				ret += (hour > 0) ? "+" : "-";
6029 				if (Math.abs(hour) < 10) {
6030 					ret += "0";
6031 				}
6032 				ret += (hour < 0) ? -hour : hour;
6033 				if (minute < 10) {
6034 					ret += "0";
6035 				}
6036 				ret += minute;
6037 			}
6038 			return ret; 
6039 		case 'long':
6040 			if (this.zone.n) {
6041 				if (this.zone.n.indexOf("{c}") !== -1) {
6042 					var str = this.inDaylightTime(date) ? "Daylight" : "Standard"; 
6043 					var temp = new IString(this.zone.n);
6044 					return temp.format({c: str || ""});
6045 				}
6046 				return this.zone.n;
6047 			}
6048 			var temp = "GMT" + this.zone.o;
6049 			if (this.inDaylightTime(date)) {
6050 				temp += "+" + this.zone.s.v;
6051 			}
6052 			return temp;
6053 			break;
6054 	}
6055 };
6056 
6057 /**
6058  * Convert the offset string to an object with an h, m, and possibly s property
6059  * to indicate the hours, minutes, and seconds.
6060  * 
6061  * @private
6062  * @param {string} str the offset string to convert to an object
6063  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset for the zone at 
6064  * the given date/time, in hours, minutes, and seconds
6065  */
6066 TimeZone.prototype._offsetStringToObj = function (str) {
6067 	var offsetParts = (typeof(str) === 'string') ? str.split(":") : [],
6068 		ret = {h:0},
6069 		temp;
6070 	
6071 	if (offsetParts.length > 0) {
6072 		ret.h = parseInt(offsetParts[0], 10);
6073 		if (offsetParts.length > 1) {
6074 			temp = parseInt(offsetParts[1], 10);
6075 			if (temp) {
6076 				ret.m = temp;
6077 			}
6078 			if (offsetParts.length > 2) {
6079 				temp = parseInt(offsetParts[2], 10);
6080 				if (temp) {
6081 					ret.s = temp;
6082 				}
6083 			}
6084 		}
6085 	}
6086 
6087 	return ret;
6088 };
6089 
6090 /**
6091  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
6092  * time is in effect at the given date/time, this method will return the offset value 
6093  * adjusted by the amount of daylight saving.
6094  * @param {IDate=} date the date for which the offset is needed
6095  * @return {Object.<{h:number,m:number}>} an object giving the offset for the zone at 
6096  * the given date/time, in hours, minutes, and seconds  
6097  */
6098 TimeZone.prototype.getOffset = function (date) {
6099 	if (!date) {
6100 		return this.getRawOffset();
6101 	}
6102 	var offset = this.getOffsetMillis(date)/60000;
6103 	
6104 	var hours = MathUtils.down(offset/60),
6105 		minutes = Math.abs(offset) - Math.abs(hours)*60;
6106 
6107 	var ret = {
6108 		h: hours
6109 	};
6110 	if (minutes != 0) {
6111 		ret.m = minutes;
6112 	}
6113 	return ret;
6114 };
6115 
6116 /**
6117  * Returns the offset of this time zone from UTC at the given date/time expressed in 
6118  * milliseconds. If daylight saving 
6119  * time is in effect at the given date/time, this method will return the offset value 
6120  * adjusted by the amount of daylight saving. Negative numbers indicate offsets west
6121  * of UTC and conversely, positive numbers indicate offset east of UTC.
6122  *  
6123  * @param {IDate=} date the date for which the offset is needed, or null for the
6124  * present date
6125  * @return {number} the number of milliseconds of offset from UTC that the given date is
6126  */
6127 TimeZone.prototype.getOffsetMillis = function (date) {
6128 	var ret;
6129 	
6130 	// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
6131 	// well if we are in the overlap time at the end of DST
6132 	if (this.isLocal && typeof(date.dst) === 'undefined') {
6133 		var d = (!date) ? new Date() : new Date(date.getTimeExtended());
6134 		return -d.getTimezoneOffset() * 60000;
6135 	} 
6136 	
6137 	ret = this.offset;
6138 	
6139 	if (date && this.inDaylightTime(date)) {
6140 		ret += this.dstSavings;
6141 	}
6142 	
6143 	return ret * 60000;
6144 };
6145 
6146 /**
6147  * Return the offset in milliseconds when the date has an RD number in wall
6148  * time rather than in UTC time.
6149  * @protected
6150  * @param date the date to check in wall time
6151  * @returns {number} the number of milliseconds of offset from UTC that the given date is
6152  */
6153 TimeZone.prototype._getOffsetMillisWallTime = function (date) {
6154 	var ret;
6155 	
6156 	ret = this.offset;
6157 	
6158 	if (date && this.inDaylightTime(date, true)) {
6159 		ret += this.dstSavings;
6160 	}
6161 	
6162 	return ret * 60000;
6163 };
6164 
6165 /**
6166  * Returns the offset of this time zone from UTC at the given date/time. If daylight saving 
6167  * time is in effect at the given date/time, this method will return the offset value 
6168  * adjusted by the amount of daylight saving.
6169  * @param {IDate=} date the date for which the offset is needed
6170  * @return {string} the offset for the zone at the given date/time as a string in the 
6171  * format "h:m:s" 
6172  */
6173 TimeZone.prototype.getOffsetStr = function (date) {
6174 	var offset = this.getOffset(date),
6175 		ret;
6176 	
6177 	ret = offset.h;
6178 	if (typeof(offset.m) !== 'undefined') {
6179 		ret += ":" + offset.m;
6180 		if (typeof(offset.s) !== 'undefined') {
6181 			ret += ":" + offset.s;
6182 		}
6183 	} else {
6184 		ret += ":0";
6185 	}
6186 	
6187 	return ret;
6188 };
6189 
6190 /**
6191  * Gets the offset from UTC for this time zone.
6192  * @return {Object.<{h:number,m:number,s:number}>} an object giving the offset from 
6193  * UTC for this time zone, in hours, minutes, and seconds 
6194  */
6195 TimeZone.prototype.getRawOffset = function () {
6196 	var hours = MathUtils.down(this.offset/60),
6197 		minutes = Math.abs(this.offset) - Math.abs(hours)*60;
6198 	
6199 	var ret = {
6200 		h: hours
6201 	};
6202 	if (minutes != 0) {
6203 		ret.m = minutes;
6204 	}
6205 	return ret;
6206 };
6207 
6208 /**
6209  * Gets the offset from UTC for this time zone expressed in milliseconds. Negative numbers
6210  * indicate zones west of UTC, and positive numbers indicate zones east of UTC.
6211  * 
6212  * @return {number} an number giving the offset from 
6213  * UTC for this time zone in milliseconds 
6214  */
6215 TimeZone.prototype.getRawOffsetMillis = function () {
6216 	return this.offset * 60000;
6217 };
6218 
6219 /**
6220  * Gets the offset from UTC for this time zone without DST savings.
6221  * @return {string} the offset from UTC for this time zone, in the format "h:m:s" 
6222  */
6223 TimeZone.prototype.getRawOffsetStr = function () {
6224 	var off = this.getRawOffset();
6225 	return off.h + ":" + (off.m || "0");
6226 };
6227 
6228 /**
6229  * Return the amount of time in hours:minutes that the clock is advanced during
6230  * daylight savings time.
6231  * @return {Object.<{h:number,m:number,s:number}>} the amount of time that the 
6232  * clock advances for DST in hours, minutes, and seconds 
6233  */
6234 TimeZone.prototype.getDSTSavings = function () {
6235 	if (this.isLocal) {
6236 		// take the absolute because the difference in the offsets may be positive or
6237 		// negative, depending on the hemisphere
6238 		var savings = Math.abs(this.offsetJan1 - this.offsetJun1);
6239 		var hours = MathUtils.down(savings/60),
6240 			minutes = savings - hours*60;
6241 		return {
6242 			h: hours,
6243 			m: minutes
6244 		};
6245 	} else if (this.zone && this.zone.s) {
6246 		return this._offsetStringToObj(this.zone.s.v);	// this.zone.start.savings
6247 	}
6248 	return {h:0};
6249 };
6250 
6251 /**
6252  * Return the amount of time in hours:minutes that the clock is advanced during
6253  * daylight savings time.
6254  * @return {string} the amount of time that the clock advances for DST in the
6255  * format "h:m:s"
6256  */
6257 TimeZone.prototype.getDSTSavingsStr = function () {
6258 	if (this.isLocal) {
6259 		var savings = this.getDSTSavings();
6260 		return savings.h + ":" + savings.m;
6261 	} else if (typeof(this.offset) !== 'undefined' && this.zone && this.zone.s) {
6262 		return this.zone.s.v;	// this.zone.start.savings
6263 	}
6264 	return "0:0";
6265 };
6266 
6267 /**
6268  * return the rd of the start of DST transition for the given year
6269  * @protected
6270  * @param {Object} rule set of rules
6271  * @param {number} year year to check
6272  * @return {number} the rd of the start of DST for the year
6273  */
6274 TimeZone.prototype._calcRuleStart = function (rule, year) {
6275 	var type = "=", 
6276 		weekday = 0, 
6277 		day, 
6278 		refDay, 
6279 		cal, 
6280 		hour = 0, 
6281 		minute = 0, 
6282 		second = 0,
6283 		time,
6284 		i;
6285 	
6286 	if (typeof(rule.j) !== 'undefined') {
6287 		refDay = new GregRataDie({
6288 			julianday: rule.j
6289 		});
6290 	} else {
6291 		if (rule.r.charAt(0) == 'l' || rule.r.charAt(0) == 'f') {
6292 			cal = CalendarFactory({type: "gregorian"});
6293 			type = rule.r.charAt(0);
6294 			weekday = parseInt(rule.r.substring(1), 10);
6295 			day = (type === 'l') ? cal.getMonLength(rule.m, year) : 1;
6296 			//console.log("_calcRuleStart: Calculating the " + 
6297 			//		(rule.r.charAt(0) == 'f' ? "first " : "last ") + weekday + 
6298 			//		" of month " + rule.m);
6299 		} else {
6300 			i = rule.r.indexOf('<');
6301 			if (i == -1) {
6302 				i = rule.r.indexOf('>');
6303 			}
6304 			
6305 			if (i != -1) {
6306 				type = rule.r.charAt(i);
6307 				weekday = parseInt(rule.r.substring(0, i), 10);
6308 				day = parseInt(rule.r.substring(i+1), 10); 
6309 				//console.log("_calcRuleStart: Calculating the " + weekday + 
6310 				//		type + day + " of month " + rule.m);
6311 			} else {
6312 				day = parseInt(rule.r, 10);
6313 				//console.log("_calcRuleStart: Calculating the " + day + " of month " + rule.m);
6314 			}
6315 		}
6316 	
6317 		if (rule.t) {
6318 			time = rule.t.split(":");
6319 			hour = parseInt(time[0], 10);
6320 			if (time.length > 1) {
6321 				minute = parseInt(time[1], 10);
6322 				if (time.length > 2) {
6323 					second = parseInt(time[2], 10);
6324 				}
6325 			}
6326 		}
6327 		//console.log("calculating rd of " + year + "/" + rule.m + "/" + day);
6328 		refDay = new GregRataDie({
6329 			year: year, 
6330 			month: rule.m, 
6331 			day: day, 
6332 			hour: hour, 
6333 			minute: minute, 
6334 			second: second
6335 		});
6336 	}
6337 	//console.log("refDay is " + JSON.stringify(refDay));
6338 	var d = refDay.getRataDie();
6339 	
6340 	switch (type) {
6341 		case 'l':
6342 		case '<':
6343 			//console.log("returning " + refDay.onOrBefore(rd, weekday));
6344 			d = refDay.onOrBefore(weekday); 
6345 			break;
6346 		case 'f':
6347 		case '>':
6348 			//console.log("returning " + refDay.onOrAfterRd(rd, weekday));
6349 			d = refDay.onOrAfter(weekday); 
6350 			break;
6351 	}
6352 	return d;
6353 };
6354 
6355 /**
6356  * @private
6357  */
6358 TimeZone.prototype._calcDSTSavings = function () {
6359 	var saveParts = this.getDSTSavings();
6360 	
6361 	/**
6362 	 * @private
6363 	 * @type {number} savings in minutes when DST is in effect 
6364 	 */
6365 	this.dstSavings = (Math.abs(saveParts.h || 0) * 60 + (saveParts.m || 0)) * MathUtils.signum(saveParts.h || 0);
6366 };
6367 
6368 /**
6369  * @private
6370  */
6371 TimeZone.prototype._getDSTStartRule = function (year) {
6372 	// TODO: update this when historic/future zones are supported
6373 	return this.zone.s;
6374 };
6375 
6376 /**
6377  * @private
6378  */
6379 TimeZone.prototype._getDSTEndRule = function (year) {
6380 	// TODO: update this when historic/future zones are supported
6381 	return this.zone.e;
6382 };
6383 
6384 /**
6385  * Returns whether or not the given date is in daylight saving time for the current
6386  * zone. Note that daylight savings time is observed for the summer. Because
6387  * the seasons are reversed, daylight savings time in the southern hemisphere usually
6388  * runs from the end of the year through New Years into the first few months of the
6389  * next year. This method will correctly calculate the start and end of DST for any
6390  * location.
6391  * 
6392  * @param {IDate=} date a date for which the info about daylight time is being sought,
6393  * or undefined to tell whether we are currently in daylight savings time
6394  * @param {boolean=} wallTime if true, then the given date is in wall time. If false or
6395  * undefined, it is in the usual UTC time.
6396  * @return {boolean} true if the given date is in DST for the current zone, and false
6397  * otherwise.
6398  */
6399 TimeZone.prototype.inDaylightTime = function (date, wallTime) {
6400 	var rd, startRd, endRd, year;
6401 
6402 	if (this.isLocal) {
6403 		// check if the dst property is defined -- the intrinsic JS Date object doesn't work so
6404 		// well if we are in the overlap time at the end of DST, so we have to work around that
6405 		// problem by adding in the savings ourselves
6406 		var offset = 0;
6407 		if (typeof(date.dst) !== 'undefined' && !date.dst) {
6408 			offset = this.dstSavings * 60000;
6409 		}
6410 		
6411 		var d = new Date(date ? date.getTimeExtended() + offset: undefined);
6412 		// the DST offset is always the one that is closest to positive infinity, no matter 
6413 		// if you are in the northern or southern hemisphere, east or west
6414 		var dst = Math.max(this.offsetJan1, this.offsetJun1);
6415 		return (-d.getTimezoneOffset() === dst);
6416 	}
6417 	
6418 	if (!date || !date.cal || date.cal.type !== "gregorian") {
6419 		// convert to Gregorian so that we can tell if it is in DST or not
6420 		var time = date && typeof(date.getTimeExtended) === 'function' ? date.getTimeExtended() : undefined;
6421 		rd = new GregRataDie({unixtime: time}).getRataDie();
6422 		year = new Date(time).getUTCFullYear();
6423 	} else {
6424 		rd = date.rd.getRataDie();
6425 		year = date.year;
6426 	}
6427 	// rd should be a Gregorian RD number now, in UTC
6428 	
6429 	// if we aren't using daylight time in this zone for the given year, then we are 
6430 	// not in daylight time
6431 	if (!this.useDaylightTime(year)) {
6432 		return false;
6433 	}
6434 	
6435 	// these calculate the start/end in local wall time
6436 	var startrule = this._getDSTStartRule(year);
6437 	var endrule = this._getDSTEndRule(year);
6438 	startRd = this._calcRuleStart(startrule, year);
6439 	endRd = this._calcRuleStart(endrule, year);
6440 	
6441 	if (wallTime) {
6442 		// rd is in wall time, so we have to make sure to skip the missing time
6443 		// at the start of DST when standard time ends and daylight time begins
6444 		startRd += this.dstSavings/1440;
6445 	} else {
6446 		// rd is in UTC, so we have to convert the start/end to UTC time so 
6447 		// that they can be compared directly to the UTC rd number of the date
6448 		
6449 		// when DST starts, time is standard time already, so we only have
6450 		// to subtract the offset to get to UTC and not worry about the DST savings
6451 		startRd -= this.offset/1440;  
6452 		
6453 		// when DST ends, time is in daylight time already, so we have to
6454 		// subtract the DST savings to get back to standard time, then the
6455 		// offset to get to UTC
6456 		endRd -= (this.offset + this.dstSavings)/1440;
6457 	}
6458 	
6459 	// In the northern hemisphere, the start comes first some time in spring (Feb-Apr), 
6460 	// then the end some time in the fall (Sept-Nov). In the southern
6461 	// hemisphere, it is the other way around because the seasons are reversed. Standard
6462 	// time is still in the winter, but the winter months are May-Aug, and daylight 
6463 	// savings time usually starts Aug-Oct of one year and runs through Mar-May of the 
6464 	// next year.
6465 	if (rd < endRd && endRd - rd <= this.dstSavings/1440 && typeof(date.dst) === 'boolean') {
6466 		// take care of the magic overlap time at the end of DST
6467 		return date.dst;
6468 	}
6469 	if (startRd < endRd) {
6470 		// northern hemisphere
6471 		return (rd >= startRd && rd < endRd) ? true : false;
6472 	} 
6473 	// southern hemisphere
6474 	return (rd >= startRd || rd < endRd) ? true : false;
6475 };
6476 
6477 /**
6478  * Returns true if this time zone switches to daylight savings time at some point
6479  * in the year, and false otherwise.
6480  * @param {number} year Whether or not the time zone uses daylight time in the given year. If
6481  * this parameter is not given, the current year is assumed.
6482  * @return {boolean} true if the time zone uses daylight savings time
6483  */
6484 TimeZone.prototype.useDaylightTime = function (year) {
6485 	
6486 	// this zone uses daylight savings time iff there is a rule defining when to start
6487 	// and when to stop the DST
6488 	return (this.isLocal && this.offsetJan1 !== this.offsetJun1) ||
6489 		(typeof(this.zone) !== 'undefined' && 
6490 		typeof(this.zone.s) !== 'undefined' && 
6491 		typeof(this.zone.e) !== 'undefined');
6492 };
6493 
6494 /**
6495  * Returns the ISO 3166 code of the country for which this time zone is defined.
6496  * @return {string} the ISO 3166 code of the country for this zone
6497  */
6498 TimeZone.prototype.getCountry = function () {
6499 	return this.zone.c;
6500 };
6501 
6502 
6503 
6504 /*< SearchUtils.js */
6505 /*
6506  * SearchUtils.js - Misc search utility routines
6507  * 
6508  * Copyright © 2013-2015, JEDLSoft
6509  *
6510  * Licensed under the Apache License, Version 2.0 (the "License");
6511  * you may not use this file except in compliance with the License.
6512  * You may obtain a copy of the License at
6513  *
6514  *     http://www.apache.org/licenses/LICENSE-2.0
6515  *
6516  * Unless required by applicable law or agreed to in writing, software
6517  * distributed under the License is distributed on an "AS IS" BASIS,
6518  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6519  *
6520  * See the License for the specific language governing permissions and
6521  * limitations under the License.
6522  */
6523 
6524 var SearchUtils = {};
6525 
6526 /**
6527  * Binary search a sorted array for a particular target value.
6528  * If the exact value is not found, it returns the index of the smallest 
6529  * entry that is greater than the given target value.<p> 
6530  * 
6531  * The comparator
6532  * parameter is a function that knows how to compare elements of the 
6533  * array and the target. The function should return a value greater than 0
6534  * if the array element is greater than the target, a value less than 0 if
6535  * the array element is less than the target, and 0 if the array element 
6536  * and the target are equivalent.<p>
6537  * 
6538  * If the comparator function is not specified, this function assumes
6539  * the array and the target are numeric values and should be compared 
6540  * as such.<p>
6541  * 
6542  * 
6543  * @static
6544  * @param {*} target element being sought 
6545  * @param {Array} arr the array being searched
6546  * @param {?function(*,*)=} comparator a comparator that is appropriate for comparing two entries
6547  * in the array  
6548  * @return the index of the array into which the value would fit if 
6549  * inserted, or -1 if given array is not an array or the target is not 
6550  * a number
6551  */
6552 SearchUtils.bsearch = function(target, arr, comparator) {
6553 	if (typeof(arr) === 'undefined' || !arr || typeof(target) === 'undefined') {
6554 		return -1;
6555 	}
6556 	
6557 	var high = arr.length - 1,
6558 		low = 0,
6559 		mid = 0,
6560 		value,
6561 		cmp = comparator || SearchUtils.bsearch.numbers;
6562 	
6563 	while (low <= high) {
6564 		mid = Math.floor((high+low)/2);
6565 		value = cmp(arr[mid], target);
6566 		if (value > 0) {
6567 			high = mid - 1;
6568 		} else if (value < 0) {
6569 			low = mid + 1;
6570 		} else {
6571 			return mid;
6572 		}
6573 	}
6574 	
6575 	return low;
6576 };
6577 
6578 /**
6579  * Returns whether or not the given element is greater than, less than,
6580  * or equal to the given target.<p>
6581  * 
6582  * @private
6583  * @static
6584  * @param {number} element the element being tested
6585  * @param {number} target the target being sought
6586  */
6587 SearchUtils.bsearch.numbers = function(element, target) {
6588 	return element - target;
6589 };
6590 
6591 /**
6592  * Do a bisection search of a function for a particular target value.<p> 
6593  * 
6594  * The function to search is a function that takes a numeric parameter, 
6595  * does calculations, and returns gives a numeric result. The 
6596  * function should should be smooth and not have any discontinuities 
6597  * between the low and high values of the parameter.
6598  *  
6599  * 
6600  * @static
6601  * @param {number} target value being sought
6602  * @param {number} low the lower bounds to start searching
6603  * @param {number} high the upper bounds to start searching
6604  * @param {number} precision minimum precision to support. Use 0 if you want to use the default.
6605  * @param {?function(number)=} func function to search 
6606  * @return an approximation of the input value to the function that gives the desired
6607  * target output value, correct to within the error range of Javascript floating point 
6608  * arithmetic, or NaN if there was some error
6609  */
6610 SearchUtils.bisectionSearch = function(target, low, high, precision, func) {
6611 	if (typeof(target) !== 'number' || 
6612 			typeof(low) !== 'number' || 
6613 			typeof(high) !== 'number' || 
6614 			typeof(func) !== 'function') {
6615 		return NaN;
6616 	}
6617 	
6618 	var mid = 0,
6619 		value,
6620 		pre = precision > 0 ? precision : 1e-13;
6621 	
6622 	do {
6623 		mid = (high+low)/2;
6624 		value = func(mid);
6625 		if (value > target) {
6626 			high = mid;
6627 		} else if (value < target) {
6628 			low = mid;
6629 		}
6630 	} while (high - low > pre);
6631 	
6632 	return mid;
6633 };
6634 
6635 
6636 
6637 /*< GregorianDate.js */
6638 /*
6639  * GregorianDate.js - Represent a date in the Gregorian calendar
6640  * 
6641  * Copyright © 2012-2015, JEDLSoft
6642  *
6643  * Licensed under the Apache License, Version 2.0 (the "License");
6644  * you may not use this file except in compliance with the License.
6645  * You may obtain a copy of the License at
6646  *
6647  *     http://www.apache.org/licenses/LICENSE-2.0
6648  *
6649  * Unless required by applicable law or agreed to in writing, software
6650  * distributed under the License is distributed on an "AS IS" BASIS,
6651  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6652  *
6653  * See the License for the specific language governing permissions and
6654  * limitations under the License.
6655  */
6656 
6657 /* !depends 
6658 ilib.js
6659 IDate.js 
6660 GregorianCal.js 
6661 SearchUtils.js
6662 MathUtils.js
6663 Locale.js
6664 LocaleInfo.js 
6665 JulianDay.js
6666 GregRataDie.js
6667 TimeZone.js
6668 */
6669 
6670 
6671 
6672 
6673 /**
6674  * @class
6675  * Construct a new Gregorian date object. The constructor parameters can 
6676  * contain any of the following properties:
6677  * 
6678  * <ul>
6679  * <li><i>unixtime<i> - sets the time of this instance according to the given 
6680  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
6681  * 
6682  * <li><i>julianday</i> - sets the time of this instance according to the given
6683  * Julian Day instance or the Julian Day given as a float
6684  * 
6685  * <li><i>year</i> - any integer, including 0
6686  * 
6687  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
6688  * 
6689  * <li><i>day</i> - 1 to 31
6690  * 
6691  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
6692  * is always done with an unambiguous 24 hour representation
6693  * 
6694  * <li><i>minute</i> - 0 to 59
6695  * 
6696  * <li><i>second</i> - 0 to 59
6697  * 
6698  * <li><i>millisecond</i> - 0 to 999
6699  * 
6700  * <li><i>dst</i> - boolean used to specify whether the given time components are
6701  * intended to be in daylight time or not. This is only used in the overlap
6702  * time when transitioning from DST to standard time, and the time components are 
6703  * ambiguous. Otherwise at all other times of the year, this flag is ignored.
6704  * If you specify the date using unix time (UTC) or a julian day, then the time is
6705  * already unambiguous and this flag does not need to be specified.
6706  * <p>
6707  * For example, in the US, the transition out of daylight savings time 
6708  * in 2014 happens at Nov 2, 2014 2:00am Daylight Time, when the time falls 
6709  * back to Nov 2, 2014 1:00am Standard Time. If you give a date/time components as 
6710  * "Nov 2, 2014 1:30am", then there are two 1:30am times in that day, and you would 
6711  * have to give the standard flag to indicate which of those two you mean. 
6712  * (dst=true means daylight time, dst=false means standard time).   
6713  * 
6714  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
6715  * of this gregorian date. The date/time is kept in the local time. The time zone
6716  * is used later if this date is formatted according to a different time zone and
6717  * the difference has to be calculated, or when the date format has a time zone
6718  * component in it.
6719  * 
6720  * <li><i>locale</i> - locale for this gregorian date. If the time zone is not 
6721  * given, it can be inferred from this locale. For locales that span multiple
6722  * time zones, the one with the largest population is chosen as the one that 
6723  * represents the locale.
6724  * 
6725  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
6726  * </ul>
6727  *
6728  * If the constructor is called with another Gregorian date instance instead of
6729  * a parameter block, the other instance acts as a parameter block and its
6730  * settings are copied into the current instance.<p>
6731  * 
6732  * If the constructor is called with no arguments at all or if none of the 
6733  * properties listed above 
6734  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
6735  * components are 
6736  * filled in with the current date at the time of instantiation. Note that if
6737  * you do not give the time zone when defaulting to the current time and the 
6738  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
6739  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
6740  * Mean Time").<p>
6741  * 
6742  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
6743  * specified in the params, it is assumed that they have the smallest possible
6744  * value in the range for the property (zero or one).<p>
6745  * 
6746  * 
6747  * @constructor
6748  * @extends IDate
6749  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian date
6750  */
6751 var GregorianDate = function(params) {
6752 	this.cal = new GregorianCal();
6753 	this.timezone = "local";
6754 
6755 	if (params) {
6756 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
6757 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
6758 			return;
6759 		}
6760 		if (params.locale) {
6761 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
6762 			var li = new LocaleInfo(this.locale);
6763 			this.timezone = li.getTimeZone(); 
6764 		}
6765 		if (params.timezone) {
6766 			this.timezone = params.timezone.toString();
6767 		}
6768 		
6769 		if (params.year || params.month || params.day || params.hour ||
6770 				params.minute || params.second || params.millisecond ) {
6771 			this.year = parseInt(params.year, 10) || 0;
6772 			this.month = parseInt(params.month, 10) || 1;
6773 			this.day = parseInt(params.day, 10) || 1;
6774 			this.hour = parseInt(params.hour, 10) || 0;
6775 			this.minute = parseInt(params.minute, 10) || 0;
6776 			this.second = parseInt(params.second, 10) || 0;
6777 			this.millisecond = parseInt(params.millisecond, 10) || 0;
6778 			if (typeof(params.dst) === 'boolean') {
6779 				this.dst = params.dst;
6780 			}
6781 			this.rd = this.newRd(params);
6782 			
6783 			// add the time zone offset to the rd to convert to UTC
6784 			this.offset = 0;
6785 			if (this.timezone === "local" && typeof(params.dst) === 'undefined') {
6786 				// if dst is defined, the intrinsic Date object has no way of specifying which version of a time you mean
6787 				// in the overlap time at the end of DST. Do you mean the daylight 1:30am or the standard 1:30am? In this
6788 				// case, use the ilib calculations below, which can distinguish between the two properly
6789 				var d = new Date(this.year, this.month-1, this.day, this.hour, this.minute, this.second, this.millisecond);
6790 				this.offset = -d.getTimezoneOffset() / 1440;
6791 			} else {
6792 				if (!this.tz) {
6793 					this.tz = new TimeZone({id: this.timezone});
6794 				}
6795 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
6796 				// are set in order to figure out which time zone rules apply and 
6797 				// what the offset is at that point in the year
6798 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
6799 			}
6800 			if (this.offset !== 0) {
6801 				this.rd = this.newRd({
6802 					rd: this.rd.getRataDie() - this.offset
6803 				});
6804 			}
6805 		}
6806 	} 
6807 
6808 	if (!this.rd) {
6809 		this.rd = this.newRd(params);
6810 		this._calcDateComponents();
6811 	}
6812 };
6813 
6814 GregorianDate.prototype = new IDate({noinstance: true});
6815 GregorianDate.prototype.parent = IDate;
6816 GregorianDate.prototype.constructor = GregorianDate;
6817 
6818 /**
6819  * Return a new RD for this date type using the given params.
6820  * @private
6821  * @param {Object=} params the parameters used to create this rata die instance
6822  * @returns {RataDie} the new RD instance for the given params
6823  */
6824 GregorianDate.prototype.newRd = function (params) {
6825 	return new GregRataDie(params);
6826 };
6827 
6828 /**
6829  * Calculates the Gregorian year for a given rd number.
6830  * @private
6831  * @static
6832  */
6833 GregorianDate._calcYear = function(rd) {
6834 	var days400,
6835 		days100,
6836 		days4,
6837 		years400,
6838 		years100,
6839 		years4,
6840 		years1,
6841 		year;
6842 
6843 	years400 = Math.floor((rd - 1) / 146097);
6844 	days400 = MathUtils.mod((rd - 1), 146097);
6845 	years100 = Math.floor(days400 / 36524);
6846 	days100 = MathUtils.mod(days400, 36524);
6847 	years4 = Math.floor(days100 / 1461);
6848 	days4 = MathUtils.mod(days100, 1461);
6849 	years1 = Math.floor(days4 / 365);
6850 	
6851 	year = 400 * years400 + 100 * years100 + 4 * years4 + years1;
6852 	if (years100 !== 4 && years1 !== 4) {
6853 		year++;
6854 	}
6855 	return year;
6856 };
6857 
6858 /**
6859  * @private
6860  */
6861 GregorianDate.prototype._calcYear = function(rd) {
6862 	return GregorianDate._calcYear(rd);
6863 };
6864 
6865 /**
6866  * Calculate the date components for the current time zone
6867  * @private
6868  */
6869 GregorianDate.prototype._calcDateComponents = function () {
6870 	if (this.timezone === "local" && this.rd.getRataDie() >= -99280837 && this.rd.getRataDie() <= 100719163) {
6871 		// console.log("using js Date to calculate offset");
6872 		// use the intrinsic JS Date object to do the tz conversion for us, which 
6873 		// guarantees that it follows the system tz database settings 
6874 		var d = new Date(this.rd.getTimeExtended());
6875 	
6876 		/**
6877 		 * Year in the Gregorian calendar.
6878 		 * @type number
6879 		 */
6880 		this.year = d.getFullYear();
6881 		
6882 		/**
6883 		 * The month number, ranging from 1 (January) to 12 (December).
6884 		 * @type number
6885 		 */
6886 		this.month = d.getMonth()+1;
6887 		
6888 		/**
6889 		 * The day of the month. This ranges from 1 to 31.
6890 		 * @type number
6891 		 */
6892 		this.day = d.getDate();
6893 		
6894 		/**
6895 		 * The hour of the day. This can be a number from 0 to 23, as times are
6896 		 * stored unambiguously in the 24-hour clock.
6897 		 * @type number
6898 		 */
6899 		this.hour = d.getHours();
6900 		
6901 		/**
6902 		 * The minute of the hours. Ranges from 0 to 59.
6903 		 * @type number
6904 		 */
6905 		this.minute = d.getMinutes();
6906 		
6907 		/**
6908 		 * The second of the minute. Ranges from 0 to 59.
6909 		 * @type number
6910 		 */
6911 		this.second = d.getSeconds();
6912 		
6913 		/**
6914 		 * The millisecond of the second. Ranges from 0 to 999.
6915 		 * @type number
6916 		 */
6917 		this.millisecond = d.getMilliseconds();
6918 		
6919 		this.offset = -d.getTimezoneOffset() / 1440;
6920 	} else {
6921 		// console.log("using ilib to calculate offset. tz is " + this.timezone);
6922 		// console.log("GregDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
6923 		if (typeof(this.offset) === "undefined") {
6924 			// console.log("calculating offset");
6925 			this.year = this._calcYear(this.rd.getRataDie());
6926 			
6927 			// now offset the RD by the time zone, then recalculate in case we were 
6928 			// near the year boundary
6929 			if (!this.tz) {
6930 				this.tz = new TimeZone({id: this.timezone});
6931 			}
6932 			this.offset = this.tz.getOffsetMillis(this) / 86400000;
6933 		// } else {
6934 			// console.log("offset is already defined somehow. type is " + typeof(this.offset));
6935 			// console.trace("Stack is this one");
6936 		}
6937 		// console.log("offset is " + this.offset);
6938 		var rd = this.rd.getRataDie();
6939 		if (this.offset !== 0) {
6940 			rd += this.offset;
6941 		}
6942 		this.year = this._calcYear(rd);
6943 		
6944 		var yearStartRd = this.newRd({
6945 			year: this.year,
6946 			month: 1,
6947 			day: 1,
6948 			cal: this.cal
6949 		});
6950 		
6951 		// remainder is days into the year
6952 		var remainder = rd - yearStartRd.getRataDie() + 1;
6953 		
6954 		var cumulative = GregorianCal.prototype.isLeapYear.call(this.cal, this.year) ? 
6955 			GregRataDie.cumMonthLengthsLeap : 
6956 			GregRataDie.cumMonthLengths; 
6957 		
6958 		this.month = SearchUtils.bsearch(Math.floor(remainder), cumulative);
6959 		remainder = remainder - cumulative[this.month-1];
6960 		
6961 		this.day = Math.floor(remainder);
6962 		remainder -= this.day;
6963 		// now convert to milliseconds for the rest of the calculation
6964 		remainder = Math.round(remainder * 86400000);
6965 		
6966 		this.hour = Math.floor(remainder/3600000);
6967 		remainder -= this.hour * 3600000;
6968 		
6969 		this.minute = Math.floor(remainder/60000);
6970 		remainder -= this.minute * 60000;
6971 		
6972 		this.second = Math.floor(remainder/1000);
6973 		remainder -= this.second * 1000;
6974 		
6975 		this.millisecond = Math.floor(remainder);
6976 	}
6977 };
6978 
6979 /**
6980  * Return the day of the week of this date. The day of the week is encoded
6981  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
6982  * 
6983  * @return {number} the day of the week
6984  */
6985 GregorianDate.prototype.getDayOfWeek = function() {
6986 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
6987 	return MathUtils.mod(rd, 7);
6988 };
6989 
6990 /**
6991  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
6992  * 365, regardless of months or weeks, etc. That is, January 1st is day 1, and 
6993  * December 31st is 365 in regular years, or 366 in leap years.
6994  * @return {number} the ordinal day of the year
6995  */
6996 GregorianDate.prototype.getDayOfYear = function() {
6997 	var cumulativeMap = this.cal.isLeapYear(this.year) ? 
6998 		GregRataDie.cumMonthLengthsLeap : 
6999 		GregRataDie.cumMonthLengths; 
7000 		
7001 	return cumulativeMap[this.month-1] + this.day;
7002 };
7003 
7004 /**
7005  * Return the era for this date as a number. The value for the era for Gregorian 
7006  * calendars is -1 for "before the common era" (BCE) and 1 for "the common era" (CE). 
7007  * BCE dates are any date before Jan 1, 1 CE. In the proleptic Gregorian calendar, 
7008  * there is a year 0, so any years that are negative or zero are BCE. In the Julian
7009  * calendar, there is no year 0. Instead, the calendar goes straight from year -1 to 
7010  * 1.
7011  * @return {number} 1 if this date is in the common era, -1 if it is before the 
7012  * common era 
7013  */
7014 GregorianDate.prototype.getEra = function() {
7015 	return (this.year < 1) ? -1 : 1;
7016 };
7017 
7018 /**
7019  * Return the name of the calendar that governs this date.
7020  * 
7021  * @return {string} a string giving the name of the calendar
7022  */
7023 GregorianDate.prototype.getCalendar = function() {
7024 	return "gregorian";
7025 };
7026 
7027 // register with the factory method
7028 IDate._constructors["gregorian"] = GregorianDate;
7029 
7030 
7031 /*< DateFactory.js */
7032 /*
7033  * DateFactory.js - Factory class to create the right subclasses of a date for any 
7034  * calendar or locale.
7035  * 
7036  * Copyright © 2012-2015, JEDLSoft
7037  *
7038  * Licensed under the Apache License, Version 2.0 (the "License");
7039  * you may not use this file except in compliance with the License.
7040  * You may obtain a copy of the License at
7041  *
7042  *     http://www.apache.org/licenses/LICENSE-2.0
7043  *
7044  * Unless required by applicable law or agreed to in writing, software
7045  * distributed under the License is distributed on an "AS IS" BASIS,
7046  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7047  *
7048  * See the License for the specific language governing permissions and
7049  * limitations under the License.
7050  */
7051 
7052 /* !depends ilib.js Locale.js LocaleInfo.js JulianDay.js JSUtils.js CalendarFactory.js IDate.js GregorianDate.js*/
7053 
7054 
7055 
7056 // Statically depend on these even though we don't use them
7057 // to guarantee they are loaded into the cache already.
7058 
7059 /**
7060  * Factory method to create a new instance of a date subclass.<p>
7061  * 
7062  * The options parameter can be an object that contains the following
7063  * properties:
7064  * 
7065  * <ul>
7066  * <li><i>type</i> - specify the type/calendar of the date desired. The
7067  * list of valid values changes depending on which calendars are 
7068  * defined. When assembling your iliball.js, include those date type 
7069  * you wish to use in your program or web page, and they will register 
7070  * themselves with this factory method. The "gregorian",
7071  * and "julian" calendars are all included by default, as they are the
7072  * standard calendars for much of the world. If not specified, the type
7073  * of the date returned is the one that is appropriate for the locale.
7074  * This property may also be given as "calendar" instead of "type".
7075  * 
7076  * <li><i>onLoad</i> - a callback function to call when the date object is fully 
7077  * loaded. When the onLoad option is given, the date factory will attempt to
7078  * load any missing locale data using the ilib loader callback.
7079  * When the constructor is done (even if the data is already preassembled), the 
7080  * onLoad function is called with the current instance as a parameter, so this
7081  * callback can be used with preassembled or dynamic loading or a mix of the two.
7082  * 
7083  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
7084  * asynchronously. If this option is given as "false", then the "onLoad"
7085  * callback must be given, as the instance returned from this constructor will
7086  * not be usable for a while.
7087  *  
7088  * <li><i>loadParams</i> - an object containing parameters to pass to the 
7089  * loader callback function when locale data is missing. The parameters are not
7090  * interpretted or modified in any way. They are simply passed along. The object 
7091  * may contain any property/value pairs as long as the calling code is in
7092  * agreement with the loader callback function as to what those parameters mean.
7093  * </ul>
7094  * 
7095  * The options object is also passed down to the date constructor, and 
7096  * thus can contain the the properties as the date object being instantiated.
7097  * See the documentation for {@link GregorianDate}, and other
7098  * subclasses for more details on other parameter that may be passed in.<p>
7099  * 
7100  * Please note that if you do not give the type parameter, this factory
7101  * method will create a date object that is appropriate for the calendar
7102  * that is most commonly used in the specified or current ilib locale. 
7103  * For example, in Thailand, the most common calendar is the Thai solar 
7104  * calendar. If the current locale is "th-TH" (Thai for Thailand) and you 
7105  * use this factory method to construct a new date without specifying the
7106  * type, it will automatically give you back an instance of 
7107  * {@link ThaiSolarDate}. This is convenient because you do not 
7108  * need to know which locales use which types of dates. In fact, you 
7109  * should always use this factory method to make new date instances unless
7110  * you know that you specifically need a date in a particular calendar.<p>
7111  * 
7112  * Also note that when you pass in the date components such as year, month,
7113  * day, etc., these components should be appropriate for the given date
7114  * being instantiated. That is, in our Thai example in the previous
7115  * paragraph, the year and such should be given as a Thai solar year, not
7116  * the Gregorian year that you get from the Javascript Date class. In
7117  * order to initialize a date instance when you don't know what subclass
7118  * will be instantiated for the locale, use a parameter such as "unixtime" 
7119  * or "julianday" which are unambiguous and based on UTC time, instead of
7120  * the year/month/date date components. The date components for that UTC 
7121  * time will be calculated and the time zone offset will be automatically 
7122  * factored in.
7123  * 
7124  * @static
7125  * @param {Object=} options options controlling the construction of this instance, or
7126  * undefined to use the default options
7127  * @return {IDate} an instance of a calendar object of the appropriate type 
7128  */
7129 var DateFactory = function(options) {
7130 	var locale,
7131 		type,
7132 		cons,
7133 		sync = true,
7134 		obj;
7135 
7136 	if (options) {
7137 		if (options.locale) {
7138 			locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
7139 		}
7140 		
7141 		type = options.type || options.calendar;
7142 		
7143 		if (typeof(options.sync) === 'boolean') {
7144 			sync = options.sync;
7145 		}
7146 	}
7147 	
7148 	if (!locale) {
7149 		locale = new Locale();	// default locale
7150 	}
7151 
7152 	if (!type) {
7153 		new LocaleInfo(locale, {
7154 			sync: sync,
7155 			loadParams: options && options.loadParams,
7156 			onLoad: ilib.bind(this, function(info) {
7157 				type = info.getCalendar();
7158 				
7159 				obj = DateFactory._init(type, options);
7160 				
7161 				if (options && typeof(options.onLoad) === 'function') {
7162 					options.onLoad(obj);
7163 				}
7164 			})
7165 		});
7166 	} else {
7167 		obj = DateFactory._init(type, options);
7168 	}
7169 	
7170 	return obj
7171 };
7172 
7173 /**
7174  * Map calendar names to classes to initialize in the dynamic code model.
7175  * TODO: Need to figure out some way that this doesn't have to be updated by hand.
7176  * @private
7177  */
7178 DateFactory._dynMap = {
7179 	"coptic":       "Coptic",
7180 	"ethiopic":     "Ethiopic",
7181 	"gregorian":    "Gregorian",
7182 	"han":          "Han",
7183 	"hebrew":       "Hebrew",
7184 	"islamic":      "Islamic",
7185 	"julian":       "Julian",
7186 	"persian":      "Persian",
7187 	"persian-algo": "PersianAlgo",
7188 	"thaisolar":    "ThaiSolar"
7189 };
7190 
7191 /**
7192  * Dynamically load the code for a calendar and calendar class if necessary.
7193  * @protected
7194  */
7195 DateFactory._dynLoadDate = function (name) {
7196 	if (!IDate._constructors[name]) {
7197 		var entry = DateFactory._dynMap[name];
7198 		if (entry) {
7199 			IDate._constructors[name] = require("./" + entry + "Date.js");
7200 		}
7201 	}
7202 	return IDate._constructors[name];
7203 };
7204 
7205 /** 
7206  * @protected
7207  * @static 
7208  */
7209 DateFactory._init = function(type, options) {
7210 	var cons;
7211 	
7212 	if (ilib.isDynCode()) {
7213 		DateFactory._dynLoadDate(type);
7214 		CalendarFactory._dynLoadCalendar(type);
7215 	}
7216 	
7217 	cons = IDate._constructors[type];
7218 	
7219 	// pass the same options through to the constructor so the subclass
7220 	// has the ability to do something with if it needs to
7221 	return cons && new cons(options);
7222 };
7223 
7224 /**
7225  * Convert JavaScript Date objects and other types into native Dates. This accepts any
7226  * string or number that can be translated by the JavaScript Date class,
7227  * (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
7228  * any JavaScript Date classed object, any IDate subclass, an JulianDay object, an object
7229  * containing the normal options to initialize an IDate instance, or null (will 
7230  * return null or undefined if input is null or undefined). Normal output is 
7231  * a standard native subclass of the IDate object as appropriate for the locale.
7232  * 
7233  * @static
7234  * @protected
7235  * @param {IDate|Object|JulianDay|Date|string|number=} inDate The input date object, string or Number.
7236  * @param {IString|string=} timezone timezone to use if a new date object is created
7237  * @param {Locale|string=} locale locale to use when constructing an IDate
7238  * @return {IDate|null|undefined} an IDate subclass equivalent to the given inDate
7239  */
7240 DateFactory._dateToIlib = function(inDate, timezone, locale) {
7241 	if (typeof(inDate) === 'undefined' || inDate === null) {
7242 		return inDate;
7243 	}
7244 	if (inDate instanceof IDate) {
7245 		return inDate;
7246 	}
7247 	if (JSUtils.isDate(inDate)) {
7248 		return DateFactory({
7249 			unixtime: inDate.getTime(),
7250 			timezone: timezone,
7251 			locale: locale
7252 		});
7253 	}
7254 	if (inDate instanceof JulianDay) {
7255 		return DateFactory({
7256 			jd: inDate,
7257 			timezone: timezone,
7258 			locale: locale
7259 		});
7260 	}
7261 	if (typeof(inDate) === 'number') {
7262 		return DateFactory({
7263 			unixtime: inDate,
7264 			timezone: timezone,
7265 			locale: locale
7266 		});
7267 	}
7268 	if (typeof(inDate) === 'object') {
7269 		return DateFactory(inDate);
7270 	}
7271 	if (typeof(inDate) === 'string') {
7272 		inDate = new Date(inDate);
7273 	}
7274 	return DateFactory({
7275 		unixtime: inDate.getTime(),
7276 		timezone: timezone,
7277 		locale: locale
7278 	});
7279 };
7280 
7281 
7282 /*< ResBundle.js */
7283 /*
7284  * ResBundle.js - Resource bundle definition
7285  * 
7286  * Copyright © 2012-2015, JEDLSoft
7287  *
7288  * Licensed under the Apache License, Version 2.0 (the "License");
7289  * you may not use this file except in compliance with the License.
7290  * You may obtain a copy of the License at
7291  *
7292  *     http://www.apache.org/licenses/LICENSE-2.0
7293  *
7294  * Unless required by applicable law or agreed to in writing, software
7295  * distributed under the License is distributed on an "AS IS" BASIS,
7296  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7297  *
7298  * See the License for the specific language governing permissions and
7299  * limitations under the License.
7300  */
7301 
7302 // !depends ilib.js Locale.js LocaleInfo.js IString.js Utils.js JSUtils.js
7303 
7304 // !data pseudomap
7305 
7306 
7307 
7308 
7309 /**
7310  * @class
7311  * Create a new resource bundle instance. The resource bundle loads strings
7312  * appropriate for a particular locale and provides them via the getString 
7313  * method.<p>
7314  * 
7315  * The options object may contain any (or none) of the following properties:
7316  * 
7317  * <ul>
7318  * <li><i>locale</i> - The locale of the strings to load. If not specified, the default
7319  * locale is the the default for the web page or app in which the bundle is 
7320  * being loaded.
7321  * 
7322  * <li><i>name</i> - Base name of the resource bundle to load. If not specified the default
7323  * base name is "resources".
7324  * 
7325  * <li><i>type</i> - Name the type of strings this bundle contains. Valid values are 
7326  * "xml", "html", "text", or "raw". The default is "text". If the type is "xml" or "html",
7327  * then XML/HTML entities and tags are not pseudo-translated. During a real translation, 
7328  * HTML character entities are translated to their corresponding characters in a source
7329  * string before looking that string up in the translations. Also, the characters "<", ">",
7330  * and "&" are converted to entities again in the output, but characters are left as they
7331  * are. If the type is "xml", "html", or "text" types, then the replacement parameter names
7332  * are not pseudo-translated as well so that the output can be used for formatting with 
7333  * the IString class. If the type is raw, all characters are pseudo-translated, 
7334  * including replacement parameters as well as XML/HTML tags and entities.
7335  * 
7336  * <li><i>lengthen</i> - when pseudo-translating the string, tell whether or not to 
7337  * automatically lengthen the string to simulate "long" languages such as German
7338  * or French. This is a boolean value. Default is false.
7339  * 
7340  * <li><i>missing</i> - what to do when a resource is missing. The choices are:
7341  * <ul>
7342  *   <li><i>source</i> - return the source string unchanged
7343  *   <li><i>pseudo</i> - return the pseudo-translated source string, translated to the
7344  *   script of the locale if the mapping is available, or just the default Latin 
7345  *   pseudo-translation if not
7346  *   <li><i>empty</i> - return the empty string 
7347  * </ul>
7348  * The default behaviour is the same as before, which is to return the source string
7349  * unchanged.
7350  * 
7351  * <li><i>onLoad</i> - a callback function to call when the resources are fully 
7352  * loaded. When the onLoad option is given, this class will attempt to
7353  * load any missing locale data using the ilib loader callback.
7354  * When the constructor is done (even if the data is already preassembled), the 
7355  * onLoad function is called with the current instance as a parameter, so this
7356  * callback can be used with preassembled or dynamic loading or a mix of the two. 
7357  * 
7358  * <li>sync - tell whether to load any missing locale data synchronously or 
7359  * asynchronously. If this option is given as "false", then the "onLoad"
7360  * callback must be given, as the instance returned from this constructor will
7361  * not be usable for a while. 
7362  *
7363  * <li><i>loadParams</i> - an object containing parameters to pass to the 
7364  * loader callback function when locale data is missing. The parameters are not
7365  * interpretted or modified in any way. They are simply passed along. The object 
7366  * may contain any property/value pairs as long as the calling code is in
7367  * agreement with the loader callback function as to what those parameters mean.
7368  * </ul>
7369  * 
7370  * The locale option may be given as a locale spec string or as an 
7371  * Locale object. If the locale option is not specified, then strings for
7372  * the default locale will be loaded.<p> 
7373  * 
7374  * The name option can be used to put groups of strings together in a
7375  * single bundle. The strings will then appear together in a JS object in
7376  * a JS file that can be included before the ilib.<p>
7377  * 
7378  * A resource bundle with a particular name is actually a set of bundles
7379  * that are each specific to a language, a language plus a region, etc. 
7380  * All bundles with the same base name should
7381  * contain the same set of source strings, but with different translations for 
7382  * the given locale. The user of the bundle does not need to be aware of 
7383  * the locale of the bundle, as long as it contains values for the strings 
7384  * it needs.<p>
7385  * 
7386  * Strings in bundles for a particular locale are inherited from parent bundles
7387  * that are more generic. In general, the hierarchy is as follows (from 
7388  * least locale-specific to most locale-specific):
7389  * 
7390  * <ol>
7391  * <li> language
7392  * <li> region
7393  * <li> language_script
7394  * <li> language_region
7395  * <li> region_variant
7396  * <li> language_script_region
7397  * <li> language_region_variant
7398  * <li> language_script_region_variant
7399  * </ol>
7400  * 
7401  * That is, if the translation for a string does not exist in the current
7402  * locale, the more-generic parent locale is searched for the string. In the
7403  * worst case scenario, the string is not found in the base locale's strings. 
7404  * In this case, the missing option guides this class on what to do. If
7405  * the missing option is "source", then the original source is returned as 
7406  * the translation. If it is "empty", the empty string is returned. If it
7407  * is "pseudo", then the pseudo-translated string that is appropriate for
7408  * the default script of the locale is returned.<p> 
7409  * 
7410  * This allows developers to create code with new or changed strings in it and check in that
7411  * code without waiting for the translations to be done first. The translated
7412  * version of the app or web site will still function properly, but will show 
7413  * a spurious untranslated string here and there until the translations are 
7414  * done and also checked in.<p>   
7415  *  
7416  * The base is whatever language your developers use to code in. For
7417  * a German web site, strings in the source code may be written in German 
7418  * for example. Often this base is English, as many web sites are coded in
7419  * English, but that is not required.<p>
7420  * 
7421  * The strings can be extracted with the ilib localization tool (which will be
7422  * shipped at some future time.) Once the strings
7423  * have been translated, the set of translated files can be generated with the
7424  * same tool. The output from the tool can be used as input to the ResBundle
7425  * object. It is up to the web page or app to make sure the JS file that defines
7426  * the bundle is included before creating the ResBundle instance.<p>
7427  * 
7428  * A special locale "zxx-XX" is used as the pseudo-translation locale because
7429  * zxx means "no linguistic information" in the ISO 639 standard, and the region 
7430  * code XX is defined to be user-defined in the ISO 3166 standard. 
7431  * Pseudo-translation is a locale where the translations are generated on
7432  * the fly based on the contents of the source string. Characters in the source 
7433  * string are replaced with other characters and returned. 
7434  * 
7435  * Example. If the source string is:
7436  * 
7437  * <pre>
7438  * "This is a string"
7439  * </pre>
7440  * 
7441  * then the pseudo-translated version might look something like this: 
7442  * 
7443  * <pre>
7444  * "Ţħïş ïş á şţřïñĝ"
7445  * </pre>
7446  * <p>
7447  * 
7448  * Pseudo-translation can be used to test that your app or web site is translatable
7449  * before an actual translation has happened. These bugs can then be fixed 
7450  * before the translation starts, avoiding an explosion of bugs later when
7451  * each language's tester registers the same bug complaining that the same 
7452  * string is not translated. When pseudo-localizing with
7453  * the Latin script, this allows the strings to be readable in the UI in the 
7454  * source language (if somewhat funky-looking), 
7455  * so that a tester can easily verify that the string is properly externalized 
7456  * and loaded from a resource bundle without the need to be able to read a
7457  * foreign language.<p> 
7458  * 
7459  * If one of a list of script tags is given in the pseudo-locale specifier, then the
7460  * pseudo-localization can map characters to very rough transliterations of
7461  * characters in the given script. For example, zxx-Hebr-XX maps strings to
7462  * Hebrew characters, which can be used to test your UI in a right-to-left
7463  * language to catch bidi bugs before a translation is done. Currently, the
7464  * list of target scripts includes Hebrew (Hebr), Chinese Simplified Han (Hans),
7465  * and Cyrillic (Cyrl) with more to be added later. If no script is explicitly
7466  * specified in the locale spec, or if the script is not supported,
7467  * then the default mapping maps Latin base characters to accented versions of
7468  * those Latin characters as in the example above.
7469  *  
7470  * When the "lengthen" property is set to true in the options, the 
7471  * pseudotranslation code will add digits to the end of the string to simulate
7472  * the lengthening that occurs when translating to other languages. The above 
7473  * example will come out like this:
7474  * 
7475  * <pre>
7476  * "Ţħïş ïş á şţřïñĝ76543210"
7477  * </pre>
7478  * 
7479  * The string is lengthened according to the length of the source string. If
7480  * the source string is less than 20 characters long, the string is lengthened 
7481  * by 50%. If the source string is 20-40 
7482  * characters long, the string is lengthened by 33%. If te string is greater
7483  * than 40 characters long, the string is lengthened by 20%.<p>
7484  * 
7485  * The pseudotranslation always ends a string with the digit "0". If you do
7486  * not see the digit "0" in the UI for your app, you know that truncation
7487  * has occurred, and the number you see at the end of the string tells you 
7488  * how many characters were truncated.<p>
7489  * 
7490  * 
7491  * @constructor
7492  * @param {?Object} options Options controlling how the bundle is created
7493  */
7494 var ResBundle = function (options) {
7495 	var lookupLocale, spec;
7496 	
7497 	this.locale = new Locale();	// use the default locale
7498 	this.baseName = "strings";
7499 	this.type = "text";
7500 	this.loadParams = {};
7501 	this.missing = "source";
7502 	this.sync = true;
7503 	
7504 	if (options) {
7505 		if (options.locale) {
7506 			this.locale = (typeof(options.locale) === 'string') ? 
7507 					new Locale(options.locale) :
7508 					options.locale;
7509 		}
7510 		if (options.name) {
7511 			this.baseName = options.name;
7512 		}
7513 		if (options.type) {
7514 			this.type = options.type;
7515 		}
7516 		this.lengthen = options.lengthen || false;
7517 		
7518 		if (typeof(options.sync) !== 'undefined') {
7519 			this.sync = (options.sync == true);
7520 		}
7521 		
7522 		if (typeof(options.loadParams) !== 'undefined') {
7523 			this.loadParams = options.loadParams;
7524 		}
7525 		if (typeof(options.missing) !== 'undefined') {
7526 			if (options.missing === "pseudo" || options.missing === "empty") {
7527 				this.missing = options.missing;
7528 			}
7529 		}
7530 	} else {
7531 		options = {};
7532 	}
7533 	
7534 	this.map = {};
7535 
7536 	if (!ResBundle[this.baseName]) {
7537 		ResBundle[this.baseName] = {};
7538 	}
7539 
7540 	lookupLocale = this.locale.isPseudo() ? new Locale("en-US") : this.locale;
7541 
7542 	Utils.loadData({
7543 		object: ResBundle[this.baseName], 
7544 		locale: lookupLocale, 
7545 		name: this.baseName + ".json", 
7546 		sync: this.sync, 
7547 		loadParams: this.loadParams, 
7548 		callback: ilib.bind(this, function (map) {
7549 			if (!map) {
7550 				map = ilib.data[this.baseName] || {};
7551 				spec = lookupLocale.getSpec().replace(/-/g, '_');
7552 				ResBundle[this.baseName].cache[spec] = map;
7553 			}
7554 			this.map = map;
7555 			if (this.locale.isPseudo()) {
7556 				if (!ResBundle.pseudomap) {
7557 					ResBundle.pseudomap = {};
7558 				}
7559 	
7560 				this._loadPseudo(this.locale, options.onLoad);
7561 			} else if (this.missing === "pseudo") {
7562 				if (!ResBundle.pseudomap) {
7563 					ResBundle.pseudomap = {};
7564 				}
7565 	
7566 				new LocaleInfo(this.locale, {
7567 					sync: this.sync,
7568 					loadParams: this.loadParams,
7569 					onLoad: ilib.bind(this, function (li) {
7570 						var pseudoLocale = new Locale("zxx", "XX", undefined, li.getDefaultScript());
7571 						this._loadPseudo(pseudoLocale, options.onLoad);
7572 					})
7573 				});
7574 			} else {
7575 				if (typeof(options.onLoad) === 'function') {
7576 					options.onLoad(this);
7577 				}
7578 			}
7579 		})
7580 	});
7581 
7582 	// console.log("Merged resources " + this.locale.toString() + " are: " + JSON.stringify(this.map));
7583 	//if (!this.locale.isPseudo() && JSUtils.isEmpty(this.map)) {
7584 	//	console.log("Resources for bundle " + this.baseName + " locale " + this.locale.toString() + " are not available.");
7585 	//}
7586 };
7587 
7588 ResBundle.defaultPseudo = ilib.data.pseudomap || {
7589 	"a": "à",
7590 	"e": "ë",
7591 	"i": "í",
7592 	"o": "õ",
7593 	"u": "ü",
7594 	"y": "ÿ",
7595 	"A": "Ã",
7596 	"E": "Ë",
7597 	"I": "Ï",
7598 	"O": "Ø",
7599 	"U": "Ú",
7600 	"Y": "Ŷ"
7601 };
7602 
7603 ResBundle.prototype = {
7604     /**
7605      * @protected
7606      */
7607     _loadPseudo: function (pseudoLocale, onLoad) {
7608 		Utils.loadData({
7609 			object: ResBundle.pseudomap, 
7610 			locale: pseudoLocale, 
7611 			name: "pseudomap.json", 
7612 			sync: this.sync, 
7613 			loadParams: this.loadParams, 
7614 			callback: ilib.bind(this, function (map) {
7615 				if (!map || JSUtils.isEmpty(map)) {
7616 					map = ResBundle.defaultPseudo;
7617 					var spec = pseudoLocale.getSpec().replace(/-/g, '_');
7618 					ResBundle.pseudomap.cache[spec] = map;
7619 				}
7620 				this.pseudomap = map;
7621 				if (typeof(onLoad) === 'function') {
7622 					onLoad(this);
7623 				}	
7624 			})
7625 		});
7626     },
7627     
7628 	/**
7629 	 * Return the locale of this resource bundle.
7630 	 * @return {Locale} the locale of this resource bundle object 
7631 	 */
7632 	getLocale: function () {
7633 		return this.locale;
7634 	},
7635 	
7636 	/**
7637 	 * Return the name of this resource bundle. This corresponds to the name option
7638 	 * given to the constructor.
7639 	 * @return {string} name of the the current instance
7640 	 */
7641 	getName: function () {
7642 		return this.baseName;
7643 	},
7644 	
7645 	/**
7646 	 * Return the type of this resource bundle. This corresponds to the type option
7647 	 * given to the constructor.
7648 	 * @return {string} type of the the current instance
7649 	 */
7650 	getType: function () {
7651 		return this.type;
7652 	},
7653 
7654 	/*
7655 	 * @private
7656 	 * Pseudo-translate a string
7657 	 */
7658 	pseudo: function (str) {
7659 		if (!str) {
7660 			return undefined;
7661 		}
7662 		var ret = "", i;
7663 		for (i = 0; i < str.length; i++) {
7664 			if (this.type !== "raw") {
7665 				if (this.type === "html" || this.type === "xml") {
7666 					if (str.charAt(i) === '<') {
7667 						ret += str.charAt(i++);
7668 						while (i < str.length && str.charAt(i) !== '>') {
7669 							ret += str.charAt(i++);
7670 						}
7671 						if (i < str.length) {
7672 							ret += str.charAt(i++);
7673 						}
7674 					} else if (str.charAt(i) === '&') {
7675 						ret += str.charAt(i++);
7676 						while (i < str.length && str.charAt(i) !== ';' && str.charAt(i) !== ' ') {
7677 							ret += str.charAt(i++);
7678 						}
7679 						if (i < str.length) {
7680 							ret += str.charAt(i++);
7681 						}
7682 					}
7683 				}
7684 				if (i < str.length) { 
7685 					if (str.charAt(i) === '{') {
7686 						ret += str.charAt(i++);
7687 						while (i < str.length && str.charAt(i) !== '}') {
7688 							ret += str.charAt(i++);
7689 						}
7690 						if (i < str.length) {
7691 							ret += str.charAt(i);
7692 						}
7693 					} else {
7694 						ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
7695 					}
7696 				}
7697 			} else {
7698 				ret += this.pseudomap[str.charAt(i)] || str.charAt(i);
7699 			}
7700 		}
7701 		if (this.lengthen) {
7702 			var add;
7703 			if (ret.length <= 20) {
7704 				add = Math.round(ret.length / 2);
7705 			} else if (ret.length > 20 && ret.length <= 40) {
7706 				add = Math.round(ret.length / 3);
7707 			} else {
7708 				add = Math.round(ret.length / 5);
7709 			}
7710 			for (i = add-1; i >= 0; i--) {
7711 				ret += (i % 10);
7712 			}
7713 		}
7714 		if (this.locale.getScript() === "Hans" || this.locale.getScript() === "Hant" ||
7715 				this.locale.getScript() === "Hani" ||
7716 				this.locale.getScript() === "Hrkt" || this.locale.getScript() === "Jpan" ||
7717 				this.locale.getScript() === "Hira" || this.locale.getScript() === "Kana" ) {
7718 			// simulate Asian languages by getting rid of all the spaces
7719 			ret = ret.replace(/ /g, "");
7720 		}
7721 		return ret;
7722 	},
7723 	
7724 	/*
7725 	 * @private
7726 	 * Escape html characters in the output.
7727 	 */
7728 	escapeXml: function (str) {
7729 		str = str.replace(/&/g, '&');
7730 		str = str.replace(/</g, '<');
7731 		str = str.replace(/>/g, '>');
7732 		return str;
7733 	},
7734 
7735 	/*
7736 	 * @private
7737 	 * @param {string} str the string to unescape
7738 	 */
7739 	unescapeXml: function (str) {
7740 		str = str.replace(/&/g, '&');
7741 		str = str.replace(/</g, '<');
7742 		str = str.replace(/>/g, '>');
7743 		return str;
7744 	},
7745 	
7746 	/*
7747 	 * @private
7748 	 * Create a key name out of a source string. All this does so far is 
7749 	 * compress sequences of white space into a single space on the assumption
7750 	 * that this doesn't really change the meaning of the string, and therefore
7751 	 * all such strings that compress to the same thing should share the same
7752 	 * translation.
7753 	 * @param {string} source the source string to make a key out of
7754 	 */
7755 	makeKey: function (source) {
7756 		var key = source.replace(/\s+/gm, ' ');
7757 		return (this.type === "xml" || this.type === "html") ? this.unescapeXml(key) : key;
7758 	},
7759 	
7760 	/**
7761 	 * Return a localized string. If the string is not found in the loaded set of
7762 	 * resources, the original source string is returned. If the key is not given,
7763 	 * then the source string itself is used as the key. In the case where the 
7764 	 * source string is used as the key, the whitespace is compressed down to 1 space
7765 	 * each, and the whitespace at the beginning and end of the string is trimmed.<p>
7766 	 * 
7767 	 * The escape mode specifies what type of output you are escaping the returned
7768 	 * string for. Modes are similar to the types: 
7769 	 * 
7770 	 * <ul>
7771 	 * <li>"html" -- prevents HTML injection by escaping the characters < > and &
7772 	 * <li>"xml" -- currently same as "html" mode
7773 	 * <li>"js" -- prevents breaking Javascript syntax by backslash escaping all quote and 
7774 	 * double-quote characters
7775 	 * <li>"attribute" -- meant for HTML attribute values. Currently this is the same as
7776 	 * "js" escape mode.
7777 	 * <li>"default" -- use the type parameter from the constructor as the escape mode as well
7778 	 * <li>"none" or undefined -- no escaping at all.
7779 	 * </ul>
7780 	 * 
7781 	 * The type parameter of the constructor specifies what type of strings this bundle
7782 	 * is operating upon. This allows pseudo-translation and automatic key generation
7783 	 * to happen properly by telling this class how to parse the string. The escape mode 
7784 	 * for this method is different in that it specifies how this string will be used in 
7785 	 * the calling code and therefore how to escape it properly.<p> 
7786 	 * 
7787 	 * For example, a section of Javascript code may be constructing an HTML snippet in a 
7788 	 * string to add to the web page. In this case, the type parameter in the constructor should
7789 	 * be "html" so that the source string can be parsed properly, but the escape mode should
7790 	 * be "js" so that the output string can be used in Javascript without causing syntax
7791 	 * errors.
7792 	 * 
7793 	 * @param {?string=} source the source string to translate
7794 	 * @param {?string=} key optional name of the key, if any
7795 	 * @param {?string=} escapeMode escape mode, if any
7796 	 * @return {IString|undefined} the translation of the given source/key or undefined 
7797 	 * if the translation is not found and the source is undefined 
7798 	 */
7799 	getString: function (source, key, escapeMode) {
7800 		if (!source && !key) return new IString("");
7801 
7802 		var trans;
7803 		if (this.locale.isPseudo()) {
7804 			var str = source ? source : this.map[key];
7805 			trans = this.pseudo(str || key);
7806 		} else {
7807 			var keyName = key || this.makeKey(source);
7808 			if (typeof(this.map[keyName]) !== 'undefined') {
7809 				trans = this.map[keyName];
7810 			} else if (this.missing === "pseudo") {
7811 				trans = this.pseudo(source || key);
7812 			} else if (this.missing === "empty") {
7813 				trans = "";
7814 			} else {
7815 				trans = source;
7816 			}
7817 		}
7818 
7819 		if (escapeMode && escapeMode !== "none") {
7820 			if (escapeMode == "default") {
7821 				escapeMode = this.type;
7822 			}
7823 			if (escapeMode === "xml" || escapeMode === "html") {
7824 				trans = this.escapeXml(trans);
7825 			} else if (escapeMode == "js" || escapeMode === "attribute") {
7826 				trans = trans.replace(/'/g, "\\\'").replace(/"/g, "\\\"");
7827 			}
7828 		}
7829 		if (trans === undefined) {
7830 			return undefined;
7831 		} else {
7832 			var ret = new IString(trans);
7833 			ret.setLocale(this.locale.getSpec(), true, this.loadParams); // no callback
7834 			return ret;
7835 		}
7836 	},
7837 	
7838 	/**
7839 	 * Return a localized string as a Javascript object. This does the same thing as
7840 	 * the getString() method, but it returns a regular Javascript string instead of
7841 	 * and IString instance. This means it cannot be formatted with the format()
7842 	 * method without being wrapped in an IString instance first.
7843 	 * 
7844 	 * @param {?string=} source the source string to translate
7845 	 * @param {?string=} key optional name of the key, if any
7846 	 * @param {?string=} escapeMode escape mode, if any
7847 	 * @return {string|undefined} the translation of the given source/key or undefined 
7848 	 * if the translation is not found and the source is undefined
7849 	 */
7850 	getStringJS: function(source, key, escapeMode) {
7851 		return this.getString(source, key, escapeMode).toString();
7852 	},
7853 	
7854 	/**
7855 	 * Return true if the current bundle contains a translation for the given key and
7856 	 * source. The
7857 	 * getString method will always return a string for any given key and source 
7858 	 * combination, so it cannot be used to tell if a translation exists. Either one
7859 	 * or both of the source and key must be specified. If both are not specified,
7860 	 * this method will return false.
7861 	 * 
7862 	 * @param {?string=} source source string to look up
7863 	 * @param {?string=} key key to look up
7864 	 * @return {boolean} true if this bundle contains a translation for the key, and 
7865 	 * false otherwise
7866 	 */
7867 	containsKey: function(source, key) {
7868 		if (typeof(source) === 'undefined' && typeof(key) === 'undefined') {
7869 			return false;
7870 		}
7871 		
7872 		var keyName = key || this.makeKey(source);
7873 		return typeof(this.map[keyName]) !== 'undefined';
7874 	},
7875 	
7876 	/**
7877 	 * Return the merged resources as an entire object. When loading resources for a
7878 	 * locale that are not just a set of translated strings, but instead an entire 
7879 	 * structured javascript object, you can gain access to that object via this call. This method
7880 	 * will ensure that all the of the parts of the object are correct for the locale.<p>
7881 	 * 
7882 	 * For pre-assembled data, it starts by loading <i>ilib.data[name]</i>, where 
7883 	 * <i>name</i> is the base name for this set of resources. Then, it successively 
7884 	 * merges objects in the base data using progressively more locale-specific data. 
7885 	 * It loads it in this order from <i>ilib.data</i>:
7886 	 * 
7887 	 * <ol>
7888 	 * <li> language
7889 	 * <li> region
7890 	 * <li> language_script
7891 	 * <li> language_region
7892 	 * <li> region_variant
7893 	 * <li> language_script_region
7894 	 * <li> language_region_variant
7895 	 * <li> language_script_region_variant
7896 	 * </ol>
7897 	 * 
7898 	 * For dynamically loaded data, the code attempts to load the same sequence as
7899 	 * above, but with slash path separators instead of underscores.<p>
7900 	 *  
7901 	 * Loading the resources this way allows the program to share resources between all
7902 	 * locales that share a common language, region, or script. As a 
7903 	 * general rule-of-thumb, resources should be as generic as possible in order to
7904 	 * cover as many locales as possible.
7905 	 * 
7906 	 * @return {Object} returns the object that is the basis for this resources instance
7907 	 */
7908 	getResObj: function () {
7909 		return this.map;
7910 	}
7911 };
7912 
7913 
7914 /*< DateFmt.js */
7915 /*
7916  * DateFmt.js - Date formatter definition
7917  * 
7918  * Copyright © 2012-2015, JEDLSoft
7919  *
7920  * Licensed under the Apache License, Version 2.0 (the "License");
7921  * you may not use this file except in compliance with the License.
7922  * You may obtain a copy of the License at
7923  *
7924  *     http://www.apache.org/licenses/LICENSE-2.0
7925  *
7926  * Unless required by applicable law or agreed to in writing, software
7927  * distributed under the License is distributed on an "AS IS" BASIS,
7928  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7929  *
7930  * See the License for the specific language governing permissions and
7931  * limitations under the License.
7932  */
7933 
7934 /*
7935 !depends 
7936 ilib.js 
7937 Locale.js 
7938 IDate.js
7939 DateFactory.js  
7940 IString.js 
7941 ResBundle.js 
7942 Calendar.js
7943 CalendarFactory.js
7944 LocaleInfo.js
7945 TimeZone.js
7946 GregorianCal.js
7947 JSUtils.js
7948 Utils.js
7949 */
7950 
7951 // !data dateformats sysres
7952 
7953 
7954 
7955 
7956 
7957 /**
7958  * @class
7959  * Create a new date formatter instance. The date formatter is immutable once
7960  * it is created, but can format as many different dates as needed with the same
7961  * options. Create different date formatter instances for different purposes
7962  * and then keep them cached for use later if you have more than one date to
7963  * format.<p>
7964  * 
7965  * The options may contain any of the following properties:
7966  * 
7967  * <ul>
7968  * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
7969  * not specified, then the default locale of the app or web page will be used.
7970  * 
7971  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
7972  * be a sting containing the name of the calendar. Currently, the supported
7973  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
7974  * calendar is not specified, then the default calendar for the locale is used. When the
7975  * calendar type is specified, then the format method must be called with an instance of
7976  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
7977  * be called with a GregDate instance.)
7978  *  
7979  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
7980  * instance or a time zone specifier from the IANA list of time zone database names 
7981  * (eg. "America/Los_Angeles"), 
7982  * the string "local", or a string specifying the offset in RFC 822 format. The IANA
7983  * list of time zone names can be viewed at 
7984  * <a href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">this page</a>.
7985  * If the time zone is given as "local", the offset from UTC as given by
7986  * the Javascript system is used. If the offset is given as an RFC 822 style offset
7987  * specifier, it will parse that string and use the resulting offset. If the time zone
7988  * is not specified, the
7989  * default time zone for the locale is used. If both the date object and this formatter
7990  * instance contain time zones and those time zones are different from each other, the 
7991  * formatter will calculate the offset between the time zones and subtract it from the 
7992  * date before formatting the result for the current time zone. The theory is that a date
7993  * object that contains a time zone specifies a specific instant in time that is valid
7994  * around the world, whereas a date object without one is a local time and can only be
7995  * used for doing things in the local time zone of the user.
7996  * 
7997  * <li><i>type</i> - Specify whether this formatter should format times only, dates only, or
7998  * both times and dates together. Valid values are "time", "date", and "datetime". Note that
7999  * in some locales, the standard format uses the order "time followed by date" and in others, 
8000  * the order is exactly opposite, so it is better to create a single "datetime" formatter 
8001  * than it is to create a time formatter and a date formatter separately and concatenate the 
8002  * results. A "datetime" formatter will get the order correct for the locale.<p>
8003  * 
8004  * The default type if none is specified in with the type option is "date".
8005  * 
8006  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
8007  * formatted string.
8008  * 
8009  * <ul>
8010  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
8011  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
8012  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
8013  * components may still be abbreviated
8014  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
8015  * components are spelled out completely
8016  * </ul>
8017  * 
8018  * eg. The "short" format for an en_US date may be "MM/dd/yy", whereas the long format might be "d MMM, yyyy". In the long
8019  * format, the month name is textual instead of numeric and is longer, the year is 4 digits instead of 2, and the format 
8020  * contains slightly more spaces and formatting characters.<p>
8021  * 
8022  * Note that the length parameter does not specify which components are to be formatted. Use the "date" and the "time"
8023  * properties to specify the components. Also, very few of the components of a time format differ according to the length,
8024  * so this property has little to no affect on time formatting.
8025  * 
8026  * <li><i>date</i> - This property tells
8027  * which components of a date format to use. For example,
8028  * sometimes you may wish to format a date that only contains the month and date
8029  * without the year, such as when displaying a person's yearly birthday. The value
8030  * of this property allows you to specify only those components you want to see in the
8031  * final output, ordered correctly for the locale. <p>
8032  * 
8033  * Valid values are:
8034  * 
8035  * <ul>
8036  * <li><i>dmwy</i> - format all components, weekday, date, month, and year
8037  * <li><i>dmy</i> - format only date, month, and year
8038  * <li><i>dmw</i> - format only weekday, date, and month
8039  * <li><i>dm</i> - format only date and month
8040  * <li><i>my</i> - format only month and year
8041  * <li><i>dw</i> - format only the weekday and date
8042  * <li><i>d</i> - format only the date
8043  * <li><i>m</i> - format only the month, in numbers for shorter lengths, and letters for 
8044  * longer lengths
8045  * <li><i>n</i> - format only the month, in letters only for all lengths
8046  * <li><i>y</i> - format only the year
8047  * </ul>
8048  * Default components, if this property is not specified, is "dmy". This property may be specified
8049  * but has no affect if the current formatter is for times only.
8050  * 
8051  * <li><i>time</i> - This property gives which components of a time format to use. The time will be formatted 
8052  * correctly for the locale with only the time components requested. For example, a clock might only display 
8053  * the hour and minute and not need the seconds or the am/pm component. In this case, the time property should be set 
8054  * to "hm". <p>
8055  * 
8056  * Valid values for this property are:
8057  * 
8058  * <ul>
8059  * <li><i>ahmsz</i> - format the hours, minutes, seconds, am/pm (if using a 12 hour clock), and the time zone
8060  * <li><i>ahms</i> - format the hours, minutes, seconds, and am/pm (if using a 12 hour clock)
8061  * <li><i>hmsz</i> - format the hours, minutes, seconds, and the time zone
8062  * <li><i>hms</i> - format the hours, minutes, and seconds
8063  * <li><i>ahmz</i> - format the hours, minutes, am/pm (if using a 12 hour clock), and the time zone
8064  * <li><i>ahm</i> - format the hours, minutes, and am/pm (if using a 12 hour clock)
8065  * <li><i>hmz</i> - format the hours, minutes, and the time zone
8066  * <li><i>ah</i> - format only the hours and am/pm if using a 12 hour clock
8067  * <li><i>hm</i> - format only the hours and minutes
8068  * <li><i>ms</i> - format only the minutes and seconds
8069  * <li><i>h</i> - format only the hours
8070  * <li><i>m</i> - format only the minutes
8071  * <li><i>s</i> - format only the seconds
8072  * </ul>
8073  * 
8074  * If you want to format a length of time instead of a particular instant
8075  * in time, use the duration formatter object (DurationFmt) instead because this
8076  * formatter is geared towards instants. A date formatter will make sure that each component of the 
8077  * time is within the normal range
8078  * for that component. That is, the minutes will always be between 0 and 59, no matter
8079  * what is specified in the date to format. A duration format will allow the number
8080  * of minutes to exceed 59 if, for example, you were displaying the length of
8081  * a movie of 198 minutes.<p>
8082  * 
8083  * Default value if this property is not specified is "hma".
8084  * 
8085  * <li><i>clock</i> - specify that the time formatter should use a 12 or 24 hour clock. 
8086  * Valid values are "12" and "24".<p>
8087  * 
8088  * In some locales, both clocks are used. For example, in en_US, the general populace uses
8089  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
8090  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
8091  * construct a formatter that overrides the default for the locale.<p>
8092  * 
8093  * If this property is not specified, the default is to use the most widely used convention
8094  * for the locale.
8095  *  
8096  * <li><i>template</i> - use the given template string as a fixed format when formatting 
8097  * the date/time. Valid codes to use in a template string are as follows:
8098  * 
8099  * <ul>
8100  * <li><i>a</i> - am/pm marker
8101  * <li><i>d</i> - 1 or 2 digit date of month, not padded
8102  * <li><i>dd</i> - 1 or 2 digit date of month, 0 padded to 2 digits
8103  * <li><i>O</i> - ordinal representation of the date of month (eg. "1st", "2nd", etc.)
8104  * <li><i>D</i> - 1 to 3 digit day of year
8105  * <li><i>DD</i> - 1 to 3 digit day of year, 0 padded to 2 digits
8106  * <li><i>DDD</i> - 1 to 3 digit day of year, 0 padded to 3 digits
8107  * <li><i>M</i> - 1 or 2 digit month number, not padded
8108  * <li><i>MM</i> - 1 or 2 digit month number, 0 padded to 2 digits
8109  * <li><i>N</i> - 1 character month name abbreviation
8110  * <li><i>NN</i> - 2 character month name abbreviation
8111  * <li><i>MMM</i> - 3 character month month name abbreviation
8112  * <li><i>MMMM</i> - fully spelled out month name
8113  * <li><i>yy</i> - 2 digit year
8114  * <li><i>yyyy</i> - 4 digit year
8115  * <li><i>E</i> - day-of-week name, abbreviated to a single character
8116  * <li><i>EE</i> - day-of-week name, abbreviated to a max of 2 characters
8117  * <li><i>EEE</i> - day-of-week name, abbreviated to a max of 3 characters
8118  * <li><i>EEEE</i> - day-of-week name fully spelled out 
8119  * <li><i>G</i> - era designator
8120  * <li><i>w</i> - week number in year
8121  * <li><i>ww</i> - week number in year, 0 padded to 2 digits
8122  * <li><i>W</i> - week in month
8123  * <li><i>h</i> - hour (12 followed by 1 to 11)
8124  * <li><i>hh</i> - hour (12, followed by 1 to 11), 0 padded to 2 digits
8125  * <li><i>k</i> - hour (1 to 24)
8126  * <li><i>kk</i> - hour (1 to 24), 0 padded to 2 digits
8127  * <li><i>H</i> - hour (0 to 23)
8128  * <li><i>HH</i> - hour (0 to 23), 0 padded to 2 digits
8129  * <li><i>K</i> - hour (0 to 11)
8130  * <li><i>KK</i> - hour (0 to 11), 0 padded to 2 digits
8131  * <li><i>m</i> - minute in hour
8132  * <li><i>mm</i> - minute in hour, 0 padded to 2 digits
8133  * <li><i>s</i> - second in minute
8134  * <li><i>ss</i> - second in minute, 0 padded to 2 digits
8135  * <li><i>S</i> - millisecond (1 to 3 digits)
8136  * <li><i>SSS</i> - millisecond, 0 padded to 3 digits
8137  * <li><i>z</i> - general time zone
8138  * <li><i>Z</i> - RFC 822 time zone
8139  * </ul>
8140  * 
8141  * <li><i>useNative</i> - the flag used to determine whether to use the native script settings 
8142  * for formatting the numbers.
8143  *
8144  * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
8145  * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
8146  * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
8147  * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
8148  * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
8149  * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
8150  * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
8151  * when formatting dates in the Gregorian calendar.
8152  *
8153  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
8154  * loaded. When the onLoad option is given, the DateFmt object will attempt to
8155  * load any missing locale data using the ilib loader callback.
8156  * When the constructor is done (even if the data is already preassembled), the 
8157  * onLoad function is called with the current instance as a parameter, so this
8158  * callback can be used with preassembled or dynamic loading or a mix of the two.
8159  * 
8160  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
8161  * asynchronously. If this option is given as "false", then the "onLoad"
8162  * callback must be given, as the instance returned from this constructor will
8163  * not be usable for a while.
8164  *  
8165  * <li><i>loadParams</i> - an object containing parameters to pass to the 
8166  * loader callback function when locale data is missing. The parameters are not
8167  * interpretted or modified in any way. They are simply passed along. The object 
8168  * may contain any property/value pairs as long as the calling code is in
8169  * agreement with the loader callback function as to what those parameters mean.
8170  * </ul>
8171  * 
8172  * Any substring containing letters within single or double quotes will be used 
8173  * as-is in the final output and will not be interpretted for codes as above.<p>
8174  * 
8175  * Example: a date format in Spanish might be given as: "'El' d. 'de' MMMM", where
8176  * the 'El' and the 'de' are left as-is in the output because they are quoted. Typical 
8177  * output for this example template might be, "El 5. de Mayo".
8178  * 
8179  * The following options will be used when formatting a date/time with an explicit
8180  * template:
8181  * 
8182  * <ul>
8183  * <li>locale - the locale is only used for 
8184  * translations of things like month names or day-of-week names.
8185  * <li>calendar - used to translate a date instance into date/time component values 
8186  * that can be formatted into the template
8187  * <li>timezone - used to figure out the offset to add or subtract from the time to
8188  * get the final time component values
8189  * <li>clock - used to figure out whether to format times with a 12 or 24 hour clock.
8190  * If this option is specified, it will override the hours portion of a time format.
8191  * That is, "hh" is switched with "HH" and "kk" is switched with "KK" as appropriate. 
8192  * If this option is not specified, the 12/24 code in the template will dictate whether 
8193  * to use the 12 or 24 clock, and the 12/24 default in the locale will be ignored.
8194  * </ul>
8195  * 
8196  * All other options will be ignored and their corresponding getter methods will
8197  * return the empty string.<p>
8198  * 
8199  * 
8200  * @constructor
8201  * @param {Object} options options governing the way this date formatter instance works
8202  */
8203 var DateFmt = function(options) {
8204 	var arr, i, bad, 
8205 		sync = true, 
8206 		loadParams = undefined;
8207 	
8208 	this.locale = new Locale();
8209 	this.type = "date";
8210 	this.length = "s";
8211 	this.dateComponents = "dmy";
8212 	this.timeComponents = "ahm";
8213 	this.meridiems = "default";
8214 	
8215 	if (options) {
8216 		if (options.locale) {
8217 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
8218 		}
8219 		
8220 		if (options.type) {
8221 			if (options.type === 'date' || options.type === 'time' || options.type === 'datetime') {
8222 				this.type = options.type;
8223 			}
8224 		}
8225 		
8226 		if (options.calendar) {
8227 			this.calName = options.calendar;
8228 		}
8229 		
8230 		if (options.length) {
8231 			if (options.length === 'short' ||
8232 				options.length === 'medium' ||
8233 				options.length === 'long' ||
8234 				options.length === 'full') {
8235 				// only use the first char to save space in the json files
8236 				this.length = options.length.charAt(0);
8237 			}
8238 		}
8239 		
8240 		if (options.date) {
8241 			arr = options.date.split("");
8242 			arr.sort(function (left, right) {
8243 				return (left < right) ? -1 : ((right < left) ? 1 : 0);
8244 			});
8245 			bad = false;
8246 			for (i = 0; i < arr.length; i++) {
8247 				if (arr[i] !== 'd' && arr[i] !== 'm' && arr[i] !== 'y' && arr[i] !== 'w' && arr[i] !== 'n') {
8248 					bad = true;
8249 					break;
8250 				}
8251 			}
8252 			if (!bad) {
8253 				this.dateComponents = arr.join("");
8254 			}
8255 		}
8256 
8257 		if (options.time) {
8258 			arr = options.time.split("");
8259 			arr.sort(function (left, right) {
8260 				return (left < right) ? -1 : ((right < left) ? 1 : 0);
8261 			});
8262 			this.badTime = false;
8263 			for (i = 0; i < arr.length; i++) {
8264 				if (arr[i] !== 'h' && arr[i] !== 'm' && arr[i] !== 's' && arr[i] !== 'a' && arr[i] !== 'z') {
8265 					this.badTime = true;
8266 					break;
8267 				}
8268 			}
8269 			if (!this.badTime) {
8270 				this.timeComponents = arr.join("");
8271 			}
8272 		}
8273 		
8274 		if (options.clock && (options.clock === '12' || options.clock === '24')) {
8275 			this.clock = options.clock;
8276 		}
8277 		
8278 		if (options.template) {
8279 			// many options are not useful when specifying the template directly, so zero
8280 			// them out.
8281 			this.type = "";
8282 			this.length = "";
8283 			this.dateComponents = "";
8284 			this.timeComponents = "";
8285 			
8286 			this.template = options.template;
8287 		}
8288 		
8289 		if (options.timezone) {
8290 			if (options.timezone instanceof TimeZone) {
8291 				this.tz = options.timezone;
8292 			} else {
8293 				this.tz = new TimeZone({
8294 					locale: this.locale, 
8295 					id: options.timezone
8296 				});
8297 			}
8298 		} else if (options.locale) {
8299 			// if an explicit locale was given, then get the time zone for that locale
8300 			this.tz = new TimeZone({
8301 				locale: this.locale
8302 			});
8303 		} // else just assume time zone "local"
8304 		
8305 		if (typeof(options.useNative) === 'boolean') {
8306 			this.useNative = options.useNative;
8307 		}
8308 		
8309 		if (typeof(options.meridiems) !== 'undefined' && 
8310 				(options.meridiems === "chinese" || 
8311 				 options.meridiems === "gregorian" || 
8312 				 options.meridiems === "ethiopic")) {
8313 			this.meridiems = options.meridiems;
8314 		}
8315 		
8316 		if (typeof(options.sync) !== 'undefined') {
8317 			sync = (options.sync === true);
8318 		}
8319 		
8320 		loadParams = options.loadParams;
8321 	}
8322 
8323 	if (!DateFmt.cache) {
8324 		DateFmt.cache = {};
8325 	}
8326 
8327 	new LocaleInfo(this.locale, {
8328 		sync: sync,
8329 		loadParams: loadParams, 
8330 		onLoad: ilib.bind(this, function (li) {
8331 			this.locinfo = li;
8332 			
8333 			// get the default calendar name from the locale, and if the locale doesn't define
8334 			// one, use the hard-coded gregorian as the last resort
8335 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
8336 			if (ilib.isDynCode()) {
8337 				// If we are running in the dynamic code loading assembly of ilib, the following
8338 				// will attempt to dynamically load the calendar date class for this calendar. If 
8339 				// it doesn't work, this just goes on and it will use Gregorian instead.
8340 				DateFactory._dynLoadDate(this.calName);
8341 			}
8342 			
8343 			this.cal = CalendarFactory({
8344 				type: this.calName
8345 			});
8346 			if (!this.cal) {
8347 				this.cal = new GregorianCal();
8348 			}
8349 			if (this.meridiems === "default") {
8350 				this.meridiems = li.getMeridiemsStyle();
8351 			}
8352 
8353 			/*
8354 			if (this.timeComponents &&
8355 					(this.clock === '24' || 
8356 					(!this.clock && this.locinfo.getClock() === "24"))) {
8357 				// make sure we don't have am/pm in 24 hour mode unless the user specifically
8358 				// requested it in the time component option
8359 				this.timeComponents = this.timeComponents.replace("a", "");
8360 			}
8361 			*/
8362 
8363 			// load the strings used to translate the components
8364 			new ResBundle({
8365 				locale: this.locale,
8366 				name: "sysres",
8367 				sync: sync,
8368 				loadParams: loadParams, 
8369 				onLoad: ilib.bind(this, function (rb) {
8370 					this.sysres = rb;
8371 					
8372 					if (!this.template) {
8373 						Utils.loadData({
8374 							object: DateFmt, 
8375 							locale: this.locale, 
8376 							name: "dateformats.json", 
8377 							sync: sync, 
8378 							loadParams: loadParams, 
8379 							callback: ilib.bind(this, function (formats) {
8380 								if (!formats) {
8381 									formats = ilib.data.dateformats || DateFmt.defaultFmt;
8382 									var spec = this.locale.getSpec().replace(/-/g, '_');
8383 									DateFmt.cache[spec] = formats;
8384 								}
8385 								if (typeof(this.clock) === 'undefined') {
8386 									// default to the locale instead
8387 									this.clock = this.locinfo.getClock();
8388 								}
8389 								this._initTemplate(formats);
8390 								this._massageTemplate();
8391 								if (options && typeof(options.onLoad) === 'function') {
8392 									options.onLoad(this);
8393 								}
8394 							})
8395 						});
8396 					} else {
8397 						this._massageTemplate();
8398 						if (options && typeof(options.onLoad) === 'function') {
8399 							options.onLoad(this);
8400 						}
8401 					}
8402 				})
8403 			});	
8404 		})
8405 	});
8406 };
8407 
8408 // used in getLength
8409 DateFmt.lenmap = {
8410 	"s": "short",
8411 	"m": "medium",
8412 	"l": "long",
8413 	"f": "full"
8414 };
8415 
8416 DateFmt.zeros = "0000";
8417 
8418 DateFmt.defaultFmt = {
8419 	"gregorian": {
8420 		"order": "{date} {time}",
8421 		"date": {
8422 			"dmwy": "EEE d/MM/yyyy",
8423 			"dmy": "d/MM/yyyy",
8424 			"dmw": "EEE d/MM",
8425 			"dm": "d/MM",
8426 			"my": "MM/yyyy",
8427 			"dw": "EEE d",
8428 			"d": "dd",
8429 			"m": "MM",
8430 			"y": "yyyy",
8431 			"n": "NN",
8432 			"w": "EEE"
8433 		},
8434 		"time": {
8435 			"12": "h:mm:ssa",
8436 			"24": "H:mm:ss"
8437 		},
8438 		"range": {
8439 			"c00": "{st} - {et}, {sd}/{sm}/{sy}",
8440 			"c01": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
8441 			"c02": "{sd}/{sm} {st} - {ed}/{em} {et}, {sy}",
8442 			"c03": "{sd}/{sm}/{sy} {st} - {ed}/{em}/{ey} {et}",
8443 			"c10": "{sd}-{ed}/{sm}/{sy}",
8444 			"c11": "{sd}/{sm} - {ed}/{em} {sy}",
8445 			"c12": "{sd}/{sm}/{sy} - {ed}/{em}/{ey}",
8446 			"c20": "{sm}/{sy} - {em}/{ey}",
8447 			"c30": "{sy} - {ey}"
8448 		}
8449 	},
8450 	"islamic": "gregorian",
8451 	"hebrew": "gregorian",
8452 	"julian": "gregorian",
8453 	"buddhist": "gregorian",
8454 	"persian": "gregorian",
8455 	"persian-algo": "gregorian",
8456 	"han": "gregorian"
8457 };
8458 
8459 /**
8460 * @static
8461 * @private
8462 */
8463 DateFmt.monthNameLenMap = {
8464 	"short" : "N",
8465 	"medium": "NN",
8466 	"long":   "MMM",
8467 	"full":   "MMMM"
8468 };
8469 
8470 /**
8471 * @static
8472 * @private
8473 */
8474 DateFmt.weekDayLenMap = {
8475 	"short" : "E",
8476 	"medium": "EE",
8477 	"long":   "EEE",
8478 	"full":   "EEEE"
8479 };
8480 
8481 /**
8482  * Return the range of possible meridiems (times of day like "AM" or 
8483  * "PM") in this date formatter.<p>
8484  *
8485  * The options may contain any of the following properties:
8486  *
8487  * <ul>
8488  * <li><i>locale</i> - locale to use when formatting the date/time. If the locale is
8489  * not specified, then the default locale of the app or web page will be used.
8490  * 
8491  * <li><i>meridiems</i> - string that specifies what style of meridiems to use with this 
8492  * format. The choices are "default", "gregorian", "ethiopic", and "chinese". The "default" 
8493  * style is often the simple Gregorian AM/PM, but the actual style is chosen by the locale. 
8494  * (For almost all locales, the Gregorian AM/PM style is most frequently used.)
8495  * The "ethiopic" style uses 5 different meridiems for "morning", "noon", "afternoon", 
8496  * "evening", and "night". The "chinese" style uses 7 different meridiems corresponding 
8497  * to the various parts of the day. N.B. Even for the Chinese locales, the default is "gregorian"
8498  * when formatting dates in the Gregorian calendar.
8499  * </ul>
8500  *
8501  * @static
8502  * @public
8503  * @param {Object} options options governing the way this date formatter instance works for getting meridiems range
8504  * @return {Array.<{name:string,start:string,end:string}>}
8505  */
8506 DateFmt.getMeridiemsRange = function (options) {
8507 	options = options || {};
8508 	var args = {};
8509 	if (options.locale) {
8510 		args.locale = options.locale;
8511 	}
8512 
8513 	if (options.meridiems) {
8514 		args.meridiems = options.meridiems;
8515 	}
8516 
8517 	var fmt = new DateFmt(args);
8518 
8519 	return fmt.getMeridiemsRange();
8520 };
8521 
8522 DateFmt.prototype = {
8523 	/**
8524 	 * @protected
8525 	 */
8526 	_initTemplate: function (formats) {
8527 		if (formats[this.calName]) {
8528 			/** 
8529 			 * @private
8530 			 * @type {{order:(string|{s:string,m:string,l:string,f:string}),date:Object.<string, (string|{s:string,m:string,l:string,f:string})>,time:Object.<string,(string|{s:string,m:string,l:string,f:string})>,range:Object.<string, (string|{s:string,m:string,l:string,f:string})>}}
8531 			 */
8532 			this.formats = formats[this.calName];
8533 			if (typeof(this.formats) === "string") {
8534 				// alias to another calendar type
8535 				this.formats = formats[this.formats];
8536 			}
8537 			
8538 			this.template = "";
8539 			
8540 			switch (this.type) {
8541 				case "datetime":
8542 					this.template = (this.formats && this._getLengthFormat(this.formats.order, this.length)) || "{date} {time}";
8543 					this.template = this.template.replace("{date}", this._getFormat(this.formats.date, this.dateComponents, this.length) || "");
8544 					this.template = this.template.replace("{time}", this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length) || "");
8545 					break;
8546 				case "date":
8547 					this.template = this._getFormat(this.formats.date, this.dateComponents, this.length);
8548 					break;
8549 				case "time":
8550 					this.template = this._getFormat(this.formats.time[this.clock], this.timeComponents, this.length);
8551 					break;
8552 			}
8553 		} else {
8554 			throw "No formats available for calendar " + this.calName + " in locale " + this.locale.toString();
8555 		}
8556 	},
8557 	
8558 	/**
8559 	 * @protected
8560 	 */
8561 	_massageTemplate: function () {
8562 		var i;
8563 		
8564 		if (this.clock && this.template) {
8565 			// explicitly set the hours to the requested type
8566 			var temp = "";
8567 			switch (this.clock) {
8568 				case "24":
8569 					for (i = 0; i < this.template.length; i++) {
8570 						if (this.template.charAt(i) == "'") {
8571 							temp += this.template.charAt(i++);
8572 							while (i < this.template.length && this.template.charAt(i) !== "'") {
8573 								temp += this.template.charAt(i++);
8574 							}
8575 							if (i < this.template.length) {
8576 								temp += this.template.charAt(i);
8577 							}
8578 						} else if (this.template.charAt(i) == 'K') {
8579 							temp += 'k';
8580 						} else if (this.template.charAt(i) == 'h') {
8581 							temp += 'H';
8582 						} else {
8583 							temp += this.template.charAt(i);
8584 						}
8585 					}
8586 					this.template = temp;
8587 					break;
8588 				case "12":
8589 					for (i = 0; i < this.template.length; i++) {
8590 						if (this.template.charAt(i) == "'") {
8591 							temp += this.template.charAt(i++);
8592 							while (i < this.template.length && this.template.charAt(i) !== "'") {
8593 								temp += this.template.charAt(i++);
8594 							}
8595 							if (i < this.template.length) {
8596 								temp += this.template.charAt(i);
8597 							}
8598 						} else if (this.template.charAt(i) == 'k') {
8599 							temp += 'K';
8600 						} else if (this.template.charAt(i) == 'H') {
8601 							temp += 'h';
8602 						} else {
8603 							temp += this.template.charAt(i);
8604 						}
8605 					}
8606 					this.template = temp;
8607 					break;
8608 			}
8609 		}
8610 		
8611 		// tokenize it now for easy formatting
8612 		this.templateArr = this._tokenize(this.template);
8613 
8614 		var digits;
8615 		// set up the mapping to native or alternate digits if necessary
8616 		if (typeof(this.useNative) === "boolean") {
8617 			if (this.useNative) {
8618 				digits = this.locinfo.getNativeDigits();
8619 				if (digits) {
8620 					this.digits = digits;
8621 				}
8622 			}
8623 		} else if (this.locinfo.getDigitsStyle() === "native") {
8624 			digits = this.locinfo.getNativeDigits();
8625 			if (digits) {
8626 				this.useNative = true;
8627 				this.digits = digits;
8628 			}
8629 		}
8630 	},
8631     
8632 	/**
8633 	 * Convert the template into an array of date components separated by formatting chars.
8634 	 * @protected
8635 	 * @param {string} template Format template to tokenize into components
8636 	 * @return {Array.<string>} a tokenized array of date format components
8637 	 */
8638 	_tokenize: function (template) {
8639 		var i = 0, start, ch, letter, arr = [];
8640 		
8641 		// console.log("_tokenize: tokenizing template " + template);
8642 		if (template) {
8643 			while (i < template.length) {
8644 				ch = template.charAt(i);
8645 				start = i;
8646 				if (ch === "'") {
8647 					// console.log("found quoted string");
8648 					i++;
8649 					// escaped string - push as-is, then dequote later
8650 					while (i < template.length && template.charAt(i) !== "'") {
8651 						i++;
8652 					}
8653 					if (i < template.length) {
8654 						i++;	// grab the other quote too
8655 					}
8656 				} else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
8657 					letter = template.charAt(i);
8658 					// console.log("found letters " + letter);
8659 					while (i < template.length && ch === letter) {
8660 						ch = template.charAt(++i);
8661 					}
8662 				} else {
8663 					// console.log("found other");
8664 					while (i < template.length && ch !== "'" && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) {
8665 						ch = template.charAt(++i);
8666 					}
8667 				}
8668 				arr.push(template.substring(start,i));
8669 				// console.log("start is " + start + " i is " + i + " and substr is " + template.substring(start,i));
8670 			}
8671 		}
8672 		return arr;
8673 	},
8674                           
8675 	/**
8676 	 * @protected
8677 	 * @param {Object.<string, (string|{s:string,m:string,l:string,f:string})>} obj Object to search
8678 	 * @param {string} components Format components to search
8679 	 * @param {string} length Length of the requested format
8680 	 * @return {string|undefined} the requested format
8681 	 */
8682 	_getFormat: function getFormat(obj, components, length) {
8683 		if (typeof(components) !== 'undefined' && obj && obj[components]) {
8684 			return this._getLengthFormat(obj[components], length);
8685 		}
8686 		return undefined;
8687 	},
8688 
8689 	/**
8690 	 * @protected
8691 	 * @param {(string|{s:string,m:string,l:string,f:string})} obj Object to search
8692 	 * @param {string} length Length of the requested format
8693 	 * @return {(string|undefined)} the requested format
8694 	 */
8695 	_getLengthFormat: function getLengthFormat(obj, length) {
8696 		if (typeof(obj) === 'string') {
8697 			return obj;
8698 		} else if (obj[length]) {
8699 			return obj[length];
8700 		}
8701 		return undefined;
8702 	},
8703 
8704 	/**
8705 	 * Return the locale used with this formatter instance.
8706 	 * @return {Locale} the Locale instance for this formatter
8707 	 */
8708 	getLocale: function() {
8709 		return this.locale;
8710 	},
8711 	
8712 	/**
8713 	 * Return the template string that is used to format date/times for this
8714 	 * formatter instance. This will work, even when the template property is not explicitly 
8715 	 * given in the options to the constructor. Without the template option, the constructor 
8716 	 * will build the appropriate template according to the options and use that template
8717 	 * in the format method. 
8718 	 * 
8719 	 * @return {string} the format template for this formatter
8720 	 */
8721 	getTemplate: function() {
8722 		return this.template;
8723 	},
8724 	
8725 	/**
8726 	 * Return the type of this formatter. The type is a string that has one of the following
8727 	 * values: "time", "date", "datetime".
8728 	 * @return {string} the type of the formatter
8729 	 */
8730 	getType: function() {
8731 		return this.type;
8732 	},
8733 	
8734 	/**
8735 	 * Return the name of the calendar used to format date/times for this
8736 	 * formatter instance.
8737 	 * @return {string} the name of the calendar used by this formatter
8738 	 */
8739 	getCalendar: function () {
8740 		return this.cal.getType();
8741 	},
8742 	
8743 	/**
8744 	 * Return the length used to format date/times in this formatter. This is either the
8745 	 * value of the length option to the constructor, or the default value.
8746 	 * 
8747 	 * @return {string} the length of formats this formatter returns
8748 	 */
8749 	getLength: function () {
8750 		return DateFmt.lenmap[this.length] || "";
8751 	},
8752 	
8753 	/**
8754 	 * Return the date components that this formatter formats. This is either the 
8755 	 * value of the date option to the constructor, or the default value. If this
8756 	 * formatter is a time-only formatter, this method will return the empty 
8757 	 * string. The date component letters may be specified in any order in the 
8758 	 * constructor, but this method will reorder the given components to a standard 
8759 	 * order.
8760 	 * 
8761 	 * @return {string} the date components that this formatter formats
8762 	 */
8763 	getDateComponents: function () {
8764 		return this.dateComponents || "";
8765 	},
8766 
8767 	/**
8768 	 * Return the time components that this formatter formats. This is either the 
8769 	 * value of the time option to the constructor, or the default value. If this
8770 	 * formatter is a date-only formatter, this method will return the empty 
8771 	 * string. The time component letters may be specified in any order in the 
8772 	 * constructor, but this method will reorder the given components to a standard 
8773 	 * order.
8774 	 * 
8775 	 * @return {string} the time components that this formatter formats
8776 	 */
8777 	getTimeComponents: function () {
8778 		return this.timeComponents || "";
8779 	},
8780 
8781 	/**
8782 	 * Return the time zone used to format date/times for this formatter
8783 	 * instance.
8784 	 * @return a string naming the time zone
8785 	 */
8786 	getTimeZone: function () {
8787 		// Lazy load the time zone. If it wasn't explicitly set up before, set 
8788 		// it up now, but use the 
8789 		// default TZ for the locale. This way, if the caller never uses the
8790 		// time zone in their format, we never have to load up a TimeZone
8791 		// instance into this formatter.
8792 		if (!this.tz) {
8793 			this.tz = new TimeZone({id: ilib.getTimeZone()});
8794 		}
8795 		return this.tz;
8796 	},
8797 	/**
8798 	 * Return the clock option set in the constructor. If the clock option was
8799 	 * not given, the default from the locale is returned instead.
8800 	 * @return {string} "12" or "24" depending on whether this formatter uses
8801 	 * the 12-hour or 24-hour clock
8802 	 */
8803 	getClock: function () {
8804 		return this.clock || this.locinfo.getClock();
8805 	},
8806 	/**
8807 	 * Return the meridiems range in current locale. 
8808 	 * @return {Array.<{name:string,start:string,end:string}>} the range of available meridiems
8809 	 */
8810 	getMeridiemsRange: function () {
8811 		var result;
8812 		var _getSysString = function (key) {
8813 			return (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key)).toString();
8814 		};
8815 
8816 		switch (this.meridiems) {
8817 		case "chinese":
8818 			result = [
8819 				{
8820 					name: _getSysString.call(this, "azh0"),
8821 					start: "00:00",
8822 					end: "05:59"
8823 				},
8824 				{
8825 					name: _getSysString.call(this, "azh1"),
8826 					start: "06:00",
8827 					end: "08:59"
8828 				},
8829 				{
8830 					name: _getSysString.call(this, "azh2"),
8831 					start: "09:00",
8832 					end: "11:59"
8833 				},
8834 				{
8835 					name: _getSysString.call(this, "azh3"),
8836 					start: "12:00",
8837 					end: "12:59"
8838 				},
8839 				{
8840 					name: _getSysString.call(this, "azh4"),
8841 					start: "13:00",
8842 					end: "17:59"
8843 				},
8844 				{
8845 					name: _getSysString.call(this, "azh5"),
8846 					start: "18:00",
8847 					end: "20:59"
8848 				},
8849 				{
8850 					name: _getSysString.call(this, "azh6"),
8851 					start: "21:00",
8852 					end: "23:59"
8853 				}
8854 			];
8855 			break;
8856 		case "ethiopic":
8857 			result = [
8858 				{
8859 					name: _getSysString.call(this, "a0-ethiopic"),
8860 					start: "00:00",
8861 					end: "05:59"
8862 				},
8863 				{
8864 					name: _getSysString.call(this, "a1-ethiopic"),
8865 					start: "06:00",
8866 					end: "06:00"
8867 				},
8868 				{
8869 					name: _getSysString.call(this, "a2-ethiopic"),
8870 					start: "06:01",
8871 					end: "11:59"
8872 				},
8873 				{
8874 					name: _getSysString.call(this, "a3-ethiopic"),
8875 					start: "12:00",
8876 					end: "17:59"
8877 				},
8878 				{
8879 					name: _getSysString.call(this, "a4-ethiopic"),
8880 					start: "18:00",
8881 					end: "23:59"
8882 				}
8883 			];
8884 			break;
8885 		default:
8886 			result = [
8887 				{
8888 					name: _getSysString.call(this, "a0"),
8889 					start: "00:00",
8890 					end: "11:59"
8891 				},
8892 				{
8893 					name: _getSysString.call(this, "a1"),
8894 					start: "12:00",
8895 					end: "23:59"
8896 				}
8897 			];
8898 			break;
8899 		}
8900 
8901 		return result;
8902 	},
8903 	
8904 	/**
8905 	 * @private
8906 	 */
8907 	_getTemplate: function (prefix, calendar) {
8908 		if (calendar !== "gregorian") {
8909 			return prefix + "-" + calendar;
8910 		}
8911 		return prefix;
8912 	},
8913 
8914 	/**
8915 	 * Returns an array of the months of the year, formatted to the optional length specified.
8916 	 * i.e. ...getMonthsOfYear() OR ...getMonthsOfYear({length: "short"})
8917 	 * <p>
8918 	 * The options parameter may contain any of the following properties:
8919 	 * 
8920 	 * <ul>
8921 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
8922 	 * "short", "medium", "long", or "full"
8923 	 * <li><i>date</i> - retrieve the names of the months in the date of the given date
8924 	 * <li><i>year</i> - retrieve the names of the months in the given year. In some calendars,
8925 	 * the months have different names depending if that year is a leap year or not.
8926 	 * </ul>
8927 	 * 
8928 	 * @param  {Object=} options an object-literal that contains any of the above properties
8929 	 * @return {Array} an array of the names of all of the months of the year in the current calendar
8930 	 */
8931 	getMonthsOfYear: function(options) {
8932 		var length = (options && options.length) || this.getLength(),
8933 			template = DateFmt.monthNameLenMap[length],
8934 			months = [undefined],
8935 			date,
8936 			monthCount;
8937 		
8938 		if (options) {
8939 			if (options.date) {
8940 				date = DateFactory._dateToIlib(options.date); 	
8941 			}
8942 			
8943 			if (options.year) {
8944 				date = DateFactory({year: options.year, month: 1, day: 1, type: this.cal.getType()});
8945 			}
8946 		}
8947 		
8948 		if (!date) {
8949 			date = DateFactory({
8950 				calendar: this.cal.getType()
8951 			});
8952 		}
8953 
8954 		monthCount = this.cal.getNumMonths(date.getYears());
8955 		for (var i = 1; i <= monthCount; i++) {
8956 			months[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
8957 		}
8958 		return months;
8959 	},
8960 
8961 	/**
8962 	 * Returns an array of the days of the week, formatted to the optional length specified.
8963 	 * i.e. ...getDaysOfWeek() OR ...getDaysOfWeek({length: "short"})
8964 	 * <p>
8965 	 * The options parameter may contain any of the following properties:
8966 	 * 
8967 	 * <ul>
8968 	 * <li><i>length</i> - length of the names of the months being sought. This may be one of
8969 	 * "short", "medium", "long", or "full"
8970 	 * </ul>
8971 	 * @param  {Object=} options an object-literal that contains one key 
8972 	 *                   "length" with the standard length strings
8973 	 * @return {Array} an array of all of the names of the days of the week
8974 	 */
8975 	getDaysOfWeek: function(options) {
8976 		var length = (options && options.length) || this.getLength(),
8977 			template = DateFmt.weekDayLenMap[length],
8978 			days = [];
8979 		for (var i = 0; i < 7; i++) {
8980 			days[i] = this.sysres.getString(this._getTemplate(template + i, this.cal.getType())).toString();
8981 		}
8982 		return days;
8983 	},
8984 
8985 	
8986 	/**
8987 	 * Convert this formatter to a string representation by returning the
8988 	 * format template. This method delegates to getTemplate.
8989 	 * 
8990 	 * @return {string} the format template
8991 	 */
8992 	toString: function() {
8993 		return this.getTemplate();
8994 	},
8995 	
8996 	/*
8997 	 * @private
8998 	 * Left pad the str to the given length of digits with zeros
8999 	 * @param {string} str the string to pad
9000 	 * @param {number} length the desired total length of the output string, padded 
9001 	 */
9002 	_pad: function (str, length) {
9003 		if (typeof(str) !== 'string') {
9004 			str = "" + str;
9005 		}
9006 		var start = 0;
9007 		if (str.charAt(0) === '-') {
9008 			start++;
9009 		}
9010 		return (str.length >= length+start) ? str : str.substring(0, start) + DateFmt.zeros.substring(0,length-str.length+start) + str.substring(start);
9011 	},
9012 	
9013 	/*
9014 	 * @private
9015 	 * Format a date according to a sequence of components. 
9016 	 * @param {IDate} date a date/time object to format
9017 	 * @param {Array.<string>} templateArr an array of components to format
9018 	 * @return {string} the formatted date
9019 	 */
9020 	_formatTemplate: function (date, templateArr) {
9021 		var i, key, temp, tz, str = "";
9022 		for (i = 0; i < templateArr.length; i++) {
9023 			switch (templateArr[i]) {
9024 				case 'd':
9025 					str += (date.day || 1);
9026 					break;
9027 				case 'dd':
9028 					str += this._pad(date.day || "1", 2);
9029 					break;
9030 				case 'yy':
9031 					temp = "" + ((date.year || 0) % 100);
9032 					str += this._pad(temp, 2);
9033 					break;
9034 				case 'yyyy':
9035 					str += this._pad(date.year || "0", 4);
9036 					break;
9037 				case 'M':
9038 					str += (date.month || 1);
9039 					break;
9040 				case 'MM':
9041 					str += this._pad(date.month || "1", 2);
9042 					break;
9043 				case 'h':
9044 					temp = (date.hour || 0) % 12;
9045 					if (temp == 0) {
9046 						temp = "12";
9047 					}
9048 					str += temp; 
9049 					break;
9050 				case 'hh':
9051 					temp = (date.hour || 0) % 12;
9052 					if (temp == 0) {
9053 						temp = "12";
9054 					}
9055 					str += this._pad(temp, 2);
9056 					break;
9057 				/*
9058 				case 'j':
9059 					temp = (date.hour || 0) % 12 + 1;
9060 					str += temp; 
9061 					break;
9062 				case 'jj':
9063 					temp = (date.hour || 0) % 12 + 1;
9064 					str += this._pad(temp, 2);
9065 					break;
9066 				*/
9067 				case 'K':
9068 					temp = (date.hour || 0) % 12;
9069 					str += temp; 
9070 					break;
9071 				case 'KK':
9072 					temp = (date.hour || 0) % 12;
9073 					str += this._pad(temp, 2);
9074 					break;
9075 
9076 				case 'H':
9077 					str += (date.hour || "0");
9078 					break;
9079 				case 'HH':
9080 					str += this._pad(date.hour || "0", 2);
9081 					break;
9082 				case 'k':
9083 					str += (date.hour == 0 ? "24" : date.hour);
9084 					break;
9085 				case 'kk':
9086 					temp = (date.hour == 0 ? "24" : date.hour);
9087 					str += this._pad(temp, 2);
9088 					break;
9089 
9090 				case 'm':
9091 					str += (date.minute || "0");
9092 					break;
9093 				case 'mm':
9094 					str += this._pad(date.minute || "0", 2);
9095 					break;
9096 				case 's':
9097 					str += (date.minute || "0");
9098 					break;
9099 				case 'ss':
9100 					str += this._pad(date.second || "0", 2);
9101 					break;
9102 				case 'S':
9103 					str += (date.millisecond || "0");
9104 					break;
9105 				case 'SSS':
9106 					str += this._pad(date.millisecond || "0", 3);
9107 					break;
9108 
9109 				case 'N':
9110 				case 'NN':
9111 				case 'MMM':
9112 				case 'MMMM':
9113 					key = templateArr[i] + (date.month || 1);
9114 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9115 					break;
9116 
9117 				case 'E':
9118 				case 'EE':
9119 				case 'EEE':
9120 				case 'EEEE':
9121 					key = templateArr[i] + date.getDayOfWeek();
9122 					//console.log("finding " + key + " in the resources");
9123 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9124 					break;
9125 					
9126 				case 'a':
9127 					switch (this.meridiems) {
9128 					case "chinese":
9129 						if (date.hour < 6) {
9130 							key = "azh0";	// before dawn
9131 						} else if (date.hour < 9) {
9132 							key = "azh1";	// morning
9133 						} else if (date.hour < 12) {
9134 							key = "azh2";	// late morning/day before noon
9135 						} else if (date.hour < 13) {
9136 							key = "azh3";	// noon hour/midday
9137 						} else if (date.hour < 18) {
9138 							key = "azh4";	// afternoon
9139 						} else if (date.hour < 21) {
9140 							key = "azh5";	// evening time/dusk
9141 						} else {
9142 							key = "azh6";	// night time
9143 						}
9144 						break;
9145 					case "ethiopic":
9146 						if (date.hour < 6) {
9147 							key = "a0-ethiopic";	// morning
9148 						} else if (date.hour === 6 && date.minute === 0) {
9149 							key = "a1-ethiopic";	// noon
9150 						} else if (date.hour >= 6 && date.hour < 12) {
9151 							key = "a2-ethiopic";	// afternoon
9152 						} else if (date.hour >= 12 && date.hour < 18) {
9153 							key = "a3-ethiopic";	// evening
9154 						} else if (date.hour >= 18) {
9155 							key = "a4-ethiopic";	// night
9156 						}
9157 						break;
9158 					default:
9159 						key = date.hour < 12 ? "a0" : "a1";
9160 						break;
9161 					}
9162 					//console.log("finding " + key + " in the resources");
9163 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9164 					break;
9165 					
9166 				case 'w':
9167 					str += date.getWeekOfYear();
9168 					break;
9169 				case 'ww':
9170 					str += this._pad(date.getWeekOfYear(), 2);
9171 					break;
9172 
9173 				case 'D':
9174 					str += date.getDayOfYear();
9175 					break;
9176 				case 'DD':
9177 					str += this._pad(date.getDayOfYear(), 2);
9178 					break;
9179 				case 'DDD':
9180 					str += this._pad(date.getDayOfYear(), 3);
9181 					break;
9182 				case 'W':
9183 					str += date.getWeekOfMonth(this.locale);
9184 					break;
9185 
9186 				case 'G':
9187 					key = "G" + date.getEra();
9188 					str += (this.sysres.getString(undefined, key + "-" + this.calName) || this.sysres.getString(undefined, key));
9189 					break;
9190 
9191 				case 'O':
9192 					temp = this.sysres.getString("1#1st|2#2nd|3#3rd|21#21st|22#22nd|23#23rd|31#31st|#{num}th", "ordinalChoice");
9193 					str += temp.formatChoice(date.day, {num: date.day});
9194 					break;
9195 					
9196 				case 'z': // general time zone
9197 					tz = this.getTimeZone(); // lazy-load the tz
9198 					str += tz.getDisplayName(date, "standard");
9199 					break;
9200 				case 'Z': // RFC 822 time zone
9201 					tz = this.getTimeZone(); // lazy-load the tz
9202 					str += tz.getDisplayName(date, "rfc822");
9203 					break;
9204 
9205 				default:
9206 					str += templateArr[i].replace(/'/g, "");
9207 					break;
9208 			}
9209 		}
9210 
9211 		if (this.digits) {
9212 			str = JSUtils.mapString(str, this.digits);
9213 		}
9214 		return str;
9215 	},
9216 	
9217 	/**
9218 	 * Format a particular date instance according to the settings of this
9219 	 * formatter object. The type of the date instance being formatted must 
9220 	 * correspond exactly to the calendar type with which this formatter was 
9221 	 * constructed. If the types are not compatible, this formatter will
9222 	 * produce bogus results.
9223 	 * 
9224 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} dateLike a date-like object to format
9225 	 * @return {string} the formatted version of the given date instance
9226 	 */
9227 	format: function (dateLike) {
9228 		var thisZoneName = this.tz && this.tz.getId() || "local";
9229 
9230 		var date = DateFactory._dateToIlib(dateLike, thisZoneName, this.locale);
9231 		
9232 		if (!date.getCalendar || !(date instanceof IDate)) {
9233 			throw "Wrong date type passed to DateFmt.format()";
9234 		}
9235 		
9236 		var dateZoneName = date.timezone || "local";
9237 		
9238 		// convert to the time zone of this formatter before formatting
9239 		if (dateZoneName !== thisZoneName || date.getCalendar() !== this.calName) {
9240 			// console.log("Differing time zones date: " + dateZoneName + " and fmt: " + thisZoneName + ". Converting...");
9241 			// this will recalculate the date components based on the new time zone
9242 			// and/or convert a date in another calendar to the current calendar before formatting it
9243 			var newDate = DateFactory({
9244 				type: this.calName,
9245 				timezone: thisZoneName,
9246 				julianday: date.getJulianDay()
9247 			});
9248 			
9249 			date = newDate;
9250 		}
9251 		return this._formatTemplate(date, this.templateArr);
9252 	},
9253 	
9254 	/**
9255 	 * Return a string that describes a date relative to the given 
9256 	 * reference date. The string returned is text that for the locale that
9257 	 * was specified when the formatter instance was constructed.<p>
9258 	 * 
9259 	 * The date can be in the future relative to the reference date or in
9260 	 * the past, and the formatter will generate the appropriate string.<p>
9261 	 * 
9262 	 * The text used to describe the relative reference depends on the length
9263 	 * of time between the date and the reference. If the time was in the
9264 	 * past, it will use the "ago" phrase, and in the future, it will use
9265 	 * the "in" phrase. Examples:<p>
9266 	 * 
9267 	 * <ul>
9268 	 * <li>within a minute: either "X seconds ago" or "in X seconds"
9269 	 * <li>within an hour: either "X minutes ago" or "in X minutes"
9270 	 * <li>within a day: either "X hours ago" or "in X hours"
9271 	 * <li>within 2 weeks: either "X days ago" or "in X days"
9272 	 * <li>within 12 weeks (~3 months): either "X weeks ago" or "in X weeks"
9273 	 * <li>within two years: either "X months ago" or "in X months"
9274 	 * <li>longer than 2 years: "X years ago" or "in X years"
9275 	 * </ul>
9276 	 * 
9277 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} reference a date that the date parameter should be relative to
9278 	 * @param {IDate|Number|String|Date|JulianDay|null|undefined} date a date being formatted
9279 	 * @throws "Wrong calendar type" when the start or end dates are not the same
9280 	 * calendar type as the formatter itself
9281 	 * @return {string} the formatted relative date
9282 	 */
9283 	formatRelative: function(reference, date) {
9284 		reference = DateFactory._dateToIlib(reference);
9285 		date = DateFactory._dateToIlib(date);
9286 		
9287 		var referenceRd, dateRd, fmt, time, diff, num;
9288 		
9289 		if (typeof(reference) !== 'object' || !reference.getCalendar || reference.getCalendar() !== this.calName ||
9290 			typeof(date) !== 'object' || !date.getCalendar || date.getCalendar() !== this.calName) {
9291 			throw "Wrong calendar type";
9292 		}
9293 		
9294 		referenceRd = reference.getRataDie();
9295 		dateRd = date.getRataDie();
9296 		
9297 		if (dateRd < referenceRd) {
9298 			diff = referenceRd - dateRd;
9299 			fmt = this.sysres.getString("{duration} ago");
9300 		} else {
9301 			diff = dateRd - referenceRd;
9302 			fmt = this.sysres.getString("in {duration}");
9303 		}
9304 		
9305 		if (diff < 0.000694444) {
9306 			num = Math.round(diff * 86400);
9307 			switch (this.length) {
9308 				case 's':
9309 					time = this.sysres.getString("#{num}s");
9310 					break;
9311 				case 'm':
9312 					time = this.sysres.getString("1#1 se|#{num} sec");
9313 					break;
9314 				case 'l':
9315 					time = this.sysres.getString("1#1 sec|#{num} sec");
9316 					break;
9317 				default:
9318 				case 'f':
9319 					time = this.sysres.getString("1#1 second|#{num} seconds");
9320 					break;
9321 			}
9322 		} else if (diff < 0.041666667) {
9323 			num = Math.round(diff * 1440);
9324 			switch (this.length) {
9325 				case 's':
9326 					time = this.sysres.getString("#{num}m", "durationShortMinutes");
9327 					break;
9328 				case 'm':
9329 					time = this.sysres.getString("1#1 mi|#{num} min");
9330 					break;
9331 				case 'l':
9332 					time = this.sysres.getString("1#1 min|#{num} min");
9333 					break;
9334 				default:
9335 				case 'f':
9336 					time = this.sysres.getString("1#1 minute|#{num} minutes");
9337 					break;
9338 			}
9339 		} else if (diff < 1) {
9340 			num = Math.round(diff * 24);
9341 			switch (this.length) {
9342 				case 's':
9343 					time = this.sysres.getString("#{num}h");
9344 					break;
9345 				case 'm':
9346 					time = this.sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours");
9347 					break;
9348 				case 'l':
9349 					time = this.sysres.getString("1#1 hr|#{num} hrs");
9350 					break;
9351 				default:
9352 				case 'f':
9353 					time = this.sysres.getString("1#1 hour|#{num} hours");
9354 					break;
9355 			}
9356 		} else if (diff < 14) {
9357 			num = Math.round(diff);
9358 			switch (this.length) {
9359 				case 's':
9360 					time = this.sysres.getString("#{num}d");
9361 					break;
9362 				case 'm':
9363 					time = this.sysres.getString("1#1 dy|#{num} dys");
9364 					break;
9365 				case 'l':
9366 					time = this.sysres.getString("1#1 day|#{num} days", "durationLongDays");
9367 					break;
9368 				default:
9369 				case 'f':
9370 					time = this.sysres.getString("1#1 day|#{num} days");
9371 					break;
9372 			}
9373 		} else if (diff < 84) {
9374 			num = Math.round(diff/7);
9375 			switch (this.length) {
9376 				case 's':
9377 					time = this.sysres.getString("#{num}w");
9378 					break;
9379 				case 'm':
9380 					time = this.sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks");
9381 					break;
9382 				case 'l':
9383 					time = this.sysres.getString("1#1 wk|#{num} wks");
9384 					break;
9385 				default:
9386 				case 'f':
9387 					time = this.sysres.getString("1#1 week|#{num} weeks");
9388 					break;
9389 			}
9390 		} else if (diff < 730) {
9391 			num = Math.round(diff/30.4);
9392 			switch (this.length) {
9393 				case 's':
9394 					time = this.sysres.getString("#{num}m", "durationShortMonths");
9395 					break;
9396 				case 'm':
9397 					time = this.sysres.getString("1#1 mo|#{num} mos");
9398 					break;
9399 				case 'l':
9400 					time = this.sysres.getString("1#1 mon|#{num} mons");
9401 					break;
9402 				default:
9403 				case 'f':
9404 					time = this.sysres.getString("1#1 month|#{num} months");
9405 					break;
9406 			}
9407 		} else {
9408 			num = Math.round(diff/365);
9409 			switch (this.length) {
9410 				case 's':
9411 					time = this.sysres.getString("#{num}y");
9412 					break;
9413 				case 'm':
9414 					time = this.sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears");
9415 					break;
9416 				case 'l':
9417 					time = this.sysres.getString("1#1 yr|#{num} yrs");
9418 					break;
9419 				default:
9420 				case 'f':
9421 					time = this.sysres.getString("1#1 year|#{num} years");
9422 					break;
9423 			}
9424 		}
9425 		return fmt.format({duration: time.formatChoice(num, {num: num})});
9426 	}
9427 };
9428 
9429 
9430 
9431 /*< DateRngFmt.js */
9432 /*
9433  * DateFmt.js - Date formatter definition
9434  * 
9435  * Copyright © 2012-2015, JEDLSoft
9436  *
9437  * Licensed under the Apache License, Version 2.0 (the "License");
9438  * you may not use this file except in compliance with the License.
9439  * You may obtain a copy of the License at
9440  *
9441  *     http://www.apache.org/licenses/LICENSE-2.0
9442  *
9443  * Unless required by applicable law or agreed to in writing, software
9444  * distributed under the License is distributed on an "AS IS" BASIS,
9445  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9446  *
9447  * See the License for the specific language governing permissions and
9448  * limitations under the License.
9449  */
9450 
9451 /*
9452 !depends 
9453 ilib.js 
9454 Locale.js 
9455 IDate.js 
9456 IString.js 
9457 CalendarFactory.js
9458 LocaleInfo.js
9459 TimeZone.js
9460 DateFmt.js
9461 GregorianCal.js
9462 JSUtils.js
9463 Utils.js
9464 */
9465 
9466 // !data dateformats sysres
9467 
9468 
9469 
9470 
9471 
9472 /**
9473  * @class
9474  * Create a new date range formatter instance. The date range formatter is immutable once
9475  * it is created, but can format as many different date ranges as needed with the same
9476  * options. Create different date range formatter instances for different purposes
9477  * and then keep them cached for use later if you have more than one range to
9478  * format.<p>
9479  * 
9480  * The options may contain any of the following properties:
9481  * 
9482  * <ul>
9483  * <li><i>locale</i> - locale to use when formatting the date/times in the range. If the 
9484  * locale is not specified, then the default locale of the app or web page will be used.
9485  * 
9486  * <li><i>calendar</i> - the type of calendar to use for this format. The value should
9487  * be a sting containing the name of the calendar. Currently, the supported
9488  * types are "gregorian", "julian", "arabic", "hebrew", or "chinese". If the
9489  * calendar is not specified, then the default calendar for the locale is used. When the
9490  * calendar type is specified, then the format method must be called with an instance of
9491  * the appropriate date type. (eg. Gregorian calendar means that the format method must 
9492  * be called with a GregDate instance.)
9493  *  
9494  * <li><i>timezone</i> - time zone to use when formatting times. This may be a time zone
9495  * instance or a time zone specifier string in RFC 822 format. If not specified, the
9496  * default time zone for the locale is used.
9497  * 
9498  * <li><i>length</i> - Specify the length of the format to use as a string. The length 
9499  * is the approximate size of the formatted string.
9500  * 
9501  * <ul>
9502  * <li><i>short</i> - use a short representation of the time. This is the most compact format possible for the locale.
9503  * <li><i>medium</i> - use a medium length representation of the time. This is a slightly longer format.
9504  * <li><i>long</i> - use a long representation of the time. This is a fully specified format, but some of the textual 
9505  * components may still be abbreviated. (eg. "Tue" instead of "Tuesday")
9506  * <li><i>full</i> - use a full representation of the time. This is a fully specified format where all the textual 
9507  * components are spelled out completely.
9508  * </ul>
9509  * 
9510  * eg. The "short" format for an en_US range may be "MM/yy - MM/yy", whereas the long format might be 
9511  * "MMM, yyyy - MMM, yyyy". In the long format, the month name is textual instead of numeric 
9512  * and is longer, the year is 4 digits instead of 2, and the format contains slightly more 
9513  * spaces and formatting characters.<p>
9514  * 
9515  * Note that the length parameter does not specify which components are to be formatted. The
9516  * components that are formatted depend on the length of time in the range.
9517  * 
9518  * <li><i>clock</i> - specify that formatted times should use a 12 or 24 hour clock if the
9519  * format happens to include times. Valid values are "12" and "24".<p>
9520  * 
9521  * In some locales, both clocks are used. For example, in en_US, the general populace uses
9522  * a 12 hour clock with am/pm, but in the US military or in nautical or aeronautical or 
9523  * scientific writing, it is more common to use a 24 hour clock. This property allows you to
9524  * construct a formatter that overrides the default for the locale.<p>
9525  * 
9526  * If this property is not specified, the default is to use the most widely used convention
9527  * for the locale.
9528  * <li>onLoad - a callback function to call when the date range format object is fully 
9529  * loaded. When the onLoad option is given, the DateRngFmt object will attempt to
9530  * load any missing locale data using the ilib loader callback.
9531  * When the constructor is done (even if the data is already preassembled), the 
9532  * onLoad function is called with the current instance as a parameter, so this
9533  * callback can be used with preassembled or dynamic loading or a mix of the two. 
9534  * 
9535  * <li>sync - tell whether to load any missing locale data synchronously or 
9536  * asynchronously. If this option is given as "false", then the "onLoad"
9537  * callback must be given, as the instance returned from this constructor will
9538  * not be usable for a while.
9539  *  
9540  * <li><i>loadParams</i> - an object containing parameters to pass to the 
9541  * loader callback function when locale data is missing. The parameters are not
9542  * interpretted or modified in any way. They are simply passed along. The object 
9543  * may contain any property/value pairs as long as the calling code is in
9544  * agreement with the loader callback function as to what those parameters mean.
9545  * </ul>
9546  * <p>
9547  * 
9548  * 
9549  * @constructor
9550  * @param {Object} options options governing the way this date range formatter instance works
9551  */
9552 var DateRngFmt = function(options) {
9553 	var sync = true;
9554 	var loadParams = undefined;
9555 	this.locale = new Locale();
9556 	this.length = "s";
9557 	
9558 	if (options) {
9559 		if (options.locale) {
9560 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
9561 		}
9562 		
9563 		if (options.calendar) {
9564 			this.calName = options.calendar;
9565 		}
9566 		
9567 		if (options.length) {
9568 			if (options.length === 'short' ||
9569 				options.length === 'medium' ||
9570 				options.length === 'long' ||
9571 				options.length === 'full') {
9572 				// only use the first char to save space in the json files
9573 				this.length = options.length.charAt(0);
9574 			}
9575 		}
9576 		if (typeof(options.sync) !== 'undefined') {
9577 			sync = (options.sync == true);
9578 		}
9579 		
9580 		loadParams = options.loadParams;
9581 	}
9582 	
9583 	var opts = {};
9584 	JSUtils.shallowCopy(options, opts);
9585 	opts.sync = sync;
9586 	opts.loadParams = loadParams;
9587 	
9588 	/**
9589 	 * @private
9590 	 */
9591 	opts.onLoad = ilib.bind(this, function (fmt) {
9592 		this.dateFmt = fmt;
9593 		if (fmt) {
9594 			this.locinfo = this.dateFmt.locinfo;
9595 
9596 			// get the default calendar name from the locale, and if the locale doesn't define
9597 			// one, use the hard-coded gregorian as the last resort
9598 			this.calName = this.calName || this.locinfo.getCalendar() || "gregorian";
9599 			this.cal = CalendarFactory({
9600 				type: this.calName
9601 			});
9602 			if (!this.cal) {
9603 				this.cal = new GregorianCal();
9604 			}
9605 			
9606 			this.timeTemplate = this.dateFmt._getFormat(this.dateFmt.formats.time[this.dateFmt.clock], this.dateFmt.timeComponents, this.length) || "hh:mm";
9607 			this.timeTemplateArr = this.dateFmt._tokenize(this.timeTemplate);
9608 			
9609 			if (options && typeof(options.onLoad) === 'function') {
9610 				options.onLoad(this);
9611 			}
9612 		}
9613 	});
9614 
9615 	// delegate a bunch of the formatting to this formatter
9616 	new DateFmt(opts);
9617 };
9618 
9619 DateRngFmt.prototype = {
9620 	/**
9621 	 * Return the locale used with this formatter instance.
9622 	 * @return {Locale} the Locale instance for this formatter
9623 	 */
9624 	getLocale: function() {
9625 		return this.locale;
9626 	},
9627 	
9628 	/**
9629 	 * Return the name of the calendar used to format date/times for this
9630 	 * formatter instance.
9631 	 * @return {string} the name of the calendar used by this formatter
9632 	 */
9633 	getCalendar: function () {
9634 		return this.dateFmt.getCalendar();
9635 	},
9636 	
9637 	/**
9638 	 * Return the length used to format date/times in this formatter. This is either the
9639 	 * value of the length option to the constructor, or the default value.
9640 	 * 
9641 	 * @return {string} the length of formats this formatter returns
9642 	 */
9643 	getLength: function () {
9644 		return DateFmt.lenmap[this.length] || "";
9645 	},
9646 	
9647 	/**
9648 	 * Return the time zone used to format date/times for this formatter
9649 	 * instance.
9650 	 * @return {TimeZone} a string naming the time zone
9651 	 */
9652 	getTimeZone: function () {
9653 		return this.dateFmt.getTimeZone();
9654 	},
9655 	
9656 	/**
9657 	 * Return the clock option set in the constructor. If the clock option was
9658 	 * not given, the default from the locale is returned instead.
9659 	 * @return {string} "12" or "24" depending on whether this formatter uses
9660 	 * the 12-hour or 24-hour clock
9661 	 */
9662 	getClock: function () {
9663 		return this.dateFmt.getClock();
9664 	},
9665 	
9666 	/**
9667 	 * Format a date/time range according to the settings of the current
9668 	 * formatter. The range is specified as being from the "start" date until
9669 	 * the "end" date. <p>
9670 	 * 
9671 	 * The template that the date/time range uses depends on the
9672 	 * length of time between the dates, on the premise that a long date range
9673 	 * which is too specific is not useful. For example, when giving
9674 	 * the dates of the 100 Years War, in most situations it would be more 
9675 	 * appropriate to format the range as "1337 - 1453" than to format it as 
9676 	 * "10:37am November 9, 1337 - 4:37pm July 17, 1453", as the latter format 
9677 	 * is much too specific given the length of time that the range represents.
9678 	 * If a very specific, but long, date range really is needed, the caller 
9679 	 * should format two specific dates separately and put them 
9680 	 * together as you might with other normal strings.<p>
9681 	 * 
9682 	 * The format used for a date range contains the following date components,
9683 	 * where the order of those components is rearranged and the component values 
9684 	 * are translated according to each locale:
9685 	 * 
9686 	 * <ul>
9687 	 * <li>within 3 days: the times of day, dates, months, and years
9688 	 * <li>within 730 days (2 years): the dates, months, and years
9689 	 * <li>within 3650 days (10 years): the months and years
9690 	 * <li>longer than 10 years: the years only 
9691 	 * </ul>
9692 	 * 
9693 	 * In general, if any of the date components share a value between the
9694 	 * start and end date, that component is only given once. For example,
9695 	 * if the range is from November 15, 2011 to November 26, 2011, the 
9696 	 * start and end dates both share the same month and year. The 
9697 	 * range would then be formatted as "November 15-26, 2011". <p>
9698 	 * 
9699 	 * If you want to format a length of time instead of a particular range of
9700 	 * time (for example, the length of an event rather than the specific start time
9701 	 * and end time of that event), then use a duration formatter instance 
9702 	 * (DurationFmt) instead. The formatRange method will make sure that each component 
9703 	 * of the date/time is within the normal range for that component. For example, 
9704 	 * the minutes will always be between 0 and 59, no matter what is specified in 
9705 	 * the date to format, because that is the normal range for minutes. A duration 
9706 	 * format will allow the number of minutes to exceed 59. For example, if you 
9707 	 * were displaying the length of a movie that is 198 minutes long, the minutes
9708 	 * component of a duration could be 198.<p>
9709 	 * 
9710 	 * @param {IDate} start the starting date/time of the range. This must be of 
9711 	 * the same calendar type as the formatter itself. 
9712 	 * @param {IDate} end the ending date/time of the range. This must be of the 
9713 	 * same calendar type as the formatter itself.
9714 	 * @throws "Wrong calendar type" when the start or end dates are not the same
9715 	 * calendar type as the formatter itself
9716 	 * @return {string} a date range formatted for the locale
9717 	 */
9718 	format: function (start, end) {
9719 		var startRd, endRd, fmt = "", yearTemplate, monthTemplate, dayTemplate;
9720 		
9721 		if (typeof(start) !== 'object' || !start.getCalendar || start.getCalendar() !== this.calName ||
9722 			typeof(end) !== 'object' || !end.getCalendar || end.getCalendar() !== this.calName) {
9723 			throw "Wrong calendar type";
9724 		}
9725 		
9726 		startRd = start.getRataDie();
9727 		endRd = end.getRataDie();
9728 		
9729 		// 
9730 		// legend:
9731 		// c00 - difference is less than 3 days. Year, month, and date are same, but time is different
9732 		// c01 - difference is less than 3 days. Year and month are same but date and time are different
9733 		// c02 - difference is less than 3 days. Year is same but month, date, and time are different. (ie. it straddles a month boundary)
9734 		// c03 - difference is less than 3 days. Year, month, date, and time are all different. (ie. it straddles a year boundary)
9735 		// c10 - difference is less than 2 years. Year and month are the same, but date is different.
9736 		// c11 - difference is less than 2 years. Year is the same, but month, date, and time are different.
9737 		// c12 - difference is less than 2 years. All fields are different. (ie. straddles a year boundary)
9738 		// c20 - difference is less than 10 years. All fields are different.
9739 		// c30 - difference is more than 10 years. All fields are different.
9740 		//
9741 		
9742 		if (endRd - startRd < 3) {
9743 			if (start.year === end.year) {
9744 				if (start.month === end.month) {
9745 					if (start.day === end.day) {
9746 						fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c00", this.length));
9747 					} else {
9748 						fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c01", this.length));
9749 					}
9750 				} else {
9751 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c02", this.length));
9752 				}
9753 			} else {
9754 				fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c03", this.length));
9755 			}
9756 		} else if (endRd - startRd < 730) {
9757 			if (start.year === end.year) {
9758 				if (start.month === end.month) {
9759 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c10", this.length));
9760 				} else {
9761 					fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c11", this.length));
9762 				}
9763 			} else {
9764 				fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c12", this.length));
9765 			}
9766 		} else if (endRd - startRd < 3650) {
9767 			fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c20", this.length));
9768 		} else {
9769 			fmt = new IString(this.dateFmt._getFormat(this.dateFmt.formats.range, "c30", this.length));
9770 		}
9771 
9772 		yearTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "y", this.length) || "yyyy");
9773 		monthTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "m", this.length) || "MM");
9774 		dayTemplate = this.dateFmt._tokenize(this.dateFmt._getFormat(this.dateFmt.formats.date, "d", this.length) || "dd");
9775 		
9776 		/*
9777 		console.log("fmt is " + fmt.toString());
9778 		console.log("year template is " + yearTemplate);
9779 		console.log("month template is " + monthTemplate);
9780 		console.log("day template is " + dayTemplate);
9781 		*/
9782 		
9783 		return fmt.format({
9784 			sy: this.dateFmt._formatTemplate(start, yearTemplate),
9785 			sm: this.dateFmt._formatTemplate(start, monthTemplate),
9786 			sd: this.dateFmt._formatTemplate(start, dayTemplate),
9787 			st: this.dateFmt._formatTemplate(start, this.timeTemplateArr),
9788 			ey: this.dateFmt._formatTemplate(end, yearTemplate),
9789 			em: this.dateFmt._formatTemplate(end, monthTemplate),
9790 			ed: this.dateFmt._formatTemplate(end, dayTemplate),
9791 			et: this.dateFmt._formatTemplate(end, this.timeTemplateArr)
9792 		});
9793 	}
9794 };
9795 
9796 
9797 /*< HebrewCal.js */
9798 /*
9799  * hebrew.js - Represent a Hebrew calendar object.
9800  * 
9801  * Copyright © 2012-2015, JEDLSoft
9802  *
9803  * Licensed under the Apache License, Version 2.0 (the "License");
9804  * you may not use this file except in compliance with the License.
9805  * You may obtain a copy of the License at
9806  *
9807  *     http://www.apache.org/licenses/LICENSE-2.0
9808  *
9809  * Unless required by applicable law or agreed to in writing, software
9810  * distributed under the License is distributed on an "AS IS" BASIS,
9811  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9812  *
9813  * See the License for the specific language governing permissions and
9814  * limitations under the License.
9815  */
9816 
9817 
9818 /* !depends ilib.js Calendar.js MathUtils.js */
9819 
9820 
9821 /**
9822  * @class
9823  * Construct a new Hebrew calendar object. This class encodes information about
9824  * the Hebrew (Jewish) calendar. The Hebrew calendar is a tabular hebrew 
9825  * calendar where the dates are calculated by arithmetic rules. This differs from 
9826  * the religious Hebrew calendar which is used to mark the beginning of particular 
9827  * holidays. The religious calendar depends on the first sighting of the new 
9828  * crescent moon to determine the first day of the new month. Because humans and 
9829  * weather are both involved, the actual time of sighting varies, so it is not 
9830  * really possible to precalculate the religious calendar. Certain groups, such 
9831  * as the Hebrew Society of North America, decreed in in 2007 that they will use
9832  * a calendar based on calculations rather than observations to determine the 
9833  * beginning of lunar months, and therefore the dates of holidays.<p>
9834  * 
9835  * 
9836  * @constructor
9837  * @extends Calendar
9838  */
9839 var HebrewCal = function() {
9840 	this.type = "hebrew";
9841 };
9842 
9843 /**
9844  * Return the number of days elapsed in the Hebrew calendar before the
9845  * given year starts.
9846  * @private
9847  * @param {number} year the year for which the number of days is sought
9848  * @return {number} the number of days elapsed in the Hebrew calendar before the
9849  * given year starts
9850  */
9851 HebrewCal.elapsedDays = function(year) {
9852 	var months = Math.floor(((235*year) - 234)/19);
9853 	var parts = 204 + 793 * MathUtils.mod(months, 1080);
9854 	var hours = 11 + 12 * months + 793 * Math.floor(months/1080) + 
9855 		Math.floor(parts/1080);
9856 	var days = 29 * months + Math.floor(hours/24);
9857 	return (MathUtils.mod(3 * (days + 1), 7) < 3) ? days + 1 : days;
9858 };
9859 
9860 /**
9861  * Return the number of days that the New Year's (Rosh HaShanah) in the Hebrew 
9862  * calendar will be corrected for the given year. Corrections are caused because New 
9863  * Year's is not allowed to start on certain days of the week. To deal with 
9864  * it, the start of the new year is corrected for the next year by adding a 
9865  * day to the 8th month (Heshvan) and/or the 9th month (Kislev) in the current
9866  * year to make them 30 days long instead of 29.
9867  * 
9868  * @private
9869  * @param {number} year the year for which the correction is sought
9870  * @param {number} elapsed number of days elapsed up to this year
9871  * @return {number} the number of days correction in the current year to make sure
9872  * Rosh HaShanah does not fall on undesirable days of the week
9873  */
9874 HebrewCal.newYearsCorrection = function(year, elapsed) {
9875 	var lastYear = HebrewCal.elapsedDays(year-1),
9876 		thisYear = elapsed,
9877 		nextYear = HebrewCal.elapsedDays(year+1);
9878 	
9879 	return (nextYear - thisYear) == 356 ? 2 : ((thisYear - lastYear) == 382 ? 1 : 0);
9880 };
9881 
9882 /**
9883  * Return the rata die date of the new year for the given hebrew year.
9884  * @private
9885  * @param {number} year the year for which the new year is needed
9886  * @return {number} the rata die date of the new year
9887  */
9888 HebrewCal.newYear = function(year) {
9889 	var elapsed = HebrewCal.elapsedDays(year); 
9890 	
9891 	return elapsed + HebrewCal.newYearsCorrection(year, elapsed);
9892 };
9893 
9894 /**
9895  * Return the number of days in the given year. Years contain a variable number of
9896  * days because the date of Rosh HaShanah (New Year's) changes so that it doesn't
9897  * fall on particular days of the week. Days are added to the months of Heshvan
9898  * and/or Kislev in the previous year in order to prevent the current year's New
9899  * Year from being on Sunday, Wednesday, or Friday.
9900  * 
9901  * @param {number} year the year for which the length is sought
9902  * @return {number} number of days in the given year
9903  */
9904 HebrewCal.daysInYear = function(year) {
9905 	return HebrewCal.newYear(year+1) - HebrewCal.newYear(year);
9906 };
9907 
9908 /**
9909  * Return true if the given year contains a long month of Heshvan. That is,
9910  * it is 30 days instead of 29.
9911  * 
9912  * @private
9913  * @param {number} year the year in which that month is questioned
9914  * @return {boolean} true if the given year contains a long month of Heshvan
9915  */
9916 HebrewCal.longHeshvan = function(year) {
9917 	return MathUtils.mod(HebrewCal.daysInYear(year), 10) === 5;
9918 };
9919 
9920 /**
9921  * Return true if the given year contains a long month of Kislev. That is,
9922  * it is 30 days instead of 29.
9923  * 
9924  * @private
9925  * @param {number} year the year in which that month is questioned
9926  * @return {boolean} true if the given year contains a short month of Kislev
9927  */
9928 HebrewCal.longKislev = function(year) {
9929 	return MathUtils.mod(HebrewCal.daysInYear(year), 10) !== 3;
9930 };
9931 
9932 /**
9933  * Return the date of the last day of the month for the given year. The date of
9934  * the last day of the month is variable because a number of months gain an extra 
9935  * day in leap years, and it is variable which months gain a day for each leap 
9936  * year and which do not.
9937  * 
9938  * @param {number} month the month for which the number of days is sought
9939  * @param {number} year the year in which that month is
9940  * @return {number} the number of days in the given month and year
9941  */
9942 HebrewCal.prototype.lastDayOfMonth = function(month, year) {
9943 	switch (month) {
9944 		case 2: 
9945 		case 4: 
9946 		case 6: 
9947 		case 10: 
9948 			return 29;
9949 		case 13:
9950 			return this.isLeapYear(year) ? 29 : 0;
9951 		case 8:
9952 			return HebrewCal.longHeshvan(year) ? 30 : 29;
9953 		case 9:
9954 			return HebrewCal.longKislev(year) ? 30 : 29;
9955 		case 12:
9956 		case 1:
9957 		case 3:
9958 		case 5:
9959 		case 7:
9960 		case 11:
9961 			return 30;
9962 		default:
9963 			return 0;
9964 	}
9965 };
9966 
9967 /**
9968  * Return the number of months in the given year. The number of months in a year varies
9969  * for luni-solar calendars because in some years, an extra month is needed to extend the 
9970  * days in a year to an entire solar year. The month is represented as a 1-based number
9971  * where 1=first month, 2=second month, etc.
9972  * 
9973  * @param {number} year a year for which the number of months is sought
9974  */
9975 HebrewCal.prototype.getNumMonths = function(year) {
9976 	return this.isLeapYear(year) ? 13 : 12;
9977 };
9978 
9979 /**
9980  * Return the number of days in a particular month in a particular year. This function
9981  * can return a different number for a month depending on the year because of leap years.
9982  *
9983  * @param {number} month the month for which the length is sought
9984  * @param {number} year the year within which that month can be found
9985  * @returns {number} the number of days within the given month in the given year, or
9986  * 0 for an invalid month in the year
9987  */
9988 HebrewCal.prototype.getMonLength = function(month, year) {
9989 	if (month < 1 || month > 13 || (month == 13 && !this.isLeapYear(year))) {
9990 		return 0;
9991 	}
9992 	return this.lastDayOfMonth(month, year);
9993 };
9994 
9995 /**
9996  * Return true if the given year is a leap year in the Hebrew calendar.
9997  * The year parameter may be given as a number, or as a HebrewDate object.
9998  * @param {number|Object} year the year for which the leap year information is being sought
9999  * @returns {boolean} true if the given year is a leap year
10000  */
10001 HebrewCal.prototype.isLeapYear = function(year) {
10002 	var y = (typeof(year) == 'number') ? year : year.year;
10003 	return (MathUtils.mod(1 + 7 * y, 19) < 7);
10004 };
10005 
10006 /**
10007  * Return the type of this calendar.
10008  * 
10009  * @returns {string} the name of the type of this calendar 
10010  */
10011 HebrewCal.prototype.getType = function() {
10012 	return this.type;
10013 };
10014 
10015 /**
10016  * Return a date instance for this calendar type using the given
10017  * options.
10018  * @param {Object} options options controlling the construction of 
10019  * the date instance
10020  * @returns {HebrewDate} a date appropriate for this calendar type
10021  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
10022  */
10023 HebrewCal.prototype.newDateInstance = function (options) {
10024 		return new HebrewDate(options);
10025 };
10026 
10027 /*register this calendar for the factory method */
10028 Calendar._constructors["hebrew"] = HebrewCal;
10029 
10030 
10031 
10032 /*< HebrewRataDie.js */
10033 /*
10034  * HebrewRataDie.js - Represent an RD date in the Hebrew calendar
10035  * 
10036  * Copyright © 2012-2015, JEDLSoft
10037  *
10038  * Licensed under the Apache License, Version 2.0 (the "License");
10039  * you may not use this file except in compliance with the License.
10040  * You may obtain a copy of the License at
10041  *
10042  *     http://www.apache.org/licenses/LICENSE-2.0
10043  *
10044  * Unless required by applicable law or agreed to in writing, software
10045  * distributed under the License is distributed on an "AS IS" BASIS,
10046  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10047  *
10048  * See the License for the specific language governing permissions and
10049  * limitations under the License.
10050  */
10051 
10052 /* !depends 
10053 MathUtils.js
10054 HebrewCal.js
10055 RataDie.js
10056 */
10057 
10058 
10059 /**
10060  * @class
10061  * Construct a new Hebrew RD date number object. The constructor parameters can 
10062  * contain any of the following properties:
10063  * 
10064  * <ul>
10065  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10066  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
10067  * 
10068  * <li><i>julianday</i> - sets the time of this instance according to the given
10069  * Julian Day instance or the Julian Day given as a float
10070  * 
10071  * <li><i>year</i> - any integer, including 0
10072  * 
10073  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10074  * 
10075  * <li><i>day</i> - 1 to 31
10076  * 
10077  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10078  * is always done with an unambiguous 24 hour representation
10079  * 
10080  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
10081  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
10082  * 
10083  * <li><i>minute</i> - 0 to 59
10084  * 
10085  * <li><i>second</i> - 0 to 59
10086  * 
10087  * <li><i>millisecond</i> - 0 to 999
10088  * 
10089  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10090  * </ul>
10091  *
10092  * If the constructor is called with another Hebrew date instance instead of
10093  * a parameter block, the other instance acts as a parameter block and its
10094  * settings are copied into the current instance.<p>
10095  * 
10096  * If the constructor is called with no arguments at all or if none of the 
10097  * properties listed above are present, then the RD is calculate based on 
10098  * the current date at the time of instantiation. <p>
10099  * 
10100  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
10101  * specified in the params, it is assumed that they have the smallest possible
10102  * value in the range for the property (zero or one).<p>
10103  * 
10104  * 
10105  * @private
10106  * @constructor
10107  * @extends RataDie
10108  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew RD date
10109  */
10110 var HebrewRataDie = function(params) {
10111 	this.cal = params && params.cal || new HebrewCal();
10112 	this.rd = undefined;
10113 	RataDie.call(this, params);
10114 };
10115 
10116 HebrewRataDie.prototype = new RataDie();
10117 HebrewRataDie.prototype.parent = RataDie;
10118 HebrewRataDie.prototype.constructor = HebrewRataDie;
10119 
10120 /**
10121  * The difference between a zero Julian day and the first day of the Hebrew 
10122  * calendar: sunset on Monday, Tishri 1, 1 = September 7, 3760 BC Gregorian = JD 347997.25
10123  * @private
10124  * @const
10125  * @type number
10126  */
10127 HebrewRataDie.prototype.epoch = 347997.25;
10128 
10129 /**
10130  * the cumulative lengths of each month for a non-leap year, without new years corrections
10131  * @private
10132  * @const
10133  * @type Array.<number>
10134  */
10135 HebrewRataDie.cumMonthLengths = [
10136 	176,  /* Nisan */
10137 	206,  /* Iyyar */
10138 	235,  /* Sivan */
10139 	265,  /* Tammuz */
10140 	294,  /* Av */
10141 	324,  /* Elul */
10142 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10143 	30,   /* Heshvan */
10144 	59,   /* Kislev */
10145 	88,   /* Teveth */
10146 	117,  /* Shevat */
10147 	147   /* Adar I */
10148 ];
10149 
10150 /**
10151  * the cumulative lengths of each month for a leap year, without new years corrections 
10152  * @private
10153  * @const
10154  * @type Array.<number>
10155  */
10156 HebrewRataDie.cumMonthLengthsLeap = [
10157 	206,  /* Nisan */
10158 	236,  /* Iyyar */
10159 	265,  /* Sivan */
10160 	295,  /* Tammuz */
10161 	324,  /* Av */
10162 	354,  /* Elul */
10163 	0,    /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10164 	30,   /* Heshvan */
10165 	59,   /* Kislev */
10166 	88,   /* Teveth */
10167 	117,  /* Shevat */
10168 	147,  /* Adar I */
10169 	177   /* Adar II */
10170 ];
10171 
10172 /**
10173  * Calculate the Rata Die (fixed day) number of the given date from the
10174  * date components.
10175  * 
10176  * @private
10177  * @param {Object} date the date components to calculate the RD from
10178  */
10179 HebrewRataDie.prototype._setDateComponents = function(date) {
10180 	var elapsed = HebrewCal.elapsedDays(date.year);
10181 	var days = elapsed +
10182 		HebrewCal.newYearsCorrection(date.year, elapsed) +
10183 		date.day - 1;
10184 	var sum = 0, table;
10185 	
10186 	//console.log("getRataDie: converting " +  JSON.stringify(date));
10187 	//console.log("getRataDie: days is " +  days);
10188 	//console.log("getRataDie: new years correction is " +  HebrewCal.newYearsCorrection(date.year, elapsed));
10189 	
10190 	table = this.cal.isLeapYear(date.year) ? 
10191 		HebrewRataDie.cumMonthLengthsLeap :
10192 		HebrewRataDie.cumMonthLengths;
10193 	sum = table[date.month-1];
10194 	
10195 	// gets cumulative without correction, so now add in the correction
10196 	if ((date.month < 7 || date.month > 8) && HebrewCal.longHeshvan(date.year)) {
10197 		sum++;
10198 	}
10199 	if ((date.month < 7 || date.month > 9) && HebrewCal.longKislev(date.year)) {
10200 		sum++;
10201 	}
10202 	// console.log("getRataDie: cum days is now " +  sum);
10203 	
10204 	days += sum;
10205 	
10206 	// the date starts at sunset, which we take as 18:00, so the hours from
10207 	// midnight to 18:00 are on the current Gregorian day, and the hours from
10208 	// 18:00 to midnight are on the previous Gregorian day. So to calculate the 
10209 	// number of hours into the current day that this time represents, we have
10210 	// to count from 18:00 to midnight first, and add in 6 hours if the time is
10211 	// less than 18:00
10212 	var minute, second, millisecond;
10213 	
10214 	if (typeof(date.parts) !== 'undefined') {
10215 		// The parts (halaqim) of the hour. This can be a number from 0 to 1079.
10216 		var parts = parseInt(date.parts, 10);
10217 		var seconds = parseInt(parts, 10) * 3.333333333333;
10218 		minute = Math.floor(seconds / 60);
10219 		seconds -= minute * 60;
10220 		second = Math.floor(seconds);
10221 		millisecond = (seconds - second);	
10222 	} else {
10223 		minute = parseInt(date.minute, 10) || 0;
10224 		second = parseInt(date.second, 10) || 0;
10225 		millisecond = parseInt(date.millisecond, 10) || 0;
10226 	}
10227 		
10228 	var time;
10229 	if (date.hour >= 18) {
10230 		time = ((date.hour - 18 || 0) * 3600000 +
10231 			(minute || 0) * 60000 +
10232 			(second || 0) * 1000 +
10233 			(millisecond || 0)) / 
10234 			86400000;
10235 	} else {
10236 		time = 0.25 +	// 6 hours from 18:00 to midnight on the previous gregorian day
10237 				((date.hour || 0) * 3600000 +
10238 				(minute || 0) * 60000 +
10239 				(second || 0) * 1000 +
10240 				(millisecond || 0)) / 
10241 				86400000;
10242 	}
10243 	
10244 	//console.log("getRataDie: rd is " +  (days + time));
10245 	this.rd = days + time;
10246 };
10247 	
10248 /**
10249  * Return the rd number of the particular day of the week on or before the 
10250  * given rd. eg. The Sunday on or before the given rd.
10251  * @private
10252  * @param {number} rd the rata die date of the reference date
10253  * @param {number} dayOfWeek the day of the week that is being sought relative 
10254  * to the current date
10255  * @return {number} the rd of the day of the week
10256  */
10257 HebrewRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
10258 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek + 1, 7);
10259 };
10260 
10261 
10262 
10263 /*< HebrewDate.js */
10264 /*
10265  * HebrewDate.js - Represent a date in the Hebrew calendar
10266  * 
10267  * Copyright © 2012-2015, JEDLSoft
10268  *
10269  * Licensed under the Apache License, Version 2.0 (the "License");
10270  * you may not use this file except in compliance with the License.
10271  * You may obtain a copy of the License at
10272  *
10273  *     http://www.apache.org/licenses/LICENSE-2.0
10274  *
10275  * Unless required by applicable law or agreed to in writing, software
10276  * distributed under the License is distributed on an "AS IS" BASIS,
10277  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10278  *
10279  * See the License for the specific language governing permissions and
10280  * limitations under the License.
10281  */
10282 
10283 /* !depends 
10284 ilib.js
10285 Locale.js
10286 LocaleInfo.js
10287 TimeZone.js
10288 IDate.js
10289 MathUtils.js
10290 Calendar.js
10291 HebrewCal.js
10292 HebrewRataDie.js
10293 */
10294 
10295 
10296 
10297 
10298 /**
10299  * @class
10300  * Construct a new civil Hebrew date object. The constructor can be called
10301  * with a params object that can contain the following properties:<p>
10302  * 
10303  * <ul>
10304  * <li><i>julianday</i> - the Julian Day to set into this date
10305  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
10306  * <li><i>month</i> - 1 to 12, where 1 means Nisan, 2 means Iyyar, etc.
10307  * <li><i>day</i> - 1 to 30
10308  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10309  * is always done with an unambiguous 24 hour representation
10310  * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 
10311  * the parts or specify the minutes, seconds, and milliseconds, but not both. 
10312  * <li><i>minute</i> - 0 to 59
10313  * <li><i>second</i> - 0 to 59
10314  * <li><i>millisecond</i> - 0 to 999
10315  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
10316  * of this julian date. The date/time is kept in the local time. The time zone
10317  * is used later if this date is formatted according to a different time zone and
10318  * the difference has to be calculated, or when the date format has a time zone
10319  * component in it.
10320  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
10321  * given, it can be inferred from this locale. For locales that span multiple
10322  * time zones, the one with the largest population is chosen as the one that 
10323  * represents the locale. 
10324  * 
10325  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10326  * </ul>
10327  * 
10328  * If called with another Hebrew date argument, the date components of the given
10329  * date are copied into the current one.<p>
10330  * 
10331  * If the constructor is called with no arguments at all or if none of the 
10332  * properties listed above 
10333  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
10334  * components are 
10335  * filled in with the current date at the time of instantiation. Note that if
10336  * you do not give the time zone when defaulting to the current time and the 
10337  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
10338  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
10339  * Mean Time").<p>
10340  * 
10341  * 
10342  * @constructor
10343  * @extends IDate
10344  * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew date
10345  */
10346 var HebrewDate = function(params) {
10347 	this.cal = new HebrewCal();
10348 	
10349 	if (params) {
10350 		if (params.timezone) {
10351 			this.timezone = params.timezone;
10352 		}
10353 		if (params.locale) {
10354 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
10355 			if (!this.timezone) {
10356 				var li = new LocaleInfo(this.locale);
10357 				this.timezone = li.getTimeZone(); 
10358 			}
10359 		}
10360 
10361 		if (params.year || params.month || params.day || params.hour ||
10362 				params.minute || params.second || params.millisecond || params.parts ) {
10363 			/**
10364 			 * Year in the Hebrew calendar.
10365 			 * @type number
10366 			 */
10367 			this.year = parseInt(params.year, 10) || 0;
10368 
10369 			/**
10370 			 * The month number, ranging from 1 to 13.
10371 			 * @type number
10372 			 */
10373 			this.month = parseInt(params.month, 10) || 1;
10374 
10375 			/**
10376 			 * The day of the month. This ranges from 1 to 30.
10377 			 * @type number
10378 			 */
10379 			this.day = parseInt(params.day, 10) || 1;
10380 			
10381 			/**
10382 			 * The hour of the day. This can be a number from 0 to 23, as times are
10383 			 * stored unambiguously in the 24-hour clock.
10384 			 * @type number
10385 			 */
10386 			this.hour = parseInt(params.hour, 10) || 0;
10387 
10388 			if (typeof(params.parts) !== 'undefined') {
10389 				/**
10390 				 * The parts (halaqim) of the hour. This can be a number from 0 to 1079.
10391 				 * @type number
10392 				 */
10393 				this.parts = parseInt(params.parts, 10);
10394 				var seconds = parseInt(params.parts, 10) * 3.333333333333;
10395 				this.minute = Math.floor(seconds / 60);
10396 				seconds -= this.minute * 60;
10397 				this.second = Math.floor(seconds);
10398 				this.millisecond = (seconds - this.second);	
10399 			} else {
10400 				/**
10401 				 * The minute of the hours. Ranges from 0 to 59.
10402 				 * @type number
10403 				 */
10404 				this.minute = parseInt(params.minute, 10) || 0;
10405 	
10406 				/**
10407 				 * The second of the minute. Ranges from 0 to 59.
10408 				 * @type number
10409 				 */
10410 				this.second = parseInt(params.second, 10) || 0;
10411 	
10412 				/**
10413 				 * The millisecond of the second. Ranges from 0 to 999.
10414 				 * @type number
10415 				 */
10416 				this.millisecond = parseInt(params.millisecond, 10) || 0;
10417 			}
10418 				
10419 			/**
10420 			 * The day of the year. Ranges from 1 to 383.
10421 			 * @type number
10422 			 */
10423 			this.dayOfYear = parseInt(params.dayOfYear, 10);
10424 			
10425 			if (typeof(params.dst) === 'boolean') {
10426 				this.dst = params.dst;
10427 			}
10428 			
10429 			this.rd = this.newRd(this);
10430 			
10431 			// add the time zone offset to the rd to convert to UTC
10432 			if (!this.tz) {
10433 				this.tz = new TimeZone({id: this.timezone});
10434 			}
10435 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
10436 			// are set in order to figure out which time zone rules apply and 
10437 			// what the offset is at that point in the year
10438 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
10439 			if (this.offset !== 0) {
10440 				this.rd = this.newRd({
10441 					rd: this.rd.getRataDie() - this.offset
10442 				});
10443 			}
10444 		}
10445 	} 
10446 	
10447 	if (!this.rd) {
10448 		this.rd = this.newRd(params);
10449 		this._calcDateComponents();
10450 	}
10451 };
10452 
10453 HebrewDate.prototype = new IDate({noinstance: true});
10454 HebrewDate.prototype.parent = IDate;
10455 HebrewDate.prototype.constructor = HebrewDate;
10456 
10457 /**
10458  * the cumulative lengths of each month for a non-leap year, without new years corrections,
10459  * that can be used in reverse to map days to months
10460  * @private
10461  * @const
10462  * @type Array.<number>
10463  */
10464 HebrewDate.cumMonthLengthsReverse = [
10465 //  [days, monthnumber],                                                
10466 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10467 	[30,  8],  /* Heshvan */
10468 	[59,  9],  /* Kislev */
10469 	[88,  10], /* Teveth */
10470 	[117, 11], /* Shevat */
10471 	[147, 12], /* Adar I */
10472 	[176, 1],  /* Nisan */
10473 	[206, 2],  /* Iyyar */
10474 	[235, 3],  /* Sivan */
10475 	[265, 4],  /* Tammuz */
10476 	[294, 5],  /* Av */
10477 	[324, 6],  /* Elul */
10478 	[354, 7]   /* end of year sentinel value */
10479 ];
10480 
10481 /**
10482  * the cumulative lengths of each month for a leap year, without new years corrections
10483  * that can be used in reverse to map days to months 
10484  * 
10485  * @private
10486  * @const
10487  * @type Array.<number>
10488  */
10489 HebrewDate.cumMonthLengthsLeapReverse = [
10490 //  [days, monthnumber],                                                
10491 	[0,   7],  /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */
10492 	[30,  8],  /* Heshvan */
10493 	[59,  9],  /* Kislev */
10494 	[88,  10], /* Teveth */
10495 	[117, 11], /* Shevat */
10496 	[147, 12], /* Adar I */
10497 	[177, 13], /* Adar II */
10498 	[206, 1],  /* Nisan */
10499 	[236, 2],  /* Iyyar */
10500 	[265, 3],  /* Sivan */
10501 	[295, 4],  /* Tammuz */
10502 	[324, 5],  /* Av */
10503 	[354, 6],  /* Elul */
10504 	[384, 7]   /* end of year sentinel value */
10505 ];
10506 
10507 /**
10508  * Number of days difference between RD 0 of the Hebrew calendar 
10509  * (Jan 1, 1 Gregorian = JD 1721057.5) and RD 0 of the Hebrew calendar
10510  * (September 7, -3760 Gregorian = JD 347997.25)
10511  * @private
10512  * @const
10513  * @type number
10514  */
10515 HebrewDate.GregorianDiff = 1373060.25;
10516 
10517 /**
10518  * Return a new RD for this date type using the given params.
10519  * @private
10520  * @param {Object=} params the parameters used to create this rata die instance
10521  * @returns {RataDie} the new RD instance for the given params
10522  */
10523 HebrewDate.prototype.newRd = function (params) {
10524 	return new HebrewRataDie(params);
10525 };
10526 
10527 /**
10528  * Return the year for the given RD
10529  * @protected
10530  * @param {number} rd RD to calculate from 
10531  * @returns {number} the year for the RD
10532  */
10533 HebrewDate.prototype._calcYear = function(rd) {
10534 	var year, approximation, nextNewYear;
10535 	
10536 	// divide by the average number of days per year in the Hebrew calendar
10537 	// to approximate the year, then tweak it to get the real year
10538 	approximation = Math.floor(rd / 365.246822206) + 1;
10539 	
10540 	// console.log("HebrewDate._calcYear: approx is " + approximation);
10541 	
10542 	// search forward from approximation-1 for the year that actually contains this rd
10543 	year = approximation;
10544 	nextNewYear = HebrewCal.newYear(year);
10545 	while (rd >= nextNewYear) {
10546 		year++;
10547 		nextNewYear = HebrewCal.newYear(year);
10548 	}
10549 	return year - 1;
10550 };
10551 
10552 /**
10553  * Calculate date components for the given RD date.
10554  * @protected
10555  */
10556 HebrewDate.prototype._calcDateComponents = function () {
10557 	var remainder,
10558 		i,
10559 		table,
10560 		target,
10561 		rd = this.rd.getRataDie();
10562 	
10563 	// console.log("HebrewDate.calcComponents: calculating for rd " + rd);
10564 
10565 	if (typeof(this.offset) === "undefined") {
10566 		this.year = this._calcYear(rd);
10567 		
10568 		// now offset the RD by the time zone, then recalculate in case we were 
10569 		// near the year boundary
10570 		if (!this.tz) {
10571 			this.tz = new TimeZone({id: this.timezone});
10572 		}
10573 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
10574 	}
10575 
10576 	if (this.offset !== 0) {
10577 		rd += this.offset;
10578 		this.year = this._calcYear(rd);
10579 	}
10580 	
10581 	// console.log("HebrewDate.calcComponents: year is " + this.year + " with starting rd " + thisNewYear);
10582 	
10583 	remainder = rd - HebrewCal.newYear(this.year);
10584 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
10585 
10586 	// take out new years corrections so we get the right month when we look it up in the table
10587 	if (remainder >= 59) {
10588 		if (remainder >= 88) {
10589 			if (HebrewCal.longKislev(this.year)) {
10590 				remainder--;
10591 			}
10592 		}
10593 		if (HebrewCal.longHeshvan(this.year)) {
10594 			remainder--;
10595 		}
10596 	}
10597 	
10598 	// console.log("HebrewDate.calcComponents: after new years corrections, remainder is " + remainder);
10599 	
10600 	table = this.cal.isLeapYear(this.year) ? 
10601 			HebrewDate.cumMonthLengthsLeapReverse :
10602 			HebrewDate.cumMonthLengthsReverse;
10603 	
10604 	i = 0;
10605 	target = Math.floor(remainder);
10606 	while (i+1 < table.length && target >= table[i+1][0]) {
10607 		i++;
10608 	}
10609 	
10610 	this.month = table[i][1];
10611 	// console.log("HebrewDate.calcComponents: remainder is " + remainder);
10612 	remainder -= table[i][0];
10613 	
10614 	// console.log("HebrewDate.calcComponents: month is " + this.month + " and remainder is " + remainder);
10615 	
10616 	this.day = Math.floor(remainder);
10617 	remainder -= this.day;
10618 	this.day++; // days are 1-based
10619 	
10620 	// console.log("HebrewDate.calcComponents: day is " + this.day + " and remainder is " + remainder);
10621 
10622 	// now convert to milliseconds for the rest of the calculation
10623 	remainder = Math.round(remainder * 86400000);
10624 	
10625 	this.hour = Math.floor(remainder/3600000);
10626 	remainder -= this.hour * 3600000;
10627 	
10628 	// the hours from 0 to 6 are actually 18:00 to midnight of the previous
10629 	// gregorian day, so we have to adjust for that
10630 	if (this.hour >= 6) {
10631 		this.hour -= 6;
10632 	} else {
10633 		this.hour += 18;
10634 	}
10635 		
10636 	this.minute = Math.floor(remainder/60000);
10637 	remainder -= this.minute * 60000;
10638 	
10639 	this.second = Math.floor(remainder/1000);
10640 	remainder -= this.second * 1000;
10641 	
10642 	this.millisecond = Math.floor(remainder);
10643 };
10644 
10645 /**
10646  * Return the day of the week of this date. The day of the week is encoded
10647  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
10648  * 
10649  * @return {number} the day of the week
10650  */
10651 HebrewDate.prototype.getDayOfWeek = function() {
10652 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
10653 	return MathUtils.mod(rd+1, 7);
10654 };
10655 
10656 /**
10657  * Get the Halaqim (parts) of an hour. There are 1080 parts in an hour, which means
10658  * each part is 3.33333333 seconds long. This means the number returned may not
10659  * be an integer.
10660  * 
10661  * @return {number} the halaqim parts of the current hour
10662  */
10663 HebrewDate.prototype.getHalaqim = function() {
10664 	if (this.parts < 0) {
10665 		// convert to ms first, then to parts
10666 		var h = this.minute * 60000 + this.second * 1000 + this.millisecond;
10667 		this.parts = (h * 0.0003);
10668 	}
10669 	return this.parts;
10670 };
10671 
10672 /**
10673  * Return the rd number of the first Sunday of the given ISO year.
10674  * @protected
10675  * @return the rd of the first Sunday of the ISO year
10676  */
10677 HebrewDate.prototype.firstSunday = function (year) {
10678 	var tishri1 = this.newRd({
10679 		year: year,
10680 		month: 7,
10681 		day: 1,
10682 		hour: 18,
10683 		minute: 0,
10684 		second: 0,
10685 		millisecond: 0,
10686 		cal: this.cal
10687 	});
10688 	var firstThu = this.newRd({
10689 		rd: tishri1.onOrAfter(4),
10690 		cal: this.cal
10691 	});
10692 	return firstThu.before(0);
10693 };
10694 
10695 /**
10696  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
10697  * 385, regardless of months or weeks, etc. That is, Tishri 1st is day 1, and 
10698  * Elul 29 is 385 for a leap year with a long Heshvan and long Kislev.
10699  * @return {number} the ordinal day of the year
10700  */
10701 HebrewDate.prototype.getDayOfYear = function() {
10702 	var table = this.cal.isLeapYear(this.year) ? 
10703 				HebrewRataDie.cumMonthLengthsLeap : 
10704 				HebrewRataDie.cumMonthLengths;
10705 	var days = table[this.month-1];
10706 	if ((this.month < 7 || this.month > 8) && HebrewCal.longHeshvan(this.year)) {
10707 		days++;
10708 	}
10709 	if ((this.month < 7 || this.month > 9) && HebrewCal.longKislev(this.year)) {
10710 		days++;
10711 	}
10712 
10713 	return days + this.day;
10714 };
10715 
10716 /**
10717  * Return the ordinal number of the week within the month. The first week of a month is
10718  * the first one that contains 4 or more days in that month. If any days precede this
10719  * first week, they are marked as being in week 0. This function returns values from 0
10720  * through 6.<p>
10721  * 
10722  * The locale is a required parameter because different locales that use the same 
10723  * Hebrew calendar consider different days of the week to be the beginning of
10724  * the week. This can affect the week of the month in which some days are located.
10725  * 
10726  * @param {Locale|string} locale the locale or locale spec to use when figuring out 
10727  * the first day of the week
10728  * @return {number} the ordinal number of the week within the current month
10729  */
10730 HebrewDate.prototype.getWeekOfMonth = function(locale) {
10731 	var li = new LocaleInfo(locale),
10732 		first = this.newRd({
10733 			year: this.year,
10734 			month: this.month,
10735 			day: 1,
10736 			hour: 18,
10737 			minute: 0,
10738 			second: 0,
10739 			millisecond: 0
10740 		}),
10741 		rd = this.rd.getRataDie(),
10742 		weekStart = first.onOrAfter(li.getFirstDayOfWeek());
10743 	
10744 	if (weekStart - first.getRataDie() > 3) {
10745 		// if the first week has 4 or more days in it of the current month, then consider
10746 		// that week 1. Otherwise, it is week 0. To make it week 1, move the week start
10747 		// one week earlier.
10748 		weekStart -= 7;
10749 	}
10750 	return (rd < weekStart) ? 0 : Math.floor((rd - weekStart) / 7) + 1;
10751 };
10752 
10753 /**
10754  * Return the era for this date as a number. The value for the era for Hebrew 
10755  * calendars is -1 for "before the Hebrew era" and 1 for "the Hebrew era". 
10756  * Hebrew era dates are any date after Tishri 1, 1, which is the same as
10757  * September 7, 3760 BC in the Gregorian calendar. 
10758  * 
10759  * @return {number} 1 if this date is in the Hebrew era, -1 if it is before the 
10760  * Hebrew era 
10761  */
10762 HebrewDate.prototype.getEra = function() {
10763 	return (this.year < 1) ? -1 : 1;
10764 };
10765 
10766 /**
10767  * Return the name of the calendar that governs this date.
10768  * 
10769  * @return {string} a string giving the name of the calendar
10770  */
10771 HebrewDate.prototype.getCalendar = function() {
10772 	return "hebrew";
10773 };
10774 
10775 // register with the factory method
10776 IDate._constructors["hebrew"] = HebrewDate;
10777 
10778 
10779 
10780 /*< IslamicCal.js */
10781 /*
10782  * islamic.js - Represent a Islamic calendar object.
10783  * 
10784  * Copyright © 2012-2015, JEDLSoft
10785  *
10786  * Licensed under the Apache License, Version 2.0 (the "License");
10787  * you may not use this file except in compliance with the License.
10788  * You may obtain a copy of the License at
10789  *
10790  *     http://www.apache.org/licenses/LICENSE-2.0
10791  *
10792  * Unless required by applicable law or agreed to in writing, software
10793  * distributed under the License is distributed on an "AS IS" BASIS,
10794  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10795  *
10796  * See the License for the specific language governing permissions and
10797  * limitations under the License.
10798  */
10799 
10800 
10801 /* !depends 
10802 ilib.js
10803 Calendar.js 
10804 MathUtils.js 
10805 */
10806 
10807 
10808 /**
10809  * @class
10810  * Construct a new Islamic calendar object. This class encodes information about
10811  * the civil Islamic calendar. The civil Islamic calendar is a tabular islamic 
10812  * calendar where the dates are calculated by arithmetic rules. This differs from 
10813  * the religious Islamic calendar which is used to mark the beginning of particular 
10814  * holidays. The religious calendar depends on the first sighting of the new 
10815  * crescent moon to determine the first day of the new month. Because humans and 
10816  * weather are both involved, the actual time of sighting varies, so it is not 
10817  * really possible to precalculate the religious calendar. Certain groups, such 
10818  * as the Islamic Society of North America, decreed in in 2007 that they will use
10819  * a calendar based on calculations rather than observations to determine the 
10820  * beginning of lunar months, and therefore the dates of holidays.<p>
10821  * 
10822  * 
10823  * @constructor
10824  * @extends Calendar
10825  */
10826 var IslamicCal = function() {
10827 	this.type = "islamic";
10828 };
10829 
10830 /**
10831  * the lengths of each month 
10832  * @private
10833  * @const
10834  * @type Array.<number>
10835  */
10836 IslamicCal.monthLengths = [
10837 	30,  /* Muharram */
10838 	29,  /* Saffar */
10839 	30,  /* Rabi'I */
10840 	29,  /* Rabi'II */
10841 	30,  /* Jumada I */
10842 	29,  /* Jumada II */
10843 	30,  /* Rajab */
10844 	29,  /* Sha'ban */
10845 	30,  /* Ramadan */
10846 	29,  /* Shawwal */
10847 	30,  /* Dhu al-Qa'da */
10848 	29   /* Dhu al-Hijja */
10849 ];
10850 
10851 
10852 /**
10853  * Return the number of months in the given year. The number of months in a year varies
10854  * for luni-solar calendars because in some years, an extra month is needed to extend the 
10855  * days in a year to an entire solar year. The month is represented as a 1-based number
10856  * where 1=first month, 2=second month, etc.
10857  * 
10858  * @param {number} year a year for which the number of months is sought
10859  */
10860 IslamicCal.prototype.getNumMonths = function(year) {
10861 	return 12;
10862 };
10863 
10864 /**
10865  * Return the number of days in a particular month in a particular year. This function
10866  * can return a different number for a month depending on the year because of things
10867  * like leap years.
10868  *
10869  * @param {number} month the month for which the length is sought
10870  * @param {number} year the year within which that month can be found
10871  * @return {number} the number of days within the given month in the given year
10872  */
10873 IslamicCal.prototype.getMonLength = function(month, year) {
10874 	if (month !== 12) {
10875 		return IslamicCal.monthLengths[month-1];
10876 	} else {
10877 		return this.isLeapYear(year) ? 30 : 29;
10878 	}
10879 };
10880 
10881 /**
10882  * Return true if the given year is a leap year in the Islamic calendar.
10883  * The year parameter may be given as a number, or as a IslamicDate object.
10884  * @param {number} year the year for which the leap year information is being sought
10885  * @return {boolean} true if the given year is a leap year
10886  */
10887 IslamicCal.prototype.isLeapYear = function(year) {
10888 	return (MathUtils.mod((14 + 11 * year), 30) < 11);
10889 };
10890 
10891 /**
10892  * Return the type of this calendar.
10893  * 
10894  * @return {string} the name of the type of this calendar 
10895  */
10896 IslamicCal.prototype.getType = function() {
10897 	return this.type;
10898 };
10899 
10900 /**
10901  * Return a date instance for this calendar type using the given
10902  * options.
10903  * @param {Object} options options controlling the construction of 
10904  * the date instance
10905  * @return {IslamicDate} a date appropriate for this calendar type
10906  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
10907  */
10908 IslamicCal.prototype.newDateInstance = function (options) {
10909 		return new IslamicDate(options);
10910 };
10911 
10912 /*register this calendar for the factory method */
10913 Calendar._constructors["islamic"] = IslamicCal;
10914 
10915 
10916 /*< IslamicRataDie.js */
10917 /*
10918  * IslamicRataDie.js - Represent an RD date in the Islamic calendar
10919  * 
10920  * Copyright © 2012-2015, JEDLSoft
10921  *
10922  * Licensed under the Apache License, Version 2.0 (the "License");
10923  * you may not use this file except in compliance with the License.
10924  * You may obtain a copy of the License at
10925  *
10926  *     http://www.apache.org/licenses/LICENSE-2.0
10927  *
10928  * Unless required by applicable law or agreed to in writing, software
10929  * distributed under the License is distributed on an "AS IS" BASIS,
10930  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10931  *
10932  * See the License for the specific language governing permissions and
10933  * limitations under the License.
10934  */
10935 
10936 /* !depends 
10937 IslamicCal.js
10938 RataDie.js
10939 */
10940 
10941 
10942 /**
10943  * @class
10944  * Construct a new Islamic RD date number object. The constructor parameters can 
10945  * contain any of the following properties:
10946  * 
10947  * <ul>
10948  * <li><i>unixtime<i> - sets the time of this instance according to the given 
10949  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
10950  * 
10951  * <li><i>julianday</i> - sets the time of this instance according to the given
10952  * Julian Day instance or the Julian Day given as a float
10953  * 
10954  * <li><i>year</i> - any integer, including 0
10955  * 
10956  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
10957  * 
10958  * <li><i>day</i> - 1 to 31
10959  * 
10960  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
10961  * is always done with an unambiguous 24 hour representation
10962  * 
10963  * <li><i>minute</i> - 0 to 59
10964  * 
10965  * <li><i>second</i> - 0 to 59
10966  * 
10967  * <li><i>millisecond</i> - 0 to 999
10968  * 
10969  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
10970  * </ul>
10971  *
10972  * If the constructor is called with another Islamic date instance instead of
10973  * a parameter block, the other instance acts as a parameter block and its
10974  * settings are copied into the current instance.<p>
10975  * 
10976  * If the constructor is called with no arguments at all or if none of the 
10977  * properties listed above are present, then the RD is calculate based on 
10978  * the current date at the time of instantiation. <p>
10979  * 
10980  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
10981  * specified in the params, it is assumed that they have the smallest possible
10982  * value in the range for the property (zero or one).<p>
10983  * 
10984  * 
10985  * @private
10986  * @constructor
10987  * @extends RataDie
10988  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic RD date
10989  */
10990 var IslamicRataDie = function(params) {
10991 	this.cal = params && params.cal || new IslamicCal();
10992 	this.rd = undefined;
10993 	RataDie.call(this, params);
10994 };
10995 
10996 IslamicRataDie.prototype = new RataDie();
10997 IslamicRataDie.prototype.parent = RataDie;
10998 IslamicRataDie.prototype.constructor = IslamicRataDie;
10999 
11000 /**
11001  * The difference between a zero Julian day and the first Islamic date
11002  * of Friday, July 16, 622 CE Julian. 
11003  * @private
11004  * @const
11005  * @type number
11006  */
11007 IslamicRataDie.prototype.epoch = 1948439.5;
11008 
11009 /**
11010  * Calculate the Rata Die (fixed day) number of the given date from the
11011  * date components.
11012  *
11013  * @protected
11014  * @param {Object} date the date components to calculate the RD from
11015  */
11016 IslamicRataDie.prototype._setDateComponents = function(date) {
11017 	var days = (date.year - 1) * 354 +
11018 		Math.ceil(29.5 * (date.month - 1)) +
11019 		date.day +
11020 		Math.floor((3 + 11 * date.year) / 30) - 1;
11021 	var time = (date.hour * 3600000 +
11022 		date.minute * 60000 +
11023 		date.second * 1000 +
11024 		date.millisecond) / 
11025 		86400000; 
11026 	
11027 	//console.log("getRataDie: converting " +  JSON.stringify(date));
11028 	//console.log("getRataDie: days is " +  days);
11029 	//console.log("getRataDie: time is " +  time);
11030 	//console.log("getRataDie: rd is " +  (days + time));
11031 
11032 	this.rd = days + time;
11033 };
11034 	
11035 
11036 /*< IslamicDate.js */
11037 /*
11038  * islamicDate.js - Represent a date in the Islamic calendar
11039  * 
11040  * Copyright © 2012-2015, JEDLSoft
11041  *
11042  * Licensed under the Apache License, Version 2.0 (the "License");
11043  * you may not use this file except in compliance with the License.
11044  * You may obtain a copy of the License at
11045  *
11046  *     http://www.apache.org/licenses/LICENSE-2.0
11047  *
11048  * Unless required by applicable law or agreed to in writing, software
11049  * distributed under the License is distributed on an "AS IS" BASIS,
11050  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11051  *
11052  * See the License for the specific language governing permissions and
11053  * limitations under the License.
11054  */
11055 
11056 /* !depends 
11057 ilib.js
11058 Locale.js
11059 LocaleInfo.js
11060 TimeZone.js
11061 IDate.js
11062 MathUtils.js
11063 SearchUtils.js
11064 Calendar.js
11065 IslamicCal.js
11066 IslamicRataDie.js
11067 */
11068 
11069 
11070 
11071 
11072 /**
11073  * @class
11074  * Construct a new civil Islamic date object. The constructor can be called
11075  * with a params object that can contain the following properties:<p>
11076  * 
11077  * <ul>
11078  * <li><i>julianday</i> - the Julian Day to set into this date
11079  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero year
11080  * <li><i>month</i> - 1 to 12, where 1 means Muharram, 2 means Saffar, etc.
11081  * <li><i>day</i> - 1 to 30
11082  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11083  * is always done with an unambiguous 24 hour representation
11084  * <li><i>minute</i> - 0 to 59
11085  * <li><i>second</i> - 0 to 59
11086  * <li><i>millisecond</i> - 0 to 999
11087  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
11088  * of this julian date. The date/time is kept in the local time. The time zone
11089  * is used later if this date is formatted according to a different time zone and
11090  * the difference has to be calculated, or when the date format has a time zone
11091  * component in it.
11092  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
11093  * given, it can be inferred from this locale. For locales that span multiple
11094  * time zones, the one with the largest population is chosen as the one that 
11095  * represents the locale. 
11096  * 
11097  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11098  * </ul>
11099  * 
11100  * If called with another Islamic date argument, the date components of the given
11101  * date are copied into the current one.<p>
11102  * 
11103  * If the constructor is called with no arguments at all or if none of the 
11104  * properties listed above 
11105  * from <i>julianday</i> through <i>millisecond</i> are present, then the date 
11106  * components are 
11107  * filled in with the current date at the time of instantiation. Note that if
11108  * you do not give the time zone when defaulting to the current time and the 
11109  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
11110  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
11111  * Mean Time").<p>
11112  * 
11113  * 
11114  * @constructor
11115  * @extends IDate
11116  * @param {Object=} params parameters that govern the settings and behaviour of this Islamic date
11117  */
11118 var IslamicDate = function(params) {
11119 	this.cal = new IslamicCal();
11120 	
11121 	if (params) {
11122 		if (params.locale) {
11123 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
11124 			var li = new LocaleInfo(this.locale);
11125 			this.timezone = li.getTimeZone(); 
11126 		}
11127 		if (params.timezone) {
11128 			this.timezone = params.timezone;
11129 		}
11130 		
11131 		if (params.year || params.month || params.day || params.hour ||
11132 				params.minute || params.second || params.millisecond ) {
11133 			/**
11134 			 * Year in the Islamic calendar.
11135 			 * @type number
11136 			 */
11137 			this.year = parseInt(params.year, 10) || 0;
11138 
11139 			/**
11140 			 * The month number, ranging from 1 to 12 (December).
11141 			 * @type number
11142 			 */
11143 			this.month = parseInt(params.month, 10) || 1;
11144 
11145 			/**
11146 			 * The day of the month. This ranges from 1 to 30.
11147 			 * @type number
11148 			 */
11149 			this.day = parseInt(params.day, 10) || 1;
11150 			
11151 			/**
11152 			 * The hour of the day. This can be a number from 0 to 23, as times are
11153 			 * stored unambiguously in the 24-hour clock.
11154 			 * @type number
11155 			 */
11156 			this.hour = parseInt(params.hour, 10) || 0;
11157 
11158 			/**
11159 			 * The minute of the hours. Ranges from 0 to 59.
11160 			 * @type number
11161 			 */
11162 			this.minute = parseInt(params.minute, 10) || 0;
11163 
11164 			/**
11165 			 * The second of the minute. Ranges from 0 to 59.
11166 			 * @type number
11167 			 */
11168 			this.second = parseInt(params.second, 10) || 0;
11169 
11170 			/**
11171 			 * The millisecond of the second. Ranges from 0 to 999.
11172 			 * @type number
11173 			 */
11174 			this.millisecond = parseInt(params.millisecond, 10) || 0;
11175 			
11176 			/**
11177 			 * The day of the year. Ranges from 1 to 355.
11178 			 * @type number
11179 			 */
11180 			this.dayOfYear = parseInt(params.dayOfYear, 10);
11181 
11182 			if (typeof(params.dst) === 'boolean') {
11183 				this.dst = params.dst;
11184 			}
11185 			
11186 			this.rd = this.newRd(this);
11187 			
11188 			// add the time zone offset to the rd to convert to UTC
11189 			if (!this.tz) {
11190 				this.tz = new TimeZone({id: this.timezone});
11191 			}
11192 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
11193 			// are set in order to figure out which time zone rules apply and 
11194 			// what the offset is at that point in the year
11195 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
11196 			if (this.offset !== 0) {
11197 				this.rd = this.newRd({
11198 					rd: this.rd.getRataDie() - this.offset
11199 				});
11200 			}
11201 		}
11202 	}
11203 
11204 	if (!this.rd) {
11205 		this.rd = this.newRd(params);
11206 		this._calcDateComponents();
11207 	}
11208 };
11209 
11210 IslamicDate.prototype = new IDate({noinstance: true});
11211 IslamicDate.prototype.parent = IDate;
11212 IslamicDate.prototype.constructor = IslamicDate;
11213 
11214 /**
11215  * the cumulative lengths of each month, for a non-leap year 
11216  * @private
11217  * @const
11218  * @type Array.<number>
11219  */
11220 IslamicDate.cumMonthLengths = [
11221 	0,  /* Muharram */
11222 	30,  /* Saffar */
11223 	59,  /* Rabi'I */
11224 	89,  /* Rabi'II */
11225 	118,  /* Jumada I */
11226 	148,  /* Jumada II */
11227 	177,  /* Rajab */
11228 	207,  /* Sha'ban */
11229 	236,  /* Ramadan */
11230 	266,  /* Shawwal */
11231 	295,  /* Dhu al-Qa'da */
11232 	325,  /* Dhu al-Hijja */
11233 	354
11234 ];
11235 
11236 /**
11237  * Number of days difference between RD 0 of the Gregorian calendar and
11238  * RD 0 of the Islamic calendar. 
11239  * @private
11240  * @const
11241  * @type number
11242  */
11243 IslamicDate.GregorianDiff = 227015;
11244 
11245 /**
11246  * Return a new RD for this date type using the given params.
11247  * @protected
11248  * @param {Object=} params the parameters used to create this rata die instance
11249  * @returns {RataDie} the new RD instance for the given params
11250  */
11251 IslamicDate.prototype.newRd = function (params) {
11252 	return new IslamicRataDie(params);
11253 };
11254 
11255 /**
11256  * Return the year for the given RD
11257  * @protected
11258  * @param {number} rd RD to calculate from 
11259  * @returns {number} the year for the RD
11260  */
11261 IslamicDate.prototype._calcYear = function(rd) {
11262 	return Math.floor((30 * rd + 10646) / 10631);
11263 };
11264 
11265 /**
11266  * Calculate date components for the given RD date.
11267  * @protected
11268  */
11269 IslamicDate.prototype._calcDateComponents = function () {
11270 	var remainder,
11271 		rd = this.rd.getRataDie();
11272 	
11273 	this.year = this._calcYear(rd);
11274 
11275 	if (typeof(this.offset) === "undefined") {
11276 		this.year = this._calcYear(rd);
11277 		
11278 		// now offset the RD by the time zone, then recalculate in case we were 
11279 		// near the year boundary
11280 		if (!this.tz) {
11281 			this.tz = new TimeZone({id: this.timezone});
11282 		}
11283 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
11284 	}
11285 
11286 	if (this.offset !== 0) {
11287 		rd += this.offset;
11288 		this.year = this._calcYear(rd);
11289 	}
11290 
11291 	//console.log("IslamicDate.calcComponent: calculating for rd " + rd);
11292 	//console.log("IslamicDate.calcComponent: year is " + ret.year);
11293 	var yearStart = this.newRd({
11294 		year: this.year,
11295 		month: 1,
11296 		day: 1,
11297 		hour: 0,
11298 		minute: 0,
11299 		second: 0,
11300 		millisecond: 0
11301 	});
11302 	remainder = rd - yearStart.getRataDie() + 1;
11303 	
11304 	this.dayOfYear = remainder;
11305 	
11306 	//console.log("IslamicDate.calcComponent: remainder is " + remainder);
11307 	
11308 	this.month = SearchUtils.bsearch(remainder, IslamicDate.cumMonthLengths);
11309 	remainder -= IslamicDate.cumMonthLengths[this.month-1];
11310 
11311 	//console.log("IslamicDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
11312 	
11313 	this.day = Math.floor(remainder);
11314 	remainder -= this.day;
11315 
11316 	//console.log("IslamicDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
11317 
11318 	// now convert to milliseconds for the rest of the calculation
11319 	remainder = Math.round(remainder * 86400000);
11320 	
11321 	this.hour = Math.floor(remainder/3600000);
11322 	remainder -= this.hour * 3600000;
11323 	
11324 	this.minute = Math.floor(remainder/60000);
11325 	remainder -= this.minute * 60000;
11326 	
11327 	this.second = Math.floor(remainder/1000);
11328 	remainder -= this.second * 1000;
11329 	
11330 	this.millisecond = remainder;
11331 };
11332 
11333 /**
11334  * Return the day of the week of this date. The day of the week is encoded
11335  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
11336  * 
11337  * @return {number} the day of the week
11338  */
11339 IslamicDate.prototype.getDayOfWeek = function() {
11340 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
11341 	return MathUtils.mod(rd-2, 7);
11342 };
11343 
11344 /**
11345  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
11346  * 354 or 355, regardless of months or weeks, etc. That is, Muharran 1st is day 1, and 
11347  * Dhu al-Hijja 29 is 354.
11348  * @return {number} the ordinal day of the year
11349  */
11350 IslamicDate.prototype.getDayOfYear = function() {
11351 	return IslamicDate.cumMonthLengths[this.month-1] + this.day;
11352 };
11353 
11354 /**
11355  * Return the era for this date as a number. The value for the era for Islamic 
11356  * calendars is -1 for "before the Islamic era" and 1 for "the Islamic era". 
11357  * Islamic era dates are any date after Muharran 1, 1, which is the same as
11358  * July 16, 622 CE in the Gregorian calendar. 
11359  * 
11360  * @return {number} 1 if this date is in the common era, -1 if it is before the 
11361  * common era 
11362  */
11363 IslamicDate.prototype.getEra = function() {
11364 	return (this.year < 1) ? -1 : 1;
11365 };
11366 
11367 /**
11368  * Return the name of the calendar that governs this date.
11369  * 
11370  * @return {string} a string giving the name of the calendar
11371  */
11372 IslamicDate.prototype.getCalendar = function() {
11373 	return "islamic";
11374 };
11375 
11376 //register with the factory method
11377 IDate._constructors["islamic"] = IslamicDate;
11378 
11379 
11380 /*< JulianCal.js */
11381 /*
11382  * julian.js - Represent a Julian calendar object.
11383  * 
11384  * Copyright © 2012-2015, JEDLSoft
11385  *
11386  * Licensed under the Apache License, Version 2.0 (the "License");
11387  * you may not use this file except in compliance with the License.
11388  * You may obtain a copy of the License at
11389  *
11390  *     http://www.apache.org/licenses/LICENSE-2.0
11391  *
11392  * Unless required by applicable law or agreed to in writing, software
11393  * distributed under the License is distributed on an "AS IS" BASIS,
11394  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11395  *
11396  * See the License for the specific language governing permissions and
11397  * limitations under the License.
11398  */
11399 
11400 
11401 /* !depends ilib.js Calendar.js MathUtils.js */
11402 
11403 
11404 /**
11405  * @class
11406  * Construct a new Julian calendar object. This class encodes information about
11407  * a Julian calendar.<p>
11408  * 
11409  * 
11410  * @constructor
11411  * @extends Calendar
11412  */
11413 var JulianCal = function() {
11414 	this.type = "julian";
11415 };
11416 
11417 /* the lengths of each month */
11418 JulianCal.monthLengths = [
11419 	31,  /* Jan */
11420 	28,  /* Feb */
11421 	31,  /* Mar */
11422 	30,  /* Apr */
11423 	31,  /* May */
11424 	30,  /* Jun */
11425 	31,  /* Jul */
11426 	31,  /* Aug */
11427 	30,  /* Sep */
11428 	31,  /* Oct */
11429 	30,  /* Nov */
11430 	31   /* Dec */
11431 ];
11432 
11433 /**
11434  * the cumulative lengths of each month, for a non-leap year 
11435  * @private
11436  * @const
11437  * @type Array.<number>
11438  */
11439 JulianCal.cumMonthLengths = [
11440     0,   /* Jan */
11441 	31,  /* Feb */
11442 	59,  /* Mar */
11443 	90,  /* Apr */
11444 	120, /* May */
11445 	151, /* Jun */
11446 	181, /* Jul */
11447 	212, /* Aug */
11448 	243, /* Sep */
11449 	273, /* Oct */
11450 	304, /* Nov */
11451 	334, /* Dec */
11452 	365
11453 ];
11454 
11455 /**
11456  * the cumulative lengths of each month, for a leap year 
11457  * @private
11458  * @const
11459  * @type Array.<number>
11460  */
11461 JulianCal.cumMonthLengthsLeap = [
11462 	0,   /* Jan */
11463 	31,  /* Feb */
11464 	60,  /* Mar */
11465 	91,  /* Apr */
11466 	121, /* May */
11467 	152, /* Jun */
11468 	182, /* Jul */
11469 	213, /* Aug */
11470 	244, /* Sep */
11471 	274, /* Oct */
11472 	305, /* Nov */
11473 	335, /* Dec */
11474 	366
11475 ];
11476 
11477 /**
11478  * Return the number of months in the given year. The number of months in a year varies
11479  * for lunar calendars because in some years, an extra month is needed to extend the 
11480  * days in a year to an entire solar year. The month is represented as a 1-based number
11481  * where 1=Jaunary, 2=February, etc. until 12=December.
11482  * 
11483  * @param {number} year a year for which the number of months is sought
11484  */
11485 JulianCal.prototype.getNumMonths = function(year) {
11486 	return 12;
11487 };
11488 
11489 /**
11490  * Return the number of days in a particular month in a particular year. This function
11491  * can return a different number for a month depending on the year because of things
11492  * like leap years.
11493  * 
11494  * @param {number} month the month for which the length is sought
11495  * @param {number} year the year within which that month can be found
11496  * @return {number} the number of days within the given month in the given year
11497  */
11498 JulianCal.prototype.getMonLength = function(month, year) {
11499 	if (month !== 2 || !this.isLeapYear(year)) {
11500 		return JulianCal.monthLengths[month-1];
11501 	} else {
11502 		return 29;
11503 	}
11504 };
11505 
11506 /**
11507  * Return true if the given year is a leap year in the Julian calendar.
11508  * The year parameter may be given as a number, or as a JulDate object.
11509  * @param {number|JulianDate} year the year for which the leap year information is being sought
11510  * @return {boolean} true if the given year is a leap year
11511  */
11512 JulianCal.prototype.isLeapYear = function(year) {
11513 	var y = (typeof(year) === 'number' ? year : year.year);
11514 	return MathUtils.mod(y, 4) === ((year > 0) ? 0 : 3);
11515 };
11516 
11517 /**
11518  * Return the type of this calendar.
11519  * 
11520  * @return {string} the name of the type of this calendar 
11521  */
11522 JulianCal.prototype.getType = function() {
11523 	return this.type;
11524 };
11525 
11526 /**
11527  * Return a date instance for this calendar type using the given
11528  * options.
11529  * @param {Object} options options controlling the construction of 
11530  * the date instance
11531  * @return {IDate} a date appropriate for this calendar type
11532  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
11533  */
11534 JulianCal.prototype.newDateInstance = function (options) {
11535 		return new JulianDate(options);
11536 };
11537 
11538 /* register this calendar for the factory method */
11539 Calendar._constructors["julian"] = JulianCal;
11540 
11541 
11542 /*< JulianRataDie.js */
11543 /*
11544  * julianDate.js - Represent a date in the Julian calendar
11545  * 
11546  * Copyright © 2012-2015, JEDLSoft
11547  *
11548  * Licensed under the Apache License, Version 2.0 (the "License");
11549  * you may not use this file except in compliance with the License.
11550  * You may obtain a copy of the License at
11551  *
11552  *     http://www.apache.org/licenses/LICENSE-2.0
11553  *
11554  * Unless required by applicable law or agreed to in writing, software
11555  * distributed under the License is distributed on an "AS IS" BASIS,
11556  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11557  *
11558  * See the License for the specific language governing permissions and
11559  * limitations under the License.
11560  */
11561 
11562 /* !depends 
11563 JulianCal.js 
11564 RataDie.js
11565 */
11566 
11567 
11568 /**
11569  * @class
11570  * Construct a new Julian RD date number object. The constructor parameters can 
11571  * contain any of the following properties:
11572  * 
11573  * <ul>
11574  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11575  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
11576  * 
11577  * <li><i>julianday</i> - sets the time of this instance according to the given
11578  * Julian Day instance or the Julian Day given as a float
11579  * 
11580  * <li><i>year</i> - any integer, including 0
11581  * 
11582  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
11583  * 
11584  * <li><i>day</i> - 1 to 31
11585  * 
11586  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11587  * is always done with an unambiguous 24 hour representation
11588  * 
11589  * <li><i>minute</i> - 0 to 59
11590  * 
11591  * <li><i>second</i> - 0 to 59
11592  * 
11593  * <li><i>millisecond</i> - 0 to 999
11594  * 
11595  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11596  * </ul>
11597  *
11598  * If the constructor is called with another Julian date instance instead of
11599  * a parameter block, the other instance acts as a parameter block and its
11600  * settings are copied into the current instance.<p>
11601  * 
11602  * If the constructor is called with no arguments at all or if none of the 
11603  * properties listed above are present, then the RD is calculate based on 
11604  * the current date at the time of instantiation. <p>
11605  * 
11606  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
11607  * specified in the params, it is assumed that they have the smallest possible
11608  * value in the range for the property (zero or one).<p>
11609  * 
11610  * 
11611  * @private
11612  * @constructor
11613  * @extends RataDie
11614  * @param {Object=} params parameters that govern the settings and behaviour of this Julian RD date
11615  */
11616 var JulianRataDie = function(params) {
11617 	this.cal = params && params.cal || new JulianCal();
11618 	this.rd = undefined;
11619 	RataDie.call(this, params);
11620 };
11621 
11622 JulianRataDie.prototype = new RataDie();
11623 JulianRataDie.prototype.parent = RataDie;
11624 JulianRataDie.prototype.constructor = JulianRataDie;
11625 
11626 /**
11627  * The difference between a zero Julian day and the first Julian date
11628  * of Friday, July 16, 622 CE Julian. 
11629  * @private
11630  * @const
11631  * @type number
11632  */
11633 JulianRataDie.prototype.epoch = 1721422.5;
11634 
11635 /**
11636  * Calculate the Rata Die (fixed day) number of the given date from the
11637  * date components.
11638  * 
11639  * @protected
11640  * @param {Object} date the date components to calculate the RD from
11641  */
11642 JulianRataDie.prototype._setDateComponents = function(date) {
11643 	var year = date.year + ((date.year < 0) ? 1 : 0);
11644 	var years = 365 * (year - 1) + Math.floor((year-1)/4);
11645 	var dayInYear = (date.month > 1 ? JulianCal.cumMonthLengths[date.month-1] : 0) +
11646 		date.day +
11647 		(this.cal.isLeapYear(date.year) && date.month > 2 ? 1 : 0);
11648 	var rdtime = (date.hour * 3600000 +
11649 		date.minute * 60000 +
11650 		date.second * 1000 +
11651 		date.millisecond) / 
11652 		86400000;
11653 	
11654 	/*
11655 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
11656 	console.log("getRataDie: year is " +  years);
11657 	console.log("getRataDie: day in year is " +  dayInYear);
11658 	console.log("getRataDie: rdtime is " +  rdtime);
11659 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
11660 	*/
11661 	
11662 	this.rd = years + dayInYear + rdtime;
11663 };
11664 
11665 
11666 /*< JulianDate.js */
11667 /*
11668  * JulianDate.js - Represent a date in the Julian calendar
11669  * 
11670  * Copyright © 2012-2015, JEDLSoft
11671  *
11672  * Licensed under the Apache License, Version 2.0 (the "License");
11673  * you may not use this file except in compliance with the License.
11674  * You may obtain a copy of the License at
11675  *
11676  *     http://www.apache.org/licenses/LICENSE-2.0
11677  *
11678  * Unless required by applicable law or agreed to in writing, software
11679  * distributed under the License is distributed on an "AS IS" BASIS,
11680  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11681  *
11682  * See the License for the specific language governing permissions and
11683  * limitations under the License.
11684  */
11685 
11686 /* !depends 
11687 ilib.js
11688 Locale.js
11689 IDate.js 
11690 TimeZone.js
11691 Calendar.js 
11692 JulianCal.js 
11693 SearchUtils.js 
11694 MathUtils.js
11695 LocaleInfo.js 
11696 JulianRataDie.js
11697 */
11698 
11699 
11700 
11701 
11702 /**
11703  * @class
11704  * Construct a new date object for the Julian Calendar. The constructor can be called
11705  * with a parameter object that contains any of the following properties:
11706  * 
11707  * <ul>
11708  * <li><i>unixtime<i> - sets the time of this instance according to the given 
11709  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
11710  * <li><i>julianday</i> - the Julian Day to set into this date
11711  * <li><i>year</i> - any integer except 0. Years go from -1 (BCE) to 1 (CE), skipping the zero 
11712  * year which doesn't exist in the Julian calendar
11713  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
11714  * <li><i>day</i> - 1 to 31
11715  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
11716  * is always done with an unambiguous 24 hour representation
11717  * <li><i>minute</i> - 0 to 59
11718  * <li><i>second</i> - 0 to 59
11719  * <li><i>millisecond<i> - 0 to 999
11720  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
11721  * of this julian date. The date/time is kept in the local time. The time zone
11722  * is used later if this date is formatted according to a different time zone and
11723  * the difference has to be calculated, or when the date format has a time zone
11724  * component in it.
11725  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
11726  * given, it can be inferred from this locale. For locales that span multiple
11727  * time zones, the one with the largest population is chosen as the one that 
11728  * represents the locale. 
11729  * 
11730  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
11731  * </ul>
11732  * 
11733  * NB. The <a href="http://en.wikipedia.org/wiki/Julian_date">Julian Day</a> 
11734  * (JulianDay) object is a <i>different</i> object than a 
11735  * <a href="http://en.wikipedia.org/wiki/Julian_calendar">date in
11736  * the Julian calendar</a> and the two are not to be confused. The Julian Day 
11737  * object represents time as a number of whole and fractional days since the 
11738  * beginning of the epoch, whereas a date in the Julian 
11739  * calendar is a regular date that signifies year, month, day, etc. using the rules
11740  * of the Julian calendar. The naming of Julian Days and the Julian calendar are
11741  * unfortunately close, and come from history.<p>
11742  *  
11743  * If called with another Julian date argument, the date components of the given
11744  * date are copied into the current one.<p>
11745  * 
11746  * If the constructor is called with no arguments at all or if none of the 
11747  * properties listed above 
11748  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
11749  * components are 
11750  * filled in with the current date at the time of instantiation. Note that if
11751  * you do not give the time zone when defaulting to the current time and the 
11752  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
11753  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
11754  * Mean Time").<p>
11755  * 
11756  * 
11757  * @constructor
11758  * @extends IDate
11759  * @param {Object=} params parameters that govern the settings and behaviour of this Julian date
11760  */
11761 var JulianDate = function(params) {
11762 	this.cal = new JulianCal();
11763 	
11764 	if (params) {
11765 		if (params.locale) {
11766 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
11767 			var li = new LocaleInfo(this.locale);
11768 			this.timezone = li.getTimeZone(); 
11769 		}
11770 		if (params.timezone) {
11771 			this.timezone = params.timezone;
11772 		}
11773 		
11774 		if (params.year || params.month || params.day || params.hour ||
11775 				params.minute || params.second || params.millisecond ) {
11776 			/**
11777 			 * Year in the Julian calendar.
11778 			 * @type number
11779 			 */
11780 			this.year = parseInt(params.year, 10) || 0;
11781 			/**
11782 			 * The month number, ranging from 1 (January) to 12 (December).
11783 			 * @type number
11784 			 */
11785 			this.month = parseInt(params.month, 10) || 1;
11786 			/**
11787 			 * The day of the month. This ranges from 1 to 31.
11788 			 * @type number
11789 			 */
11790 			this.day = parseInt(params.day, 10) || 1;
11791 			/**
11792 			 * The hour of the day. This can be a number from 0 to 23, as times are
11793 			 * stored unambiguously in the 24-hour clock.
11794 			 * @type number
11795 			 */
11796 			this.hour = parseInt(params.hour, 10) || 0;
11797 			/**
11798 			 * The minute of the hours. Ranges from 0 to 59.
11799 			 * @type number
11800 			 */
11801 			this.minute = parseInt(params.minute, 10) || 0;
11802 			/**
11803 			 * The second of the minute. Ranges from 0 to 59.
11804 			 * @type number
11805 			 */
11806 			this.second = parseInt(params.second, 10) || 0;
11807 			/**
11808 			 * The millisecond of the second. Ranges from 0 to 999.
11809 			 * @type number
11810 			 */
11811 			this.millisecond = parseInt(params.millisecond, 10) || 0;
11812 			
11813 			/**
11814 			 * The day of the year. Ranges from 1 to 383.
11815 			 * @type number
11816 			 */
11817 			this.dayOfYear = parseInt(params.dayOfYear, 10);
11818 			
11819 			if (typeof(params.dst) === 'boolean') {
11820 				this.dst = params.dst;
11821 			}
11822 			
11823 			this.rd = this.newRd(this);
11824 			
11825 			// add the time zone offset to the rd to convert to UTC
11826 			if (!this.tz) {
11827 				this.tz = new TimeZone({id: this.timezone});
11828 			}
11829 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
11830 			// are set in order to figure out which time zone rules apply and 
11831 			// what the offset is at that point in the year
11832 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
11833 			if (this.offset !== 0) {
11834 				this.rd = this.newRd({
11835 					rd: this.rd.getRataDie() - this.offset
11836 				});
11837 			}
11838 		}
11839 	}
11840 	
11841 	if (!this.rd) {
11842 		this.rd = this.newRd(params);
11843 		this._calcDateComponents();
11844 	}
11845 };
11846 
11847 JulianDate.prototype = new IDate({noinstance: true});
11848 JulianDate.prototype.parent = IDate;
11849 JulianDate.prototype.constructor = JulianDate;
11850 
11851 /**
11852  * Return a new RD for this date type using the given params.
11853  * @protected
11854  * @param {Object=} params the parameters used to create this rata die instance
11855  * @returns {RataDie} the new RD instance for the given params
11856  */
11857 JulianDate.prototype.newRd = function (params) {
11858 	return new JulianRataDie(params);
11859 };
11860 
11861 /**
11862  * Return the year for the given RD
11863  * @protected
11864  * @param {number} rd RD to calculate from 
11865  * @returns {number} the year for the RD
11866  */
11867 JulianDate.prototype._calcYear = function(rd) {
11868 	var year = Math.floor((4*(Math.floor(rd)-1) + 1464)/1461);
11869 	
11870 	return (year <= 0) ? year - 1 : year;
11871 };
11872 
11873 /**
11874  * Calculate date components for the given RD date.
11875  * @protected
11876  */
11877 JulianDate.prototype._calcDateComponents = function () {
11878 	var remainder,
11879 		cumulative,
11880 		rd = this.rd.getRataDie();
11881 	
11882 	this.year = this._calcYear(rd);
11883 
11884 	if (typeof(this.offset) === "undefined") {
11885 		this.year = this._calcYear(rd);
11886 		
11887 		// now offset the RD by the time zone, then recalculate in case we were 
11888 		// near the year boundary
11889 		if (!this.tz) {
11890 			this.tz = new TimeZone({id: this.timezone});
11891 		}
11892 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
11893 	}
11894 
11895 	if (this.offset !== 0) {
11896 		rd += this.offset;
11897 		this.year = this._calcYear(rd);
11898 	}
11899 	
11900 	var jan1 = this.newRd({
11901 		year: this.year,
11902 		month: 1,
11903 		day: 1,
11904 		hour: 0,
11905 		minute: 0,
11906 		second: 0,
11907 		millisecond: 0
11908 	});
11909 	remainder = rd + 1 - jan1.getRataDie();
11910 	
11911 	cumulative = this.cal.isLeapYear(this.year) ? 
11912 		JulianCal.cumMonthLengthsLeap : 
11913 		JulianCal.cumMonthLengths; 
11914 	
11915 	this.month = SearchUtils.bsearch(Math.floor(remainder), cumulative);
11916 	remainder = remainder - cumulative[this.month-1];
11917 	
11918 	this.day = Math.floor(remainder);
11919 	remainder -= this.day;
11920 	// now convert to milliseconds for the rest of the calculation
11921 	remainder = Math.round(remainder * 86400000);
11922 	
11923 	this.hour = Math.floor(remainder/3600000);
11924 	remainder -= this.hour * 3600000;
11925 	
11926 	this.minute = Math.floor(remainder/60000);
11927 	remainder -= this.minute * 60000;
11928 	
11929 	this.second = Math.floor(remainder/1000);
11930 	remainder -= this.second * 1000;
11931 	
11932 	this.millisecond = remainder;
11933 };
11934 
11935 /**
11936  * Return the day of the week of this date. The day of the week is encoded
11937  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
11938  * 
11939  * @return {number} the day of the week
11940  */
11941 JulianDate.prototype.getDayOfWeek = function() {
11942 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
11943 	return MathUtils.mod(rd-2, 7);
11944 };
11945 
11946 /**
11947  * Return the name of the calendar that governs this date.
11948  * 
11949  * @return {string} a string giving the name of the calendar
11950  */
11951 JulianDate.prototype.getCalendar = function() {
11952 	return "julian";
11953 };
11954 
11955 //register with the factory method
11956 IDate._constructors["julian"] = JulianDate;
11957 
11958 
11959 /*< ThaiSolarCal.js */
11960 /*
11961  * thaisolar.js - Represent a Thai solar calendar object.
11962  *
11963  * Copyright © 2013-2015, JEDLSoft
11964  *
11965  * Licensed under the Apache License, Version 2.0 (the "License");
11966  * you may not use this file except in compliance with the License.
11967  * You may obtain a copy of the License at
11968  *
11969  *     http://www.apache.org/licenses/LICENSE-2.0
11970  *
11971  * Unless required by applicable law or agreed to in writing, software
11972  * distributed under the License is distributed on an "AS IS" BASIS,
11973  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11974  *
11975  * See the License for the specific language governing permissions and
11976  * limitations under the License.
11977  */
11978 
11979 
11980 /* !depends ilib.js Calendar.js GregorianCal.js MathUtils.js */
11981 
11982 
11983 /**
11984  * @class
11985  * Construct a new Thai solar calendar object. This class encodes information about
11986  * a Thai solar calendar.<p>
11987  *
11988  *
11989  * @constructor
11990  * @extends Calendar
11991  */
11992 var ThaiSolarCal = function() {
11993 	this.type = "thaisolar";
11994 };
11995 
11996 ThaiSolarCal.prototype = new GregorianCal({noinstance: true});
11997 ThaiSolarCal.prototype.parent = GregorianCal;
11998 ThaiSolarCal.prototype.constructor = ThaiSolarCal;
11999 
12000 /**
12001  * Return true if the given year is a leap year in the Thai solar calendar.
12002  * The year parameter may be given as a number, or as a ThaiSolarDate object.
12003  * @param {number|ThaiSolarDate} year the year for which the leap year information is being sought
12004  * @return {boolean} true if the given year is a leap year
12005  */
12006 ThaiSolarCal.prototype.isLeapYear = function(year) {
12007 	var y = (typeof(year) === 'number' ? year : year.getYears());
12008 	y -= 543;
12009 	var centuries = MathUtils.mod(y, 400);
12010 	return (MathUtils.mod(y, 4) === 0 && centuries !== 100 && centuries !== 200 && centuries !== 300);
12011 };
12012 
12013 /**
12014  * Return a date instance for this calendar type using the given
12015  * options.
12016  * @param {Object} options options controlling the construction of
12017  * the date instance
12018  * @return {IDate} a date appropriate for this calendar type
12019  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
12020  */
12021 ThaiSolarCal.prototype.newDateInstance = function (options) {
12022 		return new ThaiSolarDate(options);
12023 };
12024 
12025 /* register this calendar for the factory method */
12026 Calendar._constructors["thaisolar"] = ThaiSolarCal;
12027 
12028 
12029 /*< ThaiSolarDate.js */
12030 /*
12031  * ThaiSolarDate.js - Represent a date in the ThaiSolar calendar
12032  * 
12033  * Copyright © 2013-2015, JEDLSoft
12034  *
12035  * Licensed under the Apache License, Version 2.0 (the "License");
12036  * you may not use this file except in compliance with the License.
12037  * You may obtain a copy of the License at
12038  *
12039  *     http://www.apache.org/licenses/LICENSE-2.0
12040  *
12041  * Unless required by applicable law or agreed to in writing, software
12042  * distributed under the License is distributed on an "AS IS" BASIS,
12043  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12044  *
12045  * See the License for the specific language governing permissions and
12046  * limitations under the License.
12047  */
12048 
12049 /* !depends 
12050 ilib.js
12051 IDate.js 
12052 JSUtils.js
12053 GregorianDate.js
12054 ThaiSolarCal.js
12055 */
12056 
12057 
12058 
12059 
12060 /**
12061  * @class
12062  * Construct a new Thai solar date object. The constructor parameters can 
12063  * contain any of the following properties:
12064  * 
12065  * <ul>
12066  * <li><i>unixtime<i> - sets the time of this instance according to the given 
12067  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
12068  * 
12069  * <li><i>julianday</i> - sets the time of this instance according to the given
12070  * Julian Day instance or the Julian Day given as a float
12071  * 
12072  * <li><i>year</i> - any integer, including 0
12073  * 
12074  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
12075  * 
12076  * <li><i>day</i> - 1 to 31
12077  * 
12078  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
12079  * is always done with an unambiguous 24 hour representation
12080  * 
12081  * <li><i>minute</i> - 0 to 59
12082  * 
12083  * <li><i>second</i> - 0 to 59
12084  * 
12085  * <li><i>millisecond</i> - 0 to 999
12086  * 
12087  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
12088  * of this Thai solar date. The date/time is kept in the local time. The time zone
12089  * is used later if this date is formatted according to a different time zone and
12090  * the difference has to be calculated, or when the date format has a time zone
12091  * component in it.
12092  * 
12093  * <li><i>locale</i> - locale for this Thai solar date. If the time zone is not 
12094  * given, it can be inferred from this locale. For locales that span multiple
12095  * time zones, the one with the largest population is chosen as the one that 
12096  * represents the locale. 
12097  * </ul>
12098  *
12099  * If the constructor is called with another Thai solar date instance instead of
12100  * a parameter block, the other instance acts as a parameter block and its
12101  * settings are copied into the current instance.<p>
12102  * 
12103  * If the constructor is called with no arguments at all or if none of the 
12104  * properties listed above 
12105  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
12106  * components are 
12107  * filled in with the current date at the time of instantiation. Note that if
12108  * you do not give the time zone when defaulting to the current time and the 
12109  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
12110  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
12111  * Mean Time").<p>
12112  * 
12113  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
12114  * specified in the params, it is assumed that they have the smallest possible
12115  * value in the range for the property (zero or one).<p>
12116  * 
12117  * 
12118  * @constructor
12119  * @extends GregorianDate
12120  * @param {Object=} params parameters that govern the settings and behaviour of this Thai solar date
12121  */
12122 var ThaiSolarDate = function(params) {
12123 	var p = params;
12124 	if (params) {
12125 		// there is 198327 days difference between the Thai solar and 
12126 		// Gregorian epochs which is equivalent to 543 years
12127 		p = {};
12128 		JSUtils.shallowCopy(params, p);
12129 		if (typeof(p.year) !== 'undefined') {
12130 			p.year -= 543;	
12131 		}
12132 		if (typeof(p.rd) !== 'undefined') {
12133 			p.rd -= 198327;
12134 		}
12135 	}
12136 	this.rd = undefined; // clear these out so that the GregorianDate constructor can set it
12137 	this.offset = undefined;
12138 	//console.log("ThaiSolarDate.constructor: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
12139 	GregorianDate.call(this, p);
12140 	this.cal = new ThaiSolarCal();
12141 	// make sure the year is set correctly
12142 	if (params && typeof(params.year) !== 'undefined') {
12143 		this.year = parseInt(params.year, 10);
12144 	}
12145 };
12146 
12147 ThaiSolarDate.prototype = new GregorianDate({noinstance: true});
12148 ThaiSolarDate.prototype.parent = GregorianDate.prototype;
12149 ThaiSolarDate.prototype.constructor = ThaiSolarDate;
12150 
12151 /**
12152  * the difference between a zero Julian day and the zero Thai Solar date.
12153  * This is some 543 years before the start of the Gregorian epoch. 
12154  * @private
12155  * @const
12156  * @type number
12157  */
12158 ThaiSolarDate.epoch = 1523097.5;
12159 
12160 /**
12161  * Calculate the date components for the current time zone
12162  * @protected
12163  */
12164 ThaiSolarDate.prototype._calcDateComponents = function () {
12165 	// there is 198327 days difference between the Thai solar and 
12166 	// Gregorian epochs which is equivalent to 543 years
12167 	// console.log("ThaiSolarDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
12168 	this.parent._calcDateComponents.call(this);
12169 	this.year += 543;
12170 };
12171 
12172 /**
12173  * Return the Rata Die (fixed day) number of this date.
12174  * 
12175  * @protected
12176  * @return {number} the rd date as a number
12177  */
12178 ThaiSolarDate.prototype.getRataDie = function() {
12179 	// there is 198327 days difference between the Thai solar and 
12180 	// Gregorian epochs which is equivalent to 543 years
12181 	return this.rd.getRataDie() + 198327;
12182 };
12183 
12184 /**
12185  * Return a new Gregorian date instance that represents the first instance of the 
12186  * given day of the week before the current date. The day of the week is encoded
12187  * as a number where 0 = Sunday, 1 = Monday, etc.
12188  * 
12189  * @param {number} dow the day of the week before the current date that is being sought
12190  * @return {IDate} the date being sought
12191  */
12192 ThaiSolarDate.prototype.before = function (dow) {
12193 	return new ThaiSolarDate({
12194 		rd: this.rd.before(dow, this.offset) + 198327,
12195 		timezone: this.timezone
12196 	});
12197 };
12198 
12199 /**
12200  * Return a new Gregorian date instance that represents the first instance of the 
12201  * given day of the week after the current date. The day of the week is encoded
12202  * as a number where 0 = Sunday, 1 = Monday, etc.
12203  * 
12204  * @param {number} dow the day of the week after the current date that is being sought
12205  * @return {IDate} the date being sought
12206  */
12207 ThaiSolarDate.prototype.after = function (dow) {
12208 	return new ThaiSolarDate({
12209 		rd: this.rd.after(dow, this.offset) + 198327,
12210 		timezone: this.timezone
12211 	});
12212 };
12213 
12214 /**
12215  * Return a new Gregorian date instance that represents the first instance of the 
12216  * given day of the week on or before the current date. The day of the week is encoded
12217  * as a number where 0 = Sunday, 1 = Monday, etc.
12218  * 
12219  * @param {number} dow the day of the week on or before the current date that is being sought
12220  * @return {IDate} the date being sought
12221  */
12222 ThaiSolarDate.prototype.onOrBefore = function (dow) {
12223 	return new ThaiSolarDate({
12224 		rd: this.rd.onOrBefore(dow, this.offset) + 198327,
12225 		timezone: this.timezone
12226 	});
12227 };
12228 
12229 /**
12230  * Return a new Gregorian date instance that represents the first instance of the 
12231  * given day of the week on or after the current date. The day of the week is encoded
12232  * as a number where 0 = Sunday, 1 = Monday, etc.
12233  * 
12234  * @param {number} dow the day of the week on or after the current date that is being sought
12235  * @return {IDate} the date being sought
12236  */
12237 ThaiSolarDate.prototype.onOrAfter = function (dow) {
12238 	return new ThaiSolarDate({
12239 		rd: this.rd.onOrAfter(dow, this.offset) + 198327,
12240 		timezone: this.timezone
12241 	});
12242 };
12243 
12244 /**
12245  * Return the name of the calendar that governs this date.
12246  * 
12247  * @return {string} a string giving the name of the calendar
12248  */
12249 ThaiSolarDate.prototype.getCalendar = function() {
12250 	return "thaisolar";
12251 };
12252 
12253 //register with the factory method
12254 IDate._constructors["thaisolar"] = ThaiSolarDate;
12255 
12256 
12257 
12258 /*< Astro.js */
12259 /*
12260  * astro.js - Static functions to support astronomical calculations
12261  * 
12262  * Copyright © 2014-2015, JEDLSoft
12263  *
12264  * Licensed under the Apache License, Version 2.0 (the "License");
12265  * you may not use this file except in compliance with the License.
12266  * You may obtain a copy of the License at
12267  *
12268  *     http://www.apache.org/licenses/LICENSE-2.0
12269  *
12270  * Unless required by applicable law or agreed to in writing, software
12271  * distributed under the License is distributed on an "AS IS" BASIS,
12272  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12273  *
12274  * See the License for the specific language governing permissions and
12275  * limitations under the License.
12276  */
12277 
12278 /* !depends
12279 ilib.js
12280 IDate.js
12281 Utils.js
12282 MathUtils.js
12283 SearchUtils.js
12284 GregorianDate.js
12285 GregRataDie.js
12286 */
12287 
12288 // !data astro
12289 
12290 /*
12291  * These routines were derived from a public domain set of JavaScript 
12292  * functions for positional astronomy by John Walker of Fourmilab, 
12293  * September 1999.
12294  */
12295 
12296 
12297 
12298 var Astro = {};
12299 
12300 /**
12301  * Load in all the data needed for astrological calculations.
12302  * 
12303  * @private
12304  * @param {boolean} sync
12305  * @param {*} loadParams
12306  * @param {function(*)|undefined} callback
12307  */
12308 Astro.initAstro = function(sync, loadParams, callback) {
12309 	if (!ilib.data.astro) {
12310 		Utils.loadData({
12311 			name: "astro.json", // countries in their own language 
12312 			locale: "-", // only need to load the root file 
12313 			nonLocale: true,
12314 			sync: sync, 
12315 			loadParams: loadParams, 
12316 			callback: ilib.bind(this, /** @type function() */ function(astroData) {
12317 				/** 
12318 				 * @type {{
12319 				 *  	_EquinoxpTerms:Array.<number>, 
12320 				 *  	_JDE0tab1000:Array.<number>, 
12321 				 *  	_JDE0tab2000:Array.<number>, 
12322 				 *  	_deltaTtab:Array.<number>,
12323 				 *  	_oterms:Array.<number>,
12324 				 *  	_nutArgMult:Array.<number>, 
12325 				 *  	_nutArgCoeff:Array.<number>, 
12326 				 *  	_nutCoeffA:Array.<number>,
12327 				 *  	_nutCoeffB:Array.<number>,
12328 				 *  	_coeff19th:Array.<number>,
12329 				 *  	_coeff18th:Array.<number>,
12330 				 *  	_solarLongCoeff:Array.<number>, 
12331 				 *  	_solarLongMultipliers:Array.<number>, 
12332 				 *  	_solarLongAddends:Array.<number>, 
12333 				 *  	_meanMoonCoeff:Array.<number>,
12334 				 *  	_elongationCoeff:Array.<number>,
12335 				 *  	_solarAnomalyCoeff:Array.<number>,
12336 				 *  	_lunarAnomalyCoeff:Array.<number>,
12337 				 *  	_moonFromNodeCoeff:Array.<number>,
12338 				 *  	_eCoeff:Array.<number>,
12339 				 *  	_lunarElongationLongCoeff:Array.<number>,
12340 				 *  	_solarAnomalyLongCoeff:Array.<number>,
12341 				 *  	_lunarAnomalyLongCoeff:Array.<number>,
12342 				 *  	_moonFromNodeLongCoeff:Array.<number>,
12343 				 *  	_sineCoeff:Array.<number>,
12344 				 *  	_nmApproxCoeff:Array.<number>,
12345 				 *  	_nmCapECoeff:Array.<number>,
12346 				 *  	_nmSolarAnomalyCoeff:Array.<number>,
12347 				 *  	_nmLunarAnomalyCoeff:Array.<number>,
12348 				 *  	_nmMoonArgumentCoeff:Array.<number>,
12349 				 *  	_nmCapOmegaCoeff:Array.<number>,
12350 				 *  	_nmEFactor:Array.<number>,
12351 				 *  	_nmSolarCoeff:Array.<number>,
12352 				 *  	_nmLunarCoeff:Array.<number>,
12353 				 *  	_nmMoonCoeff:Array.<number>,
12354 				 *  	_nmSineCoeff:Array.<number>,
12355 				 *  	_nmAddConst:Array.<number>,
12356 				 *  	_nmAddCoeff:Array.<number>,
12357 				 *  	_nmAddFactor:Array.<number>,
12358 				 *  	_nmExtra:Array.<number>
12359 				 *  }}
12360 				 */ 	
12361 			 	ilib.data.astro = astroData;
12362 				if (callback && typeof(callback) === 'function') {
12363 					callback(astroData);
12364 				}
12365 			})
12366 		});
12367 	} else {
12368 		if (callback && typeof(callback) === 'function') {
12369 			callback(ilib.data.astro);
12370 		}
12371 	}
12372 };
12373 
12374 /**
12375  * Convert degrees to radians.
12376  * 
12377  * @static
12378  * @protected
12379  * @param {number} d angle in degrees
12380  * @return {number} angle in radians 
12381  */
12382 Astro._dtr = function(d) {
12383 	return (d * Math.PI) / 180.0;
12384 };
12385 
12386 /**
12387  * Convert radians to degrees.
12388  * 
12389  * @static
12390  * @protected
12391  * @param {number} r angle in radians
12392  * @return {number} angle in degrees 
12393  */
12394 Astro._rtd = function(r) {
12395 	return (r * 180.0) / Math.PI;
12396 };
12397 
12398 /**
12399  * Return the cosine of an angle given in degrees.
12400  * @static
12401  * @protected
12402  * @param {number} d angle in degrees
12403  * @return {number} cosine of the angle.
12404  */  
12405 Astro._dcos = function(d) {
12406 	return Math.cos(Astro._dtr(d));
12407 };
12408 
12409 /**
12410  * Return the sine of an angle given in degrees.
12411  * @static
12412  * @protected
12413  * @param {number} d angle in degrees
12414  * @return {number} sine of the angle.
12415  */  
12416 Astro._dsin = function(d) {
12417 	return Math.sin(Astro._dtr(d));
12418 };
12419 
12420 /**
12421  * Return the tan of an angle given in degrees.
12422  * @static
12423  * @protected
12424  * @param {number} d angle in degrees
12425  * @return {number} tan of the angle.
12426  */  
12427 Astro._dtan = function(d) {
12428 	return Math.tan(Astro._dtr(d));
12429 };
12430 
12431 /**
12432  * Range reduce angle in degrees.
12433  * 
12434  * @static
12435  * @param {number} a angle to reduce
12436  * @return {number} the reduced angle  
12437  */
12438 Astro._fixangle = function(a) {
12439 	return a - 360.0 * (Math.floor(a / 360.0));
12440 };
12441 
12442 /**
12443  * Range reduce angle in radians.
12444  * 
12445  * @static
12446  * @protected
12447  * @param {number} a angle to reduce
12448  * @return {number} the reduced angle  
12449  */
12450 Astro._fixangr = function(a) {
12451 	return a - (2 * Math.PI) * (Math.floor(a / (2 * Math.PI)));
12452 };
12453 
12454 /**
12455  * Determine the Julian Ephemeris Day of an equinox or solstice.  The "which" 
12456  * argument selects the item to be computed:
12457  * 
12458  * <ul>
12459  * <li>0   March equinox
12460  * <li>1   June solstice
12461  * <li>2   September equinox
12462  * <li>3   December solstice
12463  * </ul>
12464  * 
12465  * @static
12466  * @protected
12467  * @param {number} year Gregorian year to calculate for
12468  * @param {number} which Which equinox or solstice to calculate
12469  */
12470 Astro._equinox = function(year, which) {
12471 	var deltaL, i, j, JDE0, JDE, JDE0tab, S, T, W, Y;
12472 
12473 	/*  Initialize terms for mean equinox and solstices.  We
12474 	    have two sets: one for years prior to 1000 and a second
12475 	    for subsequent years.  */
12476 
12477 	if (year < 1000) {
12478 		JDE0tab = ilib.data.astro._JDE0tab1000;
12479 		Y = year / 1000;
12480 	} else {
12481 		JDE0tab = ilib.data.astro._JDE0tab2000;
12482 		Y = (year - 2000) / 1000;
12483 	}
12484 
12485 	JDE0 = JDE0tab[which][0] + (JDE0tab[which][1] * Y)
12486 			+ (JDE0tab[which][2] * Y * Y) + (JDE0tab[which][3] * Y * Y * Y)
12487 			+ (JDE0tab[which][4] * Y * Y * Y * Y);
12488 
12489 	//document.debug.log.value += "JDE0 = " + JDE0 + "\n";
12490 
12491 	T = (JDE0 - 2451545.0) / 36525;
12492 	//document.debug.log.value += "T = " + T + "\n";
12493 	W = (35999.373 * T) - 2.47;
12494 	//document.debug.log.value += "W = " + W + "\n";
12495 	deltaL = 1 + (0.0334 * Astro._dcos(W)) + (0.0007 * Astro._dcos(2 * W));
12496 	//document.debug.log.value += "deltaL = " + deltaL + "\n";
12497 
12498 	//  Sum the periodic terms for time T
12499 
12500 	S = 0;
12501 	j = 0;
12502 	for (i = 0; i < 24; i++) {
12503 		S += ilib.data.astro._EquinoxpTerms[j]
12504 				* Astro._dcos(ilib.data.astro._EquinoxpTerms[j + 1] + (ilib.data.astro._EquinoxpTerms[j + 2] * T));
12505 		j += 3;
12506 	}
12507 
12508 	//document.debug.log.value += "S = " + S + "\n";
12509 	//document.debug.log.value += "Corr = " + ((S * 0.00001) / deltaL) + "\n";
12510 
12511 	JDE = JDE0 + ((S * 0.00001) / deltaL);
12512 
12513 	return JDE;
12514 };
12515 
12516 /* 
12517  * The table of observed Delta T values at the beginning of
12518  * years from 1620 through 2014 as found in astro.json is taken from
12519  * http://www.staff.science.uu.nl/~gent0113/deltat/deltat.htm
12520  * and
12521  * ftp://maia.usno.navy.mil/ser7/deltat.data
12522  */
12523 
12524 /**  
12525  * Determine the difference, in seconds, between dynamical time and universal time.
12526  * 
12527  * @static
12528  * @protected
12529  * @param {number} year to calculate the difference for
12530  * @return {number} difference in seconds between dynamical time and universal time  
12531  */
12532 Astro._deltat = function (year) {
12533 	var dt, f, i, t;
12534 
12535 	if ((year >= 1620) && (year <= 2014)) {
12536 		i = Math.floor(year - 1620);
12537 		f = (year - 1620) - i; /* Fractional part of year */
12538 		dt = ilib.data.astro._deltaTtab[i] + ((ilib.data.astro._deltaTtab[i + 1] - ilib.data.astro._deltaTtab[i]) * f);
12539 	} else {
12540 		t = (year - 2000) / 100;
12541 		if (year < 948) {
12542 			dt = 2177 + (497 * t) + (44.1 * t * t);
12543 		} else {
12544 			dt = 102 + (102 * t) + (25.3 * t * t);
12545 			if ((year > 2000) && (year < 2100)) {
12546 				dt += 0.37 * (year - 2100);
12547 			}
12548 		}
12549 	}
12550 	return dt;
12551 };
12552 
12553 /**
12554  * Calculate the obliquity of the ecliptic for a given
12555  * Julian date.  This uses Laskar's tenth-degree
12556  * polynomial fit (J. Laskar, Astronomy and
12557  * Astrophysics, Vol. 157, page 68 [1986]) which is
12558  * accurate to within 0.01 arc second between AD 1000
12559  * and AD 3000, and within a few seconds of arc for
12560  * +/-10000 years around AD 2000.  If we're outside the
12561  * range in which this fit is valid (deep time) we
12562  * simply return the J2000 value of the obliquity, which
12563  * happens to be almost precisely the mean.
12564  * 
12565  * @static
12566  * @protected
12567  * @param {number} jd Julian Day to calculate the obliquity for
12568  * @return {number} the obliquity
12569  */
12570 Astro._obliqeq = function (jd) {
12571 	var eps, u, v, i;
12572 
12573  	v = u = (jd - 2451545.0) / 3652500.0;
12574 
12575  	eps = 23 + (26 / 60.0) + (21.448 / 3600.0);
12576 
12577  	if (Math.abs(u) < 1.0) {
12578  		for (i = 0; i < 10; i++) {
12579  			eps += (ilib.data.astro._oterms[i] / 3600.0) * v;
12580  			v *= u;
12581  		}
12582  	}
12583  	return eps;
12584 };
12585 
12586 /**
12587  * Return the position of the sun.  We return
12588  * intermediate values because they are useful in a
12589  * variety of other contexts.
12590  * @static
12591  * @protected
12592  * @param {number} jd find the position of sun on this Julian Day
12593  * @return {Object} the position of the sun and many intermediate
12594  * values
12595  */
12596 Astro._sunpos = function(jd) {
12597 	var ret = {}, 
12598 		T, T2, T3, Omega, epsilon, epsilon0;
12599 
12600 	T = (jd - 2451545.0) / 36525.0;
12601 	//document.debug.log.value += "Sunpos.  T = " + T + "\n";
12602 	T2 = T * T;
12603 	T3 = T * T2;
12604 	ret.meanLongitude = Astro._fixangle(280.46646 + 36000.76983 * T + 0.0003032 * T2);
12605 	//document.debug.log.value += "ret.meanLongitude = " + ret.meanLongitude + "\n";
12606 	ret.meanAnomaly = Astro._fixangle(357.52911 + (35999.05029 * T) - 0.0001537 * T2 - 0.00000048 * T3);
12607 	//document.debug.log.value += "ret.meanAnomaly = " + ret.meanAnomaly + "\n";
12608 	ret.eccentricity = 0.016708634 - 0.000042037 * T - 0.0000001267 * T2;
12609 	//document.debug.log.value += "e = " + e + "\n";
12610 	ret.equationOfCenter = ((1.914602 - 0.004817 * T - 0.000014 * T2) * Astro._dsin(ret.meanAnomaly))
12611 			+ ((0.019993 - 0.000101 * T) * Astro._dsin(2 * ret.meanAnomaly))
12612 			+ (0.000289 * Astro._dsin(3 * ret.meanAnomaly));
12613 	//document.debug.log.value += "ret.equationOfCenter = " + ret.equationOfCenter + "\n";
12614 	ret.sunLongitude = ret.meanLongitude + ret.equationOfCenter;
12615 	//document.debug.log.value += "ret.sunLongitude = " + ret.sunLongitude + "\n";
12616 	//ret.sunAnomaly = ret.meanAnomaly + ret.equationOfCenter;
12617 	//document.debug.log.value += "ret.sunAnomaly = " + ret.sunAnomaly + "\n";
12618 	// ret.sunRadius = (1.000001018 * (1 - (ret.eccentricity * ret.eccentricity))) / (1 + (ret.eccentricity * Astro._dcos(ret.sunAnomaly)));
12619 	//document.debug.log.value += "ret.sunRadius = " + ret.sunRadius + "\n";
12620 	Omega = 125.04 - (1934.136 * T);
12621 	//document.debug.log.value += "Omega = " + Omega + "\n";
12622 	ret.apparentLong = ret.sunLongitude + (-0.00569) + (-0.00478 * Astro._dsin(Omega));
12623 	//document.debug.log.value += "ret.apparentLong = " + ret.apparentLong + "\n";
12624 	epsilon0 = Astro._obliqeq(jd);
12625 	//document.debug.log.value += "epsilon0 = " + epsilon0 + "\n";
12626 	epsilon = epsilon0 + (0.00256 * Astro._dcos(Omega));
12627 	//document.debug.log.value += "epsilon = " + epsilon + "\n";
12628 	//ret.rightAscension = Astro._fixangle(Astro._rtd(Math.atan2(Astro._dcos(epsilon0) * Astro._dsin(ret.sunLongitude), Astro._dcos(ret.sunLongitude))));
12629 	//document.debug.log.value += "ret.rightAscension = " + ret.rightAscension + "\n";
12630 	// ret.declination = Astro._rtd(Math.asin(Astro._dsin(epsilon0) * Astro._dsin(ret.sunLongitude)));
12631 	////document.debug.log.value += "ret.declination = " + ret.declination + "\n";
12632 	ret.inclination = Astro._fixangle(23.4392911 - 0.013004167 * T - 0.00000016389 * T2 + 0.0000005036 * T3);
12633 	ret.apparentRightAscension = Astro._fixangle(Astro._rtd(Math.atan2(Astro._dcos(epsilon) * Astro._dsin(ret.apparentLong), Astro._dcos(ret.apparentLong))));
12634 	//document.debug.log.value += "ret.apparentRightAscension = " + ret.apparentRightAscension + "\n";
12635 	//ret.apparentDeclination = Astro._rtd(Math.asin(Astro._dsin(epsilon) * Astro._dsin(ret.apparentLong)));
12636 	//document.debug.log.value += "ret.apparentDecliation = " + ret.apparentDecliation + "\n";
12637 
12638 	// Angular quantities are expressed in decimal degrees
12639 	return ret;
12640 };
12641 
12642 /**
12643  * Calculate the nutation in longitude, deltaPsi, and obliquity, 
12644  * deltaEpsilon for a given Julian date jd. Results are returned as an object
12645  * giving deltaPsi and deltaEpsilon in degrees.
12646  * 
12647  * @static
12648  * @protected
12649  * @param {number} jd calculate the nutation of this Julian Day
12650  * @return {Object} the deltaPsi and deltaEpsilon of the nutation
12651  */
12652 Astro._nutation = function(jd) {
12653 	var i, j, 
12654 		t = (jd - 2451545.0) / 36525.0, 
12655 		t2, t3, to10, 
12656 		ta = [], 
12657 		dp = 0, 
12658 		de = 0, 
12659 		ang,
12660 		ret = {};
12661 
12662 	t3 = t * (t2 = t * t);
12663 
12664 	/*
12665 	 * Calculate angles. The correspondence between the elements of our array
12666 	 * and the terms cited in Meeus are:
12667 	 * 
12668 	 * ta[0] = D ta[0] = M ta[2] = M' ta[3] = F ta[4] = \Omega
12669 	 * 
12670 	 */
12671 
12672 	ta[0] = Astro._dtr(297.850363 + 445267.11148 * t - 0.0019142 * t2 + t3 / 189474.0);
12673 	ta[1] = Astro._dtr(357.52772 + 35999.05034 * t - 0.0001603 * t2 - t3 / 300000.0);
12674 	ta[2] = Astro._dtr(134.96298 + 477198.867398 * t + 0.0086972 * t2 + t3 / 56250.0);
12675 	ta[3] = Astro._dtr(93.27191 + 483202.017538 * t - 0.0036825 * t2 + t3 / 327270);
12676 	ta[4] = Astro._dtr(125.04452 - 1934.136261 * t + 0.0020708 * t2 + t3 / 450000.0);
12677 
12678 	/*
12679 	 * Range reduce the angles in case the sine and cosine functions don't do it
12680 	 * as accurately or quickly.
12681 	 */
12682 
12683 	for (i = 0; i < 5; i++) {
12684 		ta[i] = Astro._fixangr(ta[i]);
12685 	}
12686 
12687 	to10 = t / 10.0;
12688 	for (i = 0; i < 63; i++) {
12689 		ang = 0;
12690 		for (j = 0; j < 5; j++) {
12691 			if (ilib.data.astro._nutArgMult[(i * 5) + j] != 0) {
12692 				ang += ilib.data.astro._nutArgMult[(i * 5) + j] * ta[j];
12693 			}
12694 		}
12695 		dp += (ilib.data.astro._nutArgCoeff[(i * 4) + 0] + ilib.data.astro._nutArgCoeff[(i * 4) + 1] * to10) * Math.sin(ang);
12696 		de += (ilib.data.astro._nutArgCoeff[(i * 4) + 2] + ilib.data.astro._nutArgCoeff[(i * 4) + 3] * to10) * Math.cos(ang);
12697 	}
12698 
12699 	/*
12700 	 * Return the result, converting from ten thousandths of arc seconds to
12701 	 * radians in the process.
12702 	 */
12703 
12704 	ret.deltaPsi = dp / (3600.0 * 10000.0);
12705 	ret.deltaEpsilon = de / (3600.0 * 10000.0);
12706 
12707 	return ret;
12708 };
12709 
12710 /**
12711  * Returns the equation of time as a fraction of a day.
12712  * 
12713  * @static
12714  * @protected
12715  * @param {number} jd the Julian Day of the day to calculate for
12716  * @return {number} the equation of time for the given day  
12717  */
12718 Astro._equationOfTime = function(jd) {
12719 	var alpha, deltaPsi, E, epsilon, L0, tau, pos;
12720 
12721 	// 2451545.0 is the Julian day of J2000 epoch
12722 	// 365250.0 is the number of days in a Julian millenium
12723 	tau = (jd - 2451545.0) / 365250.0;
12724 	//console.log("equationOfTime.  tau = " + tau);
12725 	L0 = 280.4664567 + (360007.6982779 * tau) + (0.03032028 * tau * tau)
12726 			+ ((tau * tau * tau) / 49931)
12727 			+ (-((tau * tau * tau * tau) / 15300))
12728 			+ (-((tau * tau * tau * tau * tau) / 2000000));
12729 	//console.log("L0 = " + L0);
12730 	L0 = Astro._fixangle(L0);
12731 	//console.log("L0 = " + L0);
12732 	pos = Astro._sunpos(jd);
12733 	alpha = pos.apparentRightAscension;
12734 	//console.log("alpha = " + alpha);
12735 	var nut = Astro._nutation(jd);
12736 	deltaPsi = nut.deltaPsi;
12737 	//console.log("deltaPsi = " + deltaPsi);
12738 	epsilon = Astro._obliqeq(jd) + nut.deltaEpsilon;
12739 	//console.log("epsilon = " + epsilon);
12740 	//console.log("L0 - 0.0057183 = " + (L0 - 0.0057183));
12741 	//console.log("L0 - 0.0057183 - alpha = " + (L0 - 0.0057183 - alpha));
12742 	//console.log("deltaPsi * cos(epsilon) = " + deltaPsi * Astro._dcos(epsilon));
12743 	
12744 	E = L0 - 0.0057183 - alpha + deltaPsi * Astro._dcos(epsilon);
12745 	// if alpha and L0 are in different quadrants, then renormalize
12746 	// so that the difference between them is in the right range
12747 	if (E > 180) {
12748 		E -= 360;
12749 	}
12750 	//console.log("E = " + E);
12751 	// E = E - 20.0 * (Math.floor(E / 20.0));
12752 	E = E * 4;
12753 	//console.log("Efixed = " + E);
12754 	E = E / (24 * 60);
12755 	//console.log("Eday = " + E);
12756 
12757 	return E;
12758 };
12759 
12760 /**
12761  * @private
12762  * @static
12763  */
12764 Astro._poly = function(x, coefficients) {
12765 	var result = coefficients[0];
12766 	var xpow = x;
12767 	for (var i = 1; i < coefficients.length; i++) {
12768 		result += coefficients[i] * xpow;
12769 		xpow *= x;
12770 	}
12771 	return result;
12772 };
12773 
12774 /**
12775  * Calculate the UTC RD from the local RD given "zone" number of minutes
12776  * worth of offset.
12777  * 
12778  * @static
12779  * @protected
12780  * @param {number} local RD of the locale time, given in any calendar
12781  * @param {number} zone number of minutes of offset from UTC for the time zone 
12782  * @return {number} the UTC equivalent of the local RD
12783  */
12784 Astro._universalFromLocal = function(local, zone) {
12785 	return local - zone / 1440;
12786 };
12787 
12788 /**
12789  * Calculate the local RD from the UTC RD given "zone" number of minutes
12790  * worth of offset.
12791  * 
12792  * @static
12793  * @protected
12794  * @param {number} local RD of the locale time, given in any calendar
12795  * @param {number} zone number of minutes of offset from UTC for the time zone 
12796  * @return {number} the UTC equivalent of the local RD
12797  */
12798 Astro._localFromUniversal = function(local, zone) {
12799 	return local + zone / 1440;
12800 };
12801 
12802 /**
12803  * @private
12804  * @static
12805  * @param {number} c julian centuries of the date to calculate
12806  * @return {number} the aberration
12807  */
12808 Astro._aberration = function(c) {
12809 	return 9.74e-05 * Astro._dcos(177.63 + 35999.01847999999 * c) - 0.005575;
12810 };
12811 
12812 /**
12813  * @private
12814  *
12815 ilib.data.astro._nutCoeffA = [124.90, -1934.134, 0.002063];
12816 ilib.data.astro._nutCoeffB q= [201.11, 72001.5377, 0.00057];
12817 */
12818 
12819 /**
12820  * @private
12821  * @static
12822  * @param {number} c julian centuries of the date to calculate
12823  * @return {number} the nutation for the given julian century in radians
12824  */
12825 Astro._nutation2 = function(c) {
12826 	var a = Astro._poly(c, ilib.data.astro._nutCoeffA);
12827 	var b = Astro._poly(c, ilib.data.astro._nutCoeffB);
12828 	// return -0.0000834 * Astro._dsin(a) - 0.0000064 * Astro._dsin(b);
12829 	return -0.004778 * Astro._dsin(a) - 0.0003667 * Astro._dsin(b);
12830 };
12831 
12832 /**
12833  * @static
12834  * @private
12835  */
12836 Astro._ephemerisCorrection = function(jd) {
12837 	var year = GregorianDate._calcYear(jd - 1721424.5);
12838 	
12839 	if (1988 <= year && year <= 2019) {
12840 		return (year - 1933) / 86400;
12841 	}
12842 	
12843 	if (1800 <= year && year <= 1987) {
12844 		var jul1 = new GregRataDie({
12845 			year: year,
12846 			month: 7,
12847 			day: 1,
12848 			hour: 0,
12849 			minute: 0,
12850 			second: 0
12851 		});
12852 		// 693596 is the rd of Jan 1, 1900
12853 		var theta = (jul1.getRataDie() - 693596) / 36525;
12854 		return Astro._poly(theta, (1900 <= year) ? ilib.data.astro._coeff19th : ilib.data.astro._coeff18th);
12855 	}
12856 	
12857 	if (1620 <= year && year <= 1799) {
12858 		year -= 1600;
12859 		return (196.58333 - 4.0675 * year + 0.0219167 * year * year) / 86400;
12860 	}
12861 	
12862 	// 660724 is the rd of Jan 1, 1810
12863 	var jan1 = new GregRataDie({
12864 		year: year,
12865 		month: 1,
12866 		day: 1,
12867 		hour: 0,
12868 		minute: 0,
12869 		second: 0
12870 	});
12871 	// var x = 0.5 + (jan1.getRataDie() - 660724);
12872 	var x = 0.5 + (jan1.getRataDie() - 660724);
12873 	
12874 	return ((x * x / 41048480) - 15) / 86400;
12875 };
12876 
12877 /**
12878  * @static
12879  * @private
12880  */
12881 Astro._ephemerisFromUniversal = function(jd) {
12882 	return jd + Astro._ephemerisCorrection(jd);
12883 };
12884 
12885 /**
12886  * @static
12887  * @private
12888  */
12889 Astro._universalFromEphemeris = function(jd) {
12890 	return jd - Astro._ephemerisCorrection(jd);
12891 };
12892 
12893 /**
12894  * @static
12895  * @private
12896  */
12897 Astro._julianCenturies = function(jd) {
12898 	// 2451545.0 is the Julian day of J2000 epoch
12899 	// 730119.5 is the Gregorian RD of J2000 epoch
12900 	// 36525.0 is the number of days in a Julian century
12901 	return (Astro._ephemerisFromUniversal(jd) - 2451545.0) / 36525.0;
12902 };
12903 
12904 /**
12905  * Calculate the solar longitude
12906  * 
12907  * @static
12908  * @protected
12909  * @param {number} jd julian day of the date to calculate the longitude for 
12910  * @return {number} the solar longitude in degrees
12911  */
12912 Astro._solarLongitude = function(jd) {
12913 	var c = Astro._julianCenturies(jd),
12914 		longitude = 0,
12915 		len = ilib.data.astro._solarLongCoeff.length,
12916 		row;
12917 	
12918 	for (var i = 0; i < len; i++) {
12919 		longitude += ilib.data.astro._solarLongCoeff[i] * 
12920 			Astro._dsin(ilib.data.astro._solarLongAddends[i] + ilib.data.astro._solarLongMultipliers[i] * c);
12921 	}
12922 	longitude *= 5.729577951308232e-06;
12923 	longitude += 282.77718340000001 + 36000.769537439999 * c;
12924 	longitude += Astro._aberration(c) + Astro._nutation2(c);
12925 	return Astro._fixangle(longitude);
12926 };
12927 
12928 /**
12929  * @static
12930  * @protected
12931  * @param {number} jd
12932  * @return {number}
12933  */
12934 Astro._lunarLongitude = function (jd) {
12935 	var c = Astro._julianCenturies(jd),
12936 	    meanMoon = Astro._fixangle(Astro._poly(c, ilib.data.astro._meanMoonCoeff)),
12937 	    elongation = Astro._fixangle(Astro._poly(c, ilib.data.astro._elongationCoeff)),
12938 	    solarAnomaly = Astro._fixangle(Astro._poly(c, ilib.data.astro._solarAnomalyCoeff)),
12939 	    lunarAnomaly = Astro._fixangle(Astro._poly(c, ilib.data.astro._lunarAnomalyCoeff)),
12940 	    moonNode = Astro._fixangle(Astro._poly(c, ilib.data.astro._moonFromNodeCoeff)),
12941 	    e = Astro._poly(c, ilib.data.astro._eCoeff);
12942 	
12943 	var sum = 0;
12944 	for (var i = 0; i < ilib.data.astro._lunarElongationLongCoeff.length; i++) {
12945 		var x = ilib.data.astro._solarAnomalyLongCoeff[i];
12946 
12947 		sum += ilib.data.astro._sineCoeff[i] * Math.pow(e, Math.abs(x)) * 
12948 			Astro._dsin(ilib.data.astro._lunarElongationLongCoeff[i] * elongation + x * solarAnomaly + 
12949 				ilib.data.astro._lunarAnomalyLongCoeff[i] * lunarAnomaly + 
12950 				ilib.data.astro._moonFromNodeLongCoeff[i] * moonNode);
12951 	}
12952 	var longitude = sum / 1000000;
12953 	var venus = 3958.0 / 1000000 * Astro._dsin(119.75 + c * 131.84899999999999);
12954 	var jupiter = 318.0 / 1000000 * Astro._dsin(53.090000000000003 + c * 479264.28999999998);
12955 	var flatEarth = 1962.0 / 1000000 * Astro._dsin(meanMoon - moonNode);
12956 	
12957 	return Astro._fixangle(meanMoon + longitude + venus + jupiter + flatEarth + Astro._nutation2(c));
12958 };
12959 
12960 /**
12961  * @static
12962  * @protected
12963  * @param {number} n
12964  * @return {number} julian day of the n'th new moon
12965  */
12966 Astro._newMoonTime = function(n) {
12967 	var k = n - 24724;
12968 	var c = k / 1236.8499999999999;
12969 	var approx = Astro._poly(c, ilib.data.astro._nmApproxCoeff);
12970 	var capE = Astro._poly(c, ilib.data.astro._nmCapECoeff);
12971 	var solarAnomaly = Astro._poly(c, ilib.data.astro._nmSolarAnomalyCoeff);
12972 	var lunarAnomaly = Astro._poly(c, ilib.data.astro._nmLunarAnomalyCoeff);
12973 	var moonArgument = Astro._poly(c, ilib.data.astro._nmMoonArgumentCoeff);
12974 	var capOmega = Astro._poly(c, ilib.data.astro._nmCapOmegaCoeff);
12975 	var correction = -0.00017 * Astro._dsin(capOmega);
12976 	for (var i = 0; i < ilib.data.astro._nmSineCoeff.length; i++) {
12977 		correction = correction + ilib.data.astro._nmSineCoeff[i] * Math.pow(capE, ilib.data.astro._nmEFactor[i]) * 
12978 		Astro._dsin(ilib.data.astro._nmSolarCoeff[i] * solarAnomaly + 
12979 				ilib.data.astro._nmLunarCoeff[i] * lunarAnomaly + 
12980 				ilib.data.astro._nmMoonCoeff[i] * moonArgument);
12981 	}
12982 	var additional = 0;
12983 	for (var i = 0; i < ilib.data.astro._nmAddConst.length; i++) {
12984 		additional = additional + ilib.data.astro._nmAddFactor[i] * 
12985 		Astro._dsin(ilib.data.astro._nmAddConst[i] + ilib.data.astro._nmAddCoeff[i] * k);
12986 	}
12987 	var extra = 0.000325 * Astro._dsin(Astro._poly(c, ilib.data.astro._nmExtra));
12988 	return Astro._universalFromEphemeris(approx + correction + extra + additional + RataDie.gregorianEpoch);
12989 };
12990 
12991 /**
12992  * @static
12993  * @protected
12994  * @param {number} jd
12995  * @return {number}
12996  */
12997 Astro._lunarSolarAngle = function(jd) {
12998 	var lunar = Astro._lunarLongitude(jd);
12999 	var solar = Astro._solarLongitude(jd)
13000 	return Astro._fixangle(lunar - solar);
13001 };
13002 
13003 /**
13004  * @static
13005  * @protected
13006  * @param {number} jd
13007  * @return {number}
13008  */
13009 Astro._newMoonBefore = function (jd) {
13010 	var phase = Astro._lunarSolarAngle(jd);
13011 	// 11.450086114414322 is the julian day of the 0th full moon
13012 	// 29.530588853000001 is the average length of a month
13013 	var guess = Math.round((jd - 11.450086114414322 - RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360) - 1;
13014 	var current, last;
13015 	current = last = Astro._newMoonTime(guess);
13016 	while (current < jd) {
13017 		guess++;
13018 		last = current;
13019 		current = Astro._newMoonTime(guess);
13020 	}
13021 	return last;
13022 };
13023 
13024 /**
13025  * @static
13026  * @protected
13027  * @param {number} jd
13028  * @return {number}
13029  */
13030 Astro._newMoonAtOrAfter = function (jd) {
13031 	var phase = Astro._lunarSolarAngle(jd);
13032 	// 11.450086114414322 is the julian day of the 0th full moon
13033 	// 29.530588853000001 is the average length of a month
13034 	var guess = Math.round((jd - 11.450086114414322 - RataDie.gregorianEpoch) / 29.530588853000001 - phase / 360);
13035 	var current;
13036 	while ((current = Astro._newMoonTime(guess)) < jd) {
13037 		guess++;
13038 	}
13039 	return current;
13040 };
13041 
13042 /**
13043  * @static
13044  * @protected
13045  * @param {number} jd JD to calculate from
13046  * @param {number} longitude longitude to seek 
13047  * @returns {number} the JD of the next time that the solar longitude 
13048  * is a multiple of the given longitude
13049  */
13050 Astro._nextSolarLongitude = function(jd, longitude) {
13051 	var rate = 365.242189 / 360.0;
13052 	var tau = jd + rate * Astro._fixangle(longitude - Astro._solarLongitude(jd));
13053 	var start = Math.max(jd, tau - 5.0);
13054 	var end = tau + 5.0;
13055 	
13056 	return SearchUtils.bisectionSearch(0, start, end, 1e-6, function (l) {
13057 		return 180 - Astro._fixangle(Astro._solarLongitude(l) - longitude);
13058 	});
13059 };
13060 
13061 /**
13062  * Floor the julian day to midnight of the current julian day.
13063  * 
13064  * @static
13065  * @protected
13066  * @param {number} jd the julian to round
13067  * @return {number} the jd floored to the midnight of the julian day
13068  */
13069 Astro._floorToJD = function(jd) {
13070 	return Math.floor(jd - 0.5) + 0.5;
13071 };
13072 
13073 /**
13074  * Floor the julian day to midnight of the current julian day.
13075  * 
13076  * @static
13077  * @protected
13078  * @param {number} jd the julian to round
13079  * @return {number} the jd floored to the midnight of the julian day
13080  */
13081 Astro._ceilToJD = function(jd) {
13082 	return Math.ceil(jd + 0.5) - 0.5;
13083 };
13084 
13085 
13086 
13087 /*< PersRataDie.js */
13088 /*
13089  * persratadie.js - Represent a rata die date in the Persian calendar
13090  * 
13091  * Copyright © 2014-2015, JEDLSoft
13092  *
13093  * Licensed under the Apache License, Version 2.0 (the "License");
13094  * you may not use this file except in compliance with the License.
13095  * You may obtain a copy of the License at
13096  *
13097  *     http://www.apache.org/licenses/LICENSE-2.0
13098  *
13099  * Unless required by applicable law or agreed to in writing, software
13100  * distributed under the License is distributed on an "AS IS" BASIS,
13101  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13102  *
13103  * See the License for the specific language governing permissions and
13104  * limitations under the License.
13105  */
13106 
13107 /* !depends 
13108 ilib.js
13109 MathUtils.js
13110 RataDie.js
13111 Astro.js
13112 GregorianDate.js
13113 */
13114 
13115 
13116 
13117 
13118 /**
13119  * @class
13120  * Construct a new Persian RD date number object. The constructor parameters can 
13121  * contain any of the following properties:
13122  * 
13123  * <ul>
13124  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13125  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13126  * 
13127  * <li><i>julianday</i> - sets the time of this instance according to the given
13128  * Julian Day instance or the Julian Day given as a float
13129  * 
13130  * <li><i>year</i> - any integer, including 0
13131  * 
13132  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
13133  * 
13134  * <li><i>day</i> - 1 to 31
13135  * 
13136  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
13137  * is always done with an unambiguous 24 hour representation
13138  * 
13139  * <li><i>minute</i> - 0 to 59
13140  * 
13141  * <li><i>second</i> - 0 to 59
13142  * 
13143  * <li><i>millisecond</i> - 0 to 999
13144  * 
13145  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
13146  * </ul>
13147  *
13148  * If the constructor is called with another Persian date instance instead of
13149  * a parameter block, the other instance acts as a parameter block and its
13150  * settings are copied into the current instance.<p>
13151  * 
13152  * If the constructor is called with no arguments at all or if none of the 
13153  * properties listed above are present, then the RD is calculate based on 
13154  * the current date at the time of instantiation. <p>
13155  * 
13156  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13157  * specified in the params, it is assumed that they have the smallest possible
13158  * value in the range for the property (zero or one).<p>
13159  * 
13160  * 
13161  * @private
13162  * @constructor
13163  * @extends RataDie
13164  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
13165  */
13166 var PersRataDie = function(params) {
13167 	this.rd = undefined;
13168 	Astro.initAstro(
13169 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13170 		params && params.loadParams,
13171 		ilib.bind(this, function (x) {
13172 			RataDie.call(this, params);
13173 			if (params && typeof(params.callback) === 'function') {
13174 				params.callback(this);
13175 			}
13176 		})
13177 	);
13178 };
13179 
13180 PersRataDie.prototype = new RataDie();
13181 PersRataDie.prototype.parent = RataDie;
13182 PersRataDie.prototype.constructor = PersRataDie;
13183 
13184 /**
13185  * The difference between a zero Julian day and the first Persian date
13186  * @private
13187  * @const
13188  * @type number
13189  */
13190 PersRataDie.prototype.epoch = 1948319.5;
13191 
13192 /**
13193  * @protected 
13194  */
13195 PersRataDie.prototype._tehranEquinox = function(year) {
13196     var equJED, equJD, equAPP, equTehran, dtTehran, eot;
13197 
13198     //  March equinox in dynamical time
13199     equJED = Astro._equinox(year, 0);
13200 
13201     //  Correct for delta T to obtain Universal time
13202     equJD = equJED - (Astro._deltat(year) / (24 * 60 * 60));
13203 
13204     //  Apply the equation of time to yield the apparent time at Greenwich
13205     eot = Astro._equationOfTime(equJED) * 360;
13206     eot = (eot - 20 * Math.floor(eot/20)) / 360;
13207     equAPP = equJD + eot;
13208 
13209     /*  
13210      * Finally, we must correct for the constant difference between
13211      * the Greenwich meridian and the time zone standard for Iran 
13212      * Standard time, 52 degrees 30 minutes to the East.
13213      */
13214 
13215     dtTehran = 52.5 / 360;
13216     equTehran = equAPP + dtTehran;
13217 
13218     return equTehran;
13219 };
13220 
13221 /**
13222  * Calculate the year based on the given Julian day.
13223  * @protected
13224  * @param {number} jd the Julian day to get the year for
13225  * @return {{year:number,equinox:number}} the year and the last equinox
13226  */
13227 PersRataDie.prototype._getYear = function(jd) {
13228 	var gd = new GregorianDate({julianday: jd});
13229     var guess = gd.getYears() - 2,
13230     	nexteq,
13231     	ret = {};
13232 
13233     //ret.equinox = Math.floor(this._tehranEquinox(guess));
13234     ret.equinox = this._tehranEquinox(guess);
13235 	while (ret.equinox > jd) {
13236 	    guess--;
13237 	    // ret.equinox = Math.floor(this._tehranEquinox(guess));
13238 	    ret.equinox = this._tehranEquinox(guess);
13239 	}
13240 	nexteq = ret.equinox - 1;
13241 	// if the equinox falls after noon, then the day after that is the start of the 
13242 	// next year, so truncate the JD to get the noon of the day before the day with 
13243 	//the equinox on it, then add 0.5 to get the midnight of that day 
13244 	while (!(Math.floor(ret.equinox) + 0.5 <= jd && jd < Math.floor(nexteq) + 0.5)) {
13245 	    ret.equinox = nexteq;
13246 	    guess++;
13247 	    // nexteq = Math.floor(this._tehranEquinox(guess));
13248 	    nexteq = this._tehranEquinox(guess);
13249 	}
13250 	
13251 	// Mean solar tropical year is 365.24219878 days
13252 	ret.year = Math.round((ret.equinox - this.epoch - 1) / 365.24219878) + 1;
13253 	
13254 	return ret;
13255 };
13256 
13257 /**
13258  * Calculate the Rata Die (fixed day) number of the given date from the
13259  * date components.
13260  *
13261  * @protected
13262  * @param {Object} date the date components to calculate the RD from
13263  */
13264 PersRataDie.prototype._setDateComponents = function(date) {
13265     var adr, guess, jd;
13266 
13267     // Mean solar tropical year is 365.24219878 days 
13268     guess = this.epoch + 1 + 365.24219878 * (date.year - 2);
13269     adr = {year: date.year - 1, equinox: 0};
13270 
13271     while (adr.year < date.year) {
13272         adr = this._getYear(guess);
13273         guess = adr.equinox + (365.24219878 + 2);
13274     }
13275 
13276     jd = Math.floor(adr.equinox) +
13277             ((date.month <= 7) ?
13278                 ((date.month - 1) * 31) :
13279                 (((date.month - 1) * 30) + 6)
13280             ) +
13281     	    (date.day - 1 + 0.5); // add 0.5 so that we convert JDs, which start at noon to RDs which start at midnight
13282     
13283 	jd += (date.hour * 3600000 +
13284 			date.minute * 60000 +
13285 			date.second * 1000 +
13286 			date.millisecond) /
13287 			86400000;
13288 
13289     this.rd = jd - this.epoch;
13290 };
13291 
13292 /**
13293  * Return the rd number of the particular day of the week on or before the 
13294  * given rd. eg. The Sunday on or before the given rd.
13295  * @private
13296  * @param {number} rd the rata die date of the reference date
13297  * @param {number} dayOfWeek the day of the week that is being sought relative 
13298  * to the current date
13299  * @return {number} the rd of the day of the week
13300  */
13301 PersRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
13302 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 3, 7);
13303 };
13304 
13305 
13306 /*< PersianCal.js */
13307 /*
13308  * persianastro.js - Represent a Persian astronomical (Hijjri) calendar object.
13309  * 
13310  * Copyright © 2014-2015, JEDLSoft
13311  *
13312  * Licensed under the Apache License, Version 2.0 (the "License");
13313  * you may not use this file except in compliance with the License.
13314  * You may obtain a copy of the License at
13315  *
13316  *     http://www.apache.org/licenses/LICENSE-2.0
13317  *
13318  * Unless required by applicable law or agreed to in writing, software
13319  * distributed under the License is distributed on an "AS IS" BASIS,
13320  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13321  *
13322  * See the License for the specific language governing permissions and
13323  * limitations under the License.
13324  */
13325 
13326 
13327 /* !depends 
13328 Calendar.js 
13329 PersRataDie.js 
13330 ilib.js
13331 MathUtils.js
13332 */
13333 
13334 
13335 
13336 
13337 /**
13338  * @class
13339  * Construct a new Persian astronomical (Hijjri) calendar object. This class encodes 
13340  * information about a Persian calendar. This class differs from the 
13341  * Persian calendar in that the leap years are calculated based on the
13342  * astronomical observations of the sun in Teheran, instead of calculating
13343  * the leap years based on a regular cyclical rhythm algorithm.<p>
13344  * 
13345  * 
13346  * @constructor
13347  * @extends Calendar
13348  */
13349 var PersianCal = function() {
13350 	this.type = "persian";
13351 };
13352 
13353 /**
13354  * @private
13355  * @const
13356  * @type Array.<number> 
13357  * the lengths of each month 
13358  */
13359 PersianCal.monthLengths = [
13360 	31,  // Farvardin
13361 	31,  // Ordibehesht
13362 	31,  // Khordad
13363 	31,  // Tir
13364 	31,  // Mordad
13365 	31,  // Shahrivar
13366 	30,  // Mehr
13367 	30,  // Aban
13368 	30,  // Azar
13369 	30,  // Dey
13370 	30,  // Bahman
13371 	29   // Esfand
13372 ];
13373 
13374 /**
13375  * Return the number of months in the given year. The number of months in a year varies
13376  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
13377  * days in a year to an entire solar year. The month is represented as a 1-based number
13378  * where 1=first month, 2=second month, etc.
13379  * 
13380  * @param {number} year a year for which the number of months is sought
13381  * @return {number} The number of months in the given year
13382  */
13383 PersianCal.prototype.getNumMonths = function(year) {
13384 	return 12;
13385 };
13386 
13387 /**
13388  * Return the number of days in a particular month in a particular year. This function
13389  * can return a different number for a month depending on the year because of things
13390  * like leap years.
13391  * 
13392  * @param {number} month the month for which the length is sought
13393  * @param {number} year the year within which that month can be found
13394  * @return {number} the number of days within the given month in the given year
13395  */
13396 PersianCal.prototype.getMonLength = function(month, year) {
13397 	if (month !== 12 || !this.isLeapYear(year)) {
13398 		return PersianCal.monthLengths[month-1];
13399 	} else {
13400 		// Month 12, Esfand, has 30 days instead of 29 in leap years
13401 		return 30;
13402 	}
13403 };
13404 
13405 /**
13406  * Return true if the given year is a leap year in the Persian astronomical calendar.
13407  * @param {number} year the year for which the leap year information is being sought
13408  * @return {boolean} true if the given year is a leap year
13409  */
13410 PersianCal.prototype.isLeapYear = function(year) {
13411 	var rdNextYear = new PersRataDie({
13412 		cal: this,
13413 		year: year + 1,
13414 		month: 1,
13415 		day: 1,
13416 		hour: 0,
13417 		minute: 0,
13418 		second: 0,
13419 		millisecond: 0
13420 	});
13421 	var rdThisYear = new PersRataDie({
13422 		cal: this,
13423 		year: year,
13424 		month: 1,
13425 		day: 1,
13426 		hour: 0,
13427 		minute: 0,
13428 		second: 0,
13429 		millisecond: 0
13430 	}); 
13431     return (rdNextYear.getRataDie() - rdThisYear.getRataDie()) > 365;
13432 };
13433 
13434 /**
13435  * Return the type of this calendar.
13436  * 
13437  * @return {string} the name of the type of this calendar 
13438  */
13439 PersianCal.prototype.getType = function() {
13440 	return this.type;
13441 };
13442 
13443 /**
13444  * Return a date instance for this calendar type using the given
13445  * options.
13446  * @param {Object} options options controlling the construction of 
13447  * the date instance
13448  * @return {IDate} a date appropriate for this calendar type
13449  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
13450  */
13451 PersianCal.prototype.newDateInstance = function (options) {
13452 		return new PersianDate(options);
13453 };
13454 
13455 /* register this calendar for the factory method */
13456 Calendar._constructors["persian"] = PersianCal;
13457 
13458 
13459 /*< PersianDate.js */
13460 /*
13461  * PersianDate.js - Represent a date in the Persian astronomical (Hijjri) calendar
13462  * 
13463  * Copyright © 2014-2015, JEDLSoft
13464  *
13465  * Licensed under the Apache License, Version 2.0 (the "License");
13466  * you may not use this file except in compliance with the License.
13467  * You may obtain a copy of the License at
13468  *
13469  *     http://www.apache.org/licenses/LICENSE-2.0
13470  *
13471  * Unless required by applicable law or agreed to in writing, software
13472  * distributed under the License is distributed on an "AS IS" BASIS,
13473  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13474  *
13475  * See the License for the specific language governing permissions and
13476  * limitations under the License.
13477  */
13478 
13479 /* !depends 
13480 ilib.js
13481 Locale.js
13482 TimeZone.js
13483 IDate.js
13484 PersRataDie.js
13485 PersianCal.js 
13486 SearchUtils.js
13487 MathUtils.js
13488 LocaleInfo.js 
13489 Astro.js
13490 */
13491 
13492 // !data astro
13493 
13494 
13495 
13496 
13497 /**
13498  * @class
13499  * 
13500  * Construct a new Persian astronomical date object. The constructor parameters can 
13501  * contain any of the following properties:
13502  * 
13503  * <ul>
13504  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13505  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13506  * 
13507  * <li><i>julianday</i> - sets the time of this instance according to the given
13508  * Julian Day instance or the Julian Day given as a float
13509  * 
13510  * <li><i>year</i> - any integer, including 0
13511  * 
13512  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
13513  * 
13514  * <li><i>day</i> - 1 to 31
13515  * 
13516  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
13517  * is always done with an unambiguous 24 hour representation
13518  * 
13519  * <li><i>minute</i> - 0 to 59
13520  * 
13521  * <li><i>second</i> - 0 to 59
13522  * 
13523  * <li><i>millisecond</i> - 0 to 999
13524  * 
13525  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
13526  * of this persian date. The date/time is kept in the local time. The time zone
13527  * is used later if this date is formatted according to a different time zone and
13528  * the difference has to be calculated, or when the date format has a time zone
13529  * component in it.
13530  * 
13531  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
13532  * given, it can be inferred from this locale. For locales that span multiple
13533  * time zones, the one with the largest population is chosen as the one that 
13534  * represents the locale.
13535  * 
13536  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
13537  * </ul>
13538  *
13539  * If the constructor is called with another Persian date instance instead of
13540  * a parameter block, the other instance acts as a parameter block and its
13541  * settings are copied into the current instance.<p>
13542  * 
13543  * If the constructor is called with no arguments at all or if none of the 
13544  * properties listed above 
13545  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
13546  * components are 
13547  * filled in with the current date at the time of instantiation. Note that if
13548  * you do not give the time zone when defaulting to the current time and the 
13549  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
13550  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
13551  * Mean Time").<p>
13552  * 
13553  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
13554  * specified in the params, it is assumed that they have the smallest possible
13555  * value in the range for the property (zero or one).<p>
13556  * 
13557  * 
13558  * @constructor
13559  * @extends IDate
13560  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
13561  */
13562 var PersianDate = function(params) {
13563 	this.cal = new PersianCal();
13564 	this.timezone = "local";
13565 	
13566 	if (params) {
13567 		if (params.locale) {
13568 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
13569 			var li = new LocaleInfo(this.locale);
13570 			this.timezone = li.getTimeZone(); 
13571 		}
13572 		if (params.timezone) {
13573 			this.timezone = params.timezone;
13574 		}
13575 	}
13576 	
13577 	Astro.initAstro(
13578 		params && typeof(params.sync) === 'boolean' ? params.sync : true,
13579 		params && params.loadParams,
13580 		ilib.bind(this, function (x) {
13581 			if (params && (params.year || params.month || params.day || params.hour ||
13582 					params.minute || params.second || params.millisecond)) {
13583 				/**
13584 				 * Year in the Persian calendar.
13585 				 * @type number
13586 				 */
13587 				this.year = parseInt(params.year, 10) || 0;
13588 
13589 				/**
13590 				 * The month number, ranging from 1 to 12
13591 				 * @type number
13592 				 */
13593 				this.month = parseInt(params.month, 10) || 1;
13594 
13595 				/**
13596 				 * The day of the month. This ranges from 1 to 31.
13597 				 * @type number
13598 				 */
13599 				this.day = parseInt(params.day, 10) || 1;
13600 				
13601 				/**
13602 				 * The hour of the day. This can be a number from 0 to 23, as times are
13603 				 * stored unambiguously in the 24-hour clock.
13604 				 * @type number
13605 				 */
13606 				this.hour = parseInt(params.hour, 10) || 0;
13607 
13608 				/**
13609 				 * The minute of the hours. Ranges from 0 to 59.
13610 				 * @type number
13611 				 */
13612 				this.minute = parseInt(params.minute, 10) || 0;
13613 
13614 				/**
13615 				 * The second of the minute. Ranges from 0 to 59.
13616 				 * @type number
13617 				 */
13618 				this.second = parseInt(params.second, 10) || 0;
13619 
13620 				/**
13621 				 * The millisecond of the second. Ranges from 0 to 999.
13622 				 * @type number
13623 				 */
13624 				this.millisecond = parseInt(params.millisecond, 10) || 0;
13625 				
13626 				/**
13627 				 * The day of the year. Ranges from 1 to 366.
13628 				 * @type number
13629 				 */
13630 				this.dayOfYear = parseInt(params.dayOfYear, 10);
13631 
13632 				if (typeof(params.dst) === 'boolean') {
13633 					this.dst = params.dst;
13634 				}
13635 				
13636 				this.rd = this.newRd(this);
13637 				
13638 				// add the time zone offset to the rd to convert to UTC
13639 				if (!this.tz) {
13640 					this.tz = new TimeZone({id: this.timezone});
13641 				}
13642 				// getOffsetMillis requires that this.year, this.rd, and this.dst 
13643 				// are set in order to figure out which time zone rules apply and 
13644 				// what the offset is at that point in the year
13645 				this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
13646 				if (this.offset !== 0) {
13647 					this.rd = this.newRd({
13648 						rd: this.rd.getRataDie() - this.offset
13649 					});
13650 				}
13651 			}
13652 			
13653 			if (!this.rd) {
13654 				this.rd = this.newRd(params);
13655 				this._calcDateComponents();
13656 			}
13657 			
13658 			if (params && typeof(params.onLoad) === 'function') {
13659 				params.onLoad(this);
13660 			}
13661 		})
13662 	);
13663 };
13664 
13665 PersianDate.prototype = new IDate({noinstance: true});
13666 PersianDate.prototype.parent = IDate;
13667 PersianDate.prototype.constructor = PersianDate;
13668 
13669 /**
13670  * @private
13671  * @const
13672  * @type Array.<number>
13673  * the cumulative lengths of each month, for a non-leap year 
13674  */
13675 PersianDate.cumMonthLengths = [
13676     0,    // Farvardin
13677 	31,   // Ordibehesht
13678 	62,   // Khordad
13679 	93,   // Tir
13680 	124,  // Mordad
13681 	155,  // Shahrivar
13682 	186,  // Mehr
13683 	216,  // Aban
13684 	246,  // Azar
13685 	276,  // Dey
13686 	306,  // Bahman
13687 	336,  // Esfand
13688 	366
13689 ];
13690 
13691 /**
13692  * Return a new RD for this date type using the given params.
13693  * @protected
13694  * @param {Object=} params the parameters used to create this rata die instance
13695  * @returns {RataDie} the new RD instance for the given params
13696  */
13697 PersianDate.prototype.newRd = function (params) {
13698 	return new PersRataDie(params);
13699 };
13700 
13701 /**
13702  * Return the year for the given RD
13703  * @protected
13704  * @param {number} rd RD to calculate from 
13705  * @returns {number} the year for the RD
13706  */
13707 PersianDate.prototype._calcYear = function(rd) {
13708 	var julianday = rd + this.rd.epoch;
13709 	return this.rd._getYear(julianday).year;
13710 };
13711 
13712 /**
13713  * @private
13714  * Calculate date components for the given RD date.
13715  */
13716 PersianDate.prototype._calcDateComponents = function () {
13717 	var remainder,
13718 		rd = this.rd.getRataDie();
13719 	
13720 	this.year = this._calcYear(rd);
13721 	
13722 	if (typeof(this.offset) === "undefined") {
13723 		// now offset the RD by the time zone, then recalculate in case we were 
13724 		// near the year boundary
13725 		if (!this.tz) {
13726 			this.tz = new TimeZone({id: this.timezone});
13727 		}
13728 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
13729 	}
13730 	
13731 	if (this.offset !== 0) {
13732 		rd += this.offset;
13733 		this.year = this._calcYear(rd);
13734 	}
13735 	
13736 	//console.log("PersDate.calcComponent: calculating for rd " + rd);
13737 	//console.log("PersDate.calcComponent: year is " + ret.year);
13738 	var yearStart = this.newRd({
13739 		year: this.year,
13740 		month: 1,
13741 		day: 1,
13742 		hour: 0,
13743 		minute: 0,
13744 		second: 0,
13745 		millisecond: 0
13746 	});
13747 	remainder = rd - yearStart.getRataDie() + 1;
13748 	
13749 	this.dayOfYear = remainder;
13750 	
13751 	//console.log("PersDate.calcComponent: remainder is " + remainder);
13752 	
13753 	this.month = SearchUtils.bsearch(Math.floor(remainder), PersianDate.cumMonthLengths);
13754 	remainder -= PersianDate.cumMonthLengths[this.month-1];
13755 	
13756 	//console.log("PersDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
13757 	
13758 	this.day = Math.floor(remainder);
13759 	remainder -= this.day;
13760 	
13761 	//console.log("PersDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
13762 	
13763 	// now convert to milliseconds for the rest of the calculation
13764 	remainder = Math.round(remainder * 86400000);
13765 	
13766 	this.hour = Math.floor(remainder/3600000);
13767 	remainder -= this.hour * 3600000;
13768 	
13769 	this.minute = Math.floor(remainder/60000);
13770 	remainder -= this.minute * 60000;
13771 	
13772 	this.second = Math.floor(remainder/1000);
13773 	remainder -= this.second * 1000;
13774 	
13775 	this.millisecond = remainder;
13776 };
13777 
13778 /**
13779  * Return the day of the week of this date. The day of the week is encoded
13780  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
13781  * 
13782  * @return {number} the day of the week
13783  */
13784 PersianDate.prototype.getDayOfWeek = function() {
13785 	var rd = Math.floor(this.getRataDie());
13786 	return MathUtils.mod(rd-3, 7);
13787 };
13788 
13789 /**
13790  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
13791  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
13792  * December 31st is 365 in regular years, or 366 in leap years.
13793  * @return {number} the ordinal day of the year
13794  */
13795 PersianDate.prototype.getDayOfYear = function() {
13796 	return PersianDate.cumMonthLengths[this.month-1] + this.day;
13797 };
13798 
13799 /**
13800  * Return the era for this date as a number. The value for the era for Persian 
13801  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
13802  * persico or AP). 
13803  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
13804  * there is a year 0, so any years that are negative or zero are BP.
13805  * @return {number} 1 if this date is in the common era, -1 if it is before the 
13806  * common era 
13807  */
13808 PersianDate.prototype.getEra = function() {
13809 	return (this.year < 1) ? -1 : 1;
13810 };
13811 
13812 /**
13813  * Return the name of the calendar that governs this date.
13814  * 
13815  * @return {string} a string giving the name of the calendar
13816  */
13817 PersianDate.prototype.getCalendar = function() {
13818 	return "persian";
13819 };
13820 
13821 // register with the factory method
13822 IDate._constructors["persian"] = PersianDate;
13823 
13824 
13825 /*< PersianAlgoCal.js */
13826 /*
13827  * persian.js - Represent a Persian algorithmic calendar object.
13828  * 
13829  * Copyright © 2014-2015, JEDLSoft
13830  *
13831  * Licensed under the Apache License, Version 2.0 (the "License");
13832  * you may not use this file except in compliance with the License.
13833  * You may obtain a copy of the License at
13834  *
13835  *     http://www.apache.org/licenses/LICENSE-2.0
13836  *
13837  * Unless required by applicable law or agreed to in writing, software
13838  * distributed under the License is distributed on an "AS IS" BASIS,
13839  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13840  *
13841  * See the License for the specific language governing permissions and
13842  * limitations under the License.
13843  */
13844 
13845 
13846 /* !depends ilib.js Calendar.js MathUtils.js */
13847 
13848 
13849 /**
13850  * @class
13851  * Construct a new Persian algorithmic calendar object. This class encodes information about
13852  * a Persian algorithmic calendar.<p>
13853  * 
13854  * 
13855  * @constructor
13856  * @extends Calendar
13857  */
13858 var PersianAlgoCal = function() {
13859 	this.type = "persian-algo";
13860 };
13861 
13862 /**
13863  * @private
13864  * @const
13865  * @type Array.<number> 
13866  * the lengths of each month 
13867  */
13868 PersianAlgoCal.monthLengths = [
13869 	31,  // Farvardin
13870 	31,  // Ordibehesht
13871 	31,  // Khordad
13872 	31,  // Tir
13873 	31,  // Mordad
13874 	31,  // Shahrivar
13875 	30,  // Mehr
13876 	30,  // Aban
13877 	30,  // Azar
13878 	30,  // Dey
13879 	30,  // Bahman
13880 	29   // Esfand
13881 ];
13882 
13883 /**
13884  * Return the number of months in the given year. The number of months in a year varies
13885  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
13886  * days in a year to an entire solar year. The month is represented as a 1-based number
13887  * where 1=first month, 2=second month, etc.
13888  * 
13889  * @param {number} year a year for which the number of months is sought
13890  * @return {number} The number of months in the given year
13891  */
13892 PersianAlgoCal.prototype.getNumMonths = function(year) {
13893 	return 12;
13894 };
13895 
13896 /**
13897  * Return the number of days in a particular month in a particular year. This function
13898  * can return a different number for a month depending on the year because of things
13899  * like leap years.
13900  * 
13901  * @param {number} month the month for which the length is sought
13902  * @param {number} year the year within which that month can be found
13903  * @return {number} the number of days within the given month in the given year
13904  */
13905 PersianAlgoCal.prototype.getMonLength = function(month, year) {
13906 	if (month !== 12 || !this.isLeapYear(year)) {
13907 		return PersianAlgoCal.monthLengths[month-1];
13908 	} else {
13909 		// Month 12, Esfand, has 30 days instead of 29 in leap years
13910 		return 30;
13911 	}
13912 };
13913 
13914 /**
13915  * Return the equivalent year in the 2820 year cycle that begins on 
13916  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
13917  * whereas the others do not specifically. This cycle can be used as
13918  * a proxy for other years outside of the cycle by shifting them into 
13919  * the cycle.   
13920  * @param {number} year year to find the equivalent cycle year for
13921  * @returns {number} the equivalent cycle year
13922  */
13923 PersianAlgoCal.prototype.equivalentCycleYear = function(year) {
13924 	var y = year - (year >= 0 ? 474 : 473);
13925 	return MathUtils.mod(y, 2820) + 474;
13926 };
13927 
13928 /**
13929  * Return true if the given year is a leap year in the Persian calendar.
13930  * The year parameter may be given as a number, or as a PersAlgoDate object.
13931  * @param {number} year the year for which the leap year information is being sought
13932  * @return {boolean} true if the given year is a leap year
13933  */
13934 PersianAlgoCal.prototype.isLeapYear = function(year) {
13935 	return (MathUtils.mod((this.equivalentCycleYear(year) + 38) * 682, 2816) < 682);
13936 };
13937 
13938 /**
13939  * Return the type of this calendar.
13940  * 
13941  * @return {string} the name of the type of this calendar 
13942  */
13943 PersianAlgoCal.prototype.getType = function() {
13944 	return this.type;
13945 };
13946 
13947 /**
13948  * Return a date instance for this calendar type using the given
13949  * options.
13950  * @param {Object} options options controlling the construction of 
13951  * the date instance
13952  * @return {IDate} a date appropriate for this calendar type
13953  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
13954  */
13955 PersianAlgoCal.prototype.newDateInstance = function (options) {
13956 		return new PersianAlgoDate(options);
13957 };
13958 
13959 /* register this calendar for the factory method */
13960 Calendar._constructors["persian-algo"] = PersianAlgoCal;
13961 
13962 
13963 /*< PersAlgoRataDie.js */
13964 /*
13965  * PersAlsoRataDie.js - Represent an RD date in the Persian algorithmic calendar
13966  * 
13967  * Copyright © 2014-2015, JEDLSoft
13968  *
13969  * Licensed under the Apache License, Version 2.0 (the "License");
13970  * you may not use this file except in compliance with the License.
13971  * You may obtain a copy of the License at
13972  *
13973  *     http://www.apache.org/licenses/LICENSE-2.0
13974  *
13975  * Unless required by applicable law or agreed to in writing, software
13976  * distributed under the License is distributed on an "AS IS" BASIS,
13977  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13978  *
13979  * See the License for the specific language governing permissions and
13980  * limitations under the License.
13981  */
13982 
13983 /* !depends 
13984 PersianAlgoCal.js 
13985 MathUtils.js
13986 RataDie.js
13987 */
13988 
13989 
13990 /**
13991  * @class
13992  * Construct a new Persian RD date number object. The constructor parameters can 
13993  * contain any of the following properties:
13994  * 
13995  * <ul>
13996  * <li><i>unixtime<i> - sets the time of this instance according to the given 
13997  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
13998  * 
13999  * <li><i>julianday</i> - sets the time of this instance according to the given
14000  * Julian Day instance or the Julian Day given as a float
14001  * 
14002  * <li><i>year</i> - any integer, including 0
14003  * 
14004  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14005  * 
14006  * <li><i>day</i> - 1 to 31
14007  * 
14008  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14009  * is always done with an unambiguous 24 hour representation
14010  * 
14011  * <li><i>minute</i> - 0 to 59
14012  * 
14013  * <li><i>second</i> - 0 to 59
14014  * 
14015  * <li><i>millisecond</i> - 0 to 999
14016  * 
14017  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14018  * </ul>
14019  *
14020  * If the constructor is called with another Persian date instance instead of
14021  * a parameter block, the other instance acts as a parameter block and its
14022  * settings are copied into the current instance.<p>
14023  * 
14024  * If the constructor is called with no arguments at all or if none of the 
14025  * properties listed above are present, then the RD is calculate based on 
14026  * the current date at the time of instantiation. <p>
14027  * 
14028  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14029  * specified in the params, it is assumed that they have the smallest possible
14030  * value in the range for the property (zero or one).<p>
14031  * 
14032  * 
14033  * @private
14034  * @constructor
14035  * @extends RataDie
14036  * @param {Object=} params parameters that govern the settings and behaviour of this Persian RD date
14037  */
14038 var PersAlgoRataDie = function(params) {
14039 	this.cal = params && params.cal || new PersianAlgoCal();
14040 	this.rd = undefined;
14041 	RataDie.call(this, params);
14042 };
14043 
14044 PersAlgoRataDie.prototype = new RataDie();
14045 PersAlgoRataDie.prototype.parent = RataDie;
14046 PersAlgoRataDie.prototype.constructor = PersAlgoRataDie;
14047 
14048 /**
14049  * The difference between a zero Julian day and the first Persian date
14050  * @private
14051  * @const
14052  * @type number
14053  */
14054 PersAlgoRataDie.prototype.epoch = 1948319.5;
14055 
14056 /**
14057  * @private
14058  * @const
14059  * @type Array.<number>
14060  * the cumulative lengths of each month, for a non-leap year 
14061  */
14062 PersAlgoRataDie.cumMonthLengths = [
14063     0,    // Farvardin
14064 	31,   // Ordibehesht
14065 	62,   // Khordad
14066 	93,   // Tir
14067 	124,  // Mordad
14068 	155,  // Shahrivar
14069 	186,  // Mehr
14070 	216,  // Aban
14071 	246,  // Azar
14072 	276,  // Dey
14073 	306,  // Bahman
14074 	336,  // Esfand
14075 	365
14076 ];
14077 
14078 /**
14079  * Calculate the Rata Die (fixed day) number of the given date from the
14080  * date components.
14081  *
14082  * @protected
14083  * @param {Object} date the date components to calculate the RD from
14084  */
14085 PersAlgoRataDie.prototype._setDateComponents = function(date) {
14086 	var year = this.cal.equivalentCycleYear(date.year);
14087 	var y = date.year - (date.year >= 0 ? 474 : 473);
14088 	var rdOfYears = 1029983 * Math.floor(y/2820) + 365 * (year - 1) + Math.floor((682 * year - 110) / 2816);
14089 	var dayInYear = (date.month > 1 ? PersAlgoRataDie.cumMonthLengths[date.month-1] : 0) + date.day;
14090 	var rdtime = (date.hour * 3600000 +
14091 		date.minute * 60000 +
14092 		date.second * 1000 +
14093 		date.millisecond) /
14094 		86400000;
14095 	
14096 	/*
14097 	// console.log("getRataDie: converting " +  JSON.stringify(this));
14098 	console.log("getRataDie: year is " +  year);
14099 	console.log("getRataDie: rd of years is " +  rdOfYears);
14100 	console.log("getRataDie: day in year is " +  dayInYear);
14101 	console.log("getRataDie: rdtime is " +  rdtime);
14102 	console.log("getRataDie: rd is " +  (rdOfYears + dayInYear + rdtime));
14103 	*/
14104 	
14105 	this.rd = rdOfYears + dayInYear + rdtime;
14106 };
14107 
14108 /**
14109  * Return the rd number of the particular day of the week on or before the 
14110  * given rd. eg. The Sunday on or before the given rd.
14111  * @private
14112  * @param {number} rd the rata die date of the reference date
14113  * @param {number} dayOfWeek the day of the week that is being sought relative 
14114  * to the current date
14115  * @return {number} the rd of the day of the week
14116  */
14117 PersAlgoRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
14118 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 3, 7);
14119 };
14120 
14121 
14122 /*< PersianAlgoDate.js */
14123 /*
14124  * PersianAlgoDate.js - Represent a date in the Persian algorithmic calendar
14125  * 
14126  * Copyright © 2014-2015, JEDLSoft
14127  *
14128  * Licensed under the Apache License, Version 2.0 (the "License");
14129  * you may not use this file except in compliance with the License.
14130  * You may obtain a copy of the License at
14131  *
14132  *     http://www.apache.org/licenses/LICENSE-2.0
14133  *
14134  * Unless required by applicable law or agreed to in writing, software
14135  * distributed under the License is distributed on an "AS IS" BASIS,
14136  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14137  *
14138  * See the License for the specific language governing permissions and
14139  * limitations under the License.
14140  */
14141 
14142 /* !depends 
14143 ilib.js
14144 Locale.js
14145 LocaleInfo.js
14146 TimeZone.js
14147 IDate.js
14148 PersianAlgoCal.js 
14149 SearchUtils.js
14150 MathUtils.js
14151 PersAlgoRataDie.js
14152 */
14153 
14154 
14155 
14156 
14157 /**
14158  * @class
14159  * 
14160  * Construct a new Persian date object. The constructor parameters can 
14161  * contain any of the following properties:
14162  * 
14163  * <ul>
14164  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14165  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14166  * 
14167  * <li><i>julianday</i> - sets the time of this instance according to the given
14168  * Julian Day instance or the Julian Day given as a float
14169  * 
14170  * <li><i>year</i> - any integer, including 0
14171  * 
14172  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14173  * 
14174  * <li><i>day</i> - 1 to 31
14175  * 
14176  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14177  * is always done with an unambiguous 24 hour representation
14178  * 
14179  * <li><i>minute</i> - 0 to 59
14180  * 
14181  * <li><i>second</i> - 0 to 59
14182  * 
14183  * <li><i>millisecond</i> - 0 to 999
14184  * 
14185  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
14186  * of this persian date. The date/time is kept in the local time. The time zone
14187  * is used later if this date is formatted according to a different time zone and
14188  * the difference has to be calculated, or when the date format has a time zone
14189  * component in it.
14190  * 
14191  * <li><i>locale</i> - locale for this persian date. If the time zone is not 
14192  * given, it can be inferred from this locale. For locales that span multiple
14193  * time zones, the one with the largest population is chosen as the one that 
14194  * represents the locale.
14195  * 
14196  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14197  * </ul>
14198  *
14199  * If the constructor is called with another Persian date instance instead of
14200  * a parameter block, the other instance acts as a parameter block and its
14201  * settings are copied into the current instance.<p>
14202  * 
14203  * If the constructor is called with no arguments at all or if none of the 
14204  * properties listed above 
14205  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
14206  * components are 
14207  * filled in with the current date at the time of instantiation. Note that if
14208  * you do not give the time zone when defaulting to the current time and the 
14209  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
14210  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
14211  * Mean Time").<p>
14212  * 
14213  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14214  * specified in the params, it is assumed that they have the smallest possible
14215  * value in the range for the property (zero or one).<p>
14216  * 
14217  * 
14218  * @constructor
14219  * @extends IDate
14220  * @param {Object=} params parameters that govern the settings and behaviour of this Persian date
14221  */
14222 var PersianAlgoDate = function(params) {
14223 	this.cal = new PersianAlgoCal();
14224 	this.timezone = "local";
14225 	
14226 	if (params) {
14227 		if (params.locale) {
14228 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
14229 			var li = new LocaleInfo(this.locale);
14230 			this.timezone = li.getTimeZone(); 
14231 		}
14232 		if (params.timezone) {
14233 			this.timezone = params.timezone;
14234 		}
14235 		
14236 		if (params.year || params.month || params.day || params.hour ||
14237 				params.minute || params.second || params.millisecond ) {
14238 			/**
14239 			 * Year in the Persian calendar.
14240 			 * @type number
14241 			 */
14242 			this.year = parseInt(params.year, 10) || 0;
14243 
14244 			/**
14245 			 * The month number, ranging from 1 to 12
14246 			 * @type number
14247 			 */
14248 			this.month = parseInt(params.month, 10) || 1;
14249 
14250 			/**
14251 			 * The day of the month. This ranges from 1 to 31.
14252 			 * @type number
14253 			 */
14254 			this.day = parseInt(params.day, 10) || 1;
14255 			
14256 			/**
14257 			 * The hour of the day. This can be a number from 0 to 23, as times are
14258 			 * stored unambiguously in the 24-hour clock.
14259 			 * @type number
14260 			 */
14261 			this.hour = parseInt(params.hour, 10) || 0;
14262 
14263 			/**
14264 			 * The minute of the hours. Ranges from 0 to 59.
14265 			 * @type number
14266 			 */
14267 			this.minute = parseInt(params.minute, 10) || 0;
14268 
14269 			/**
14270 			 * The second of the minute. Ranges from 0 to 59.
14271 			 * @type number
14272 			 */
14273 			this.second = parseInt(params.second, 10) || 0;
14274 
14275 			/**
14276 			 * The millisecond of the second. Ranges from 0 to 999.
14277 			 * @type number
14278 			 */
14279 			this.millisecond = parseInt(params.millisecond, 10) || 0;
14280 			
14281 			/**
14282 			 * The day of the year. Ranges from 1 to 366.
14283 			 * @type number
14284 			 */
14285 			this.dayOfYear = parseInt(params.dayOfYear, 10);
14286 
14287 			if (typeof(params.dst) === 'boolean') {
14288 				this.dst = params.dst;
14289 			}
14290 			
14291 			this.rd = this.newRd(this);
14292 			
14293 			// add the time zone offset to the rd to convert to UTC
14294 			if (!this.tz) {
14295 				this.tz = new TimeZone({id: this.timezone});
14296 			}
14297 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
14298 			// are set in order to figure out which time zone rules apply and 
14299 			// what the offset is at that point in the year
14300 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
14301 			if (this.offset !== 0) {
14302 				this.rd = this.newRd({
14303 					rd: this.rd.getRataDie() - this.offset
14304 				});
14305 			}
14306 		}
14307 	}
14308 
14309 	if (!this.rd) {
14310 		this.rd = this.newRd(params);
14311 		this._calcDateComponents();
14312 	}
14313 };
14314 
14315 PersianAlgoDate.prototype = new IDate({noinstance: true});
14316 PersianAlgoDate.prototype.parent = IDate;
14317 PersianAlgoDate.prototype.constructor = PersianAlgoDate;
14318 
14319 /**
14320  * Return a new RD for this date type using the given params.
14321  * @protected
14322  * @param {Object=} params the parameters used to create this rata die instance
14323  * @returns {RataDie} the new RD instance for the given params
14324  */
14325 PersianAlgoDate.prototype.newRd = function (params) {
14326 	return new PersAlgoRataDie(params);
14327 };
14328 
14329 /**
14330  * Return the year for the given RD
14331  * @protected
14332  * @param {number} rd RD to calculate from 
14333  * @returns {number} the year for the RD
14334  */
14335 PersianAlgoDate.prototype._calcYear = function(rd) {
14336 	var shiftedRd = rd - 173126;
14337 	var numberOfCycles = Math.floor(shiftedRd / 1029983);
14338 	var shiftedDayInCycle = MathUtils.mod(shiftedRd, 1029983);
14339 	var yearInCycle = (shiftedDayInCycle === 1029982) ? 2820 : Math.floor((2816 * shiftedDayInCycle + 1031337) / 1028522);
14340 	var year = 474 + 2820 * numberOfCycles + yearInCycle;
14341 	return (year > 0) ? year : year - 1;
14342 };
14343 
14344 /**
14345  * @private
14346  * Calculate date components for the given RD date.
14347  */
14348 PersianAlgoDate.prototype._calcDateComponents = function () {
14349 	var remainder,
14350 		rd = this.rd.getRataDie();
14351 	
14352 	this.year = this._calcYear(rd);
14353 	
14354 	if (typeof(this.offset) === "undefined") {
14355 		// now offset the RD by the time zone, then recalculate in case we were 
14356 		// near the year boundary
14357 		if (!this.tz) {
14358 			this.tz = new TimeZone({id: this.timezone});
14359 		}
14360 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
14361 	}
14362 	
14363 	if (this.offset !== 0) {
14364 		rd += this.offset;
14365 		this.year = this._calcYear(rd);
14366 	}
14367 	
14368 	//console.log("PersAlgoDate.calcComponent: calculating for rd " + rd);
14369 	//console.log("PersAlgoDate.calcComponent: year is " + ret.year);
14370 	var yearStart = this.newRd({
14371 		year: this.year,
14372 		month: 1,
14373 		day: 1,
14374 		hour: 0,
14375 		minute: 0,
14376 		second: 0,
14377 		millisecond: 0
14378 	});
14379 	remainder = rd - yearStart.getRataDie() + 1;
14380 	
14381 	this.dayOfYear = remainder;
14382 	
14383 	//console.log("PersAlgoDate.calcComponent: remainder is " + remainder);
14384 	
14385 	this.month = SearchUtils.bsearch(remainder, PersAlgoRataDie.cumMonthLengths);
14386 	remainder -= PersAlgoRataDie.cumMonthLengths[this.month-1];
14387 	
14388 	//console.log("PersAlgoDate.calcComponent: month is " + this.month + " and remainder is " + remainder);
14389 	
14390 	this.day = Math.floor(remainder);
14391 	remainder -= this.day;
14392 	
14393 	//console.log("PersAlgoDate.calcComponent: day is " + this.day + " and remainder is " + remainder);
14394 	
14395 	// now convert to milliseconds for the rest of the calculation
14396 	remainder = Math.round(remainder * 86400000);
14397 	
14398 	this.hour = Math.floor(remainder/3600000);
14399 	remainder -= this.hour * 3600000;
14400 	
14401 	this.minute = Math.floor(remainder/60000);
14402 	remainder -= this.minute * 60000;
14403 	
14404 	this.second = Math.floor(remainder/1000);
14405 	remainder -= this.second * 1000;
14406 	
14407 	this.millisecond = remainder;
14408 };
14409 
14410 /**
14411  * Return the day of the week of this date. The day of the week is encoded
14412  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
14413  * 
14414  * @return {number} the day of the week
14415  */
14416 PersianAlgoDate.prototype.getDayOfWeek = function() {
14417 	var rd = Math.floor(this.getRataDie());
14418 	return MathUtils.mod(rd-3, 7);
14419 };
14420 
14421 /**
14422  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
14423  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
14424  * December 31st is 365 in regular years, or 366 in leap years.
14425  * @return {number} the ordinal day of the year
14426  */
14427 PersianAlgoDate.prototype.getDayOfYear = function() {
14428 	return PersAlgoRataDie.cumMonthLengths[this.month-1] + this.day;
14429 };
14430 
14431 /**
14432  * Return the era for this date as a number. The value for the era for Persian 
14433  * calendars is -1 for "before the persian era" (BP) and 1 for "the persian era" (anno 
14434  * persico or AP). 
14435  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Persian calendar, 
14436  * there is a year 0, so any years that are negative or zero are BP.
14437  * @return {number} 1 if this date is in the common era, -1 if it is before the 
14438  * common era 
14439  */
14440 PersianAlgoDate.prototype.getEra = function() {
14441 	return (this.year < 1) ? -1 : 1;
14442 };
14443 
14444 /**
14445  * Return the name of the calendar that governs this date.
14446  * 
14447  * @return {string} a string giving the name of the calendar
14448  */
14449 PersianAlgoDate.prototype.getCalendar = function() {
14450 	return "persian-algo";
14451 };
14452 
14453 // register with the factory method
14454 IDate._constructors["persian-algo"] = PersianAlgoDate;
14455 
14456 
14457 /*< HanCal.js */
14458 /*
14459  * han.js - Represent a Han Chinese Lunar calendar object.
14460  * 
14461  * Copyright © 2014-2015, JEDLSoft
14462  *
14463  * Licensed under the Apache License, Version 2.0 (the "License");
14464  * you may not use this file except in compliance with the License.
14465  * You may obtain a copy of the License at
14466  *
14467  *     http://www.apache.org/licenses/LICENSE-2.0
14468  *
14469  * Unless required by applicable law or agreed to in writing, software
14470  * distributed under the License is distributed on an "AS IS" BASIS,
14471  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14472  *
14473  * See the License for the specific language governing permissions and
14474  * limitations under the License.
14475  */
14476 
14477 /* !depends 
14478 ilib.js 
14479 Calendar.js 
14480 MathUtils.js 
14481 Astro.js
14482 GregorianDate.js
14483 GregRataDie.js
14484 RataDie.js
14485 */
14486 
14487 
14488 
14489 
14490 /**
14491  * @class
14492  * Construct a new Han algorithmic calendar object. This class encodes information about
14493  * a Han algorithmic calendar.<p>
14494  * 
14495  * 
14496  * @constructor
14497  * @param {Object=} params optional parameters to load the calendrical data
14498  * @extends Calendar
14499  */
14500 var HanCal = function(params) {
14501 	this.type = "han";
14502 	var sync = params && typeof(params.sync) === 'boolean' ? params.sync : true;
14503 	
14504 	Astro.initAstro(sync, params && params.loadParams, /** @type {function ((Object|null)=): ?} */ ilib.bind(this, function (x) {
14505 		if (params && typeof(params.callback) === 'function') {
14506 			params.callback(this);
14507 		}
14508 	}));
14509 };
14510 
14511 /**
14512  * @protected
14513  * @static
14514  * @param {number} year
14515  * @param {number=} cycle
14516  * @return {number}
14517  */
14518 HanCal._getElapsedYear = function(year, cycle) {
14519 	var elapsedYear = year || 0;
14520 	if (typeof(year) !== 'undefined' && year < 61 && typeof(cycle) !== 'undefined') {
14521 		elapsedYear = 60 * cycle + year;
14522 	}
14523 	return elapsedYear;
14524 };
14525 
14526 /**
14527  * @protected
14528  * @static
14529  * @param {number} jd julian day to calculate from
14530  * @param {number} longitude longitude to seek 
14531  * @returns {number} the julian day of the next time that the solar longitude 
14532  * is a multiple of the given longitude
14533  */
14534 HanCal._hanNextSolarLongitude = function(jd, longitude) {
14535 	var tz = HanCal._chineseTZ(jd);
14536 	var uni = Astro._universalFromLocal(jd, tz);
14537 	var sol = Astro._nextSolarLongitude(uni, longitude);
14538 	return Astro._localFromUniversal(sol, tz);
14539 };
14540 
14541 /**
14542  * @protected
14543  * @static
14544  * @param {number} jd julian day to calculate from 
14545  * @returns {number} the major solar term for the julian day
14546  */
14547 HanCal._majorSTOnOrAfter = function(jd) {
14548 	var tz = HanCal._chineseTZ(jd);
14549 	var uni = Astro._universalFromLocal(jd, tz);
14550 	var next = Astro._fixangle(30 * Math.ceil(Astro._solarLongitude(uni)/30));
14551 	return HanCal._hanNextSolarLongitude(jd, next);
14552 };
14553 
14554 /**
14555  * @protected
14556  * @static
14557  * @param {number} year the year for which the leap year information is being sought
14558  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14559  * cycle is not given, then the year should be given as elapsed years since the beginning
14560  * of the epoch
14561  */
14562 HanCal._solsticeBefore = function (year, cycle) {
14563 	var elapsedYear = HanCal._getElapsedYear(year, cycle);
14564 	var gregyear = elapsedYear - 2697;
14565 	var rd = new GregRataDie({
14566 		year: gregyear-1, 
14567 		month: 12, 
14568 		day: 15, 
14569 		hour: 0, 
14570 		minute: 0, 
14571 		second: 0, 
14572 		millisecond: 0
14573 	});
14574 	return HanCal._majorSTOnOrAfter(rd.getRataDie() + RataDie.gregorianEpoch);
14575 };
14576 
14577 /**
14578  * @protected
14579  * @static
14580  * @param {number} jd julian day to calculate from
14581  * @returns {number} the current major solar term
14582  */
14583 HanCal._chineseTZ = function(jd) {
14584 	var year = GregorianDate._calcYear(jd - RataDie.gregorianEpoch);
14585 	return year < 1929 ? 465.6666666666666666 : 480;
14586 };
14587 
14588 /**
14589  * @protected
14590  * @static
14591  * @param {number} jd julian day to calculate from 
14592  * @returns {number} the julian day of next new moon on or after the given julian day date
14593  */
14594 HanCal._newMoonOnOrAfter = function(jd) {
14595 	var tz = HanCal._chineseTZ(jd);
14596 	var uni = Astro._universalFromLocal(jd, tz);
14597 	var moon = Astro._newMoonAtOrAfter(uni);
14598 	// floor to the start of the julian day
14599 	return Astro._floorToJD(Astro._localFromUniversal(moon, tz)); 
14600 };
14601 
14602 /**
14603  * @protected
14604  * @static
14605  * @param {number} jd julian day to calculate from 
14606  * @returns {number} the julian day of previous new moon before the given julian day date
14607  */
14608 HanCal._newMoonBefore = function(jd) {
14609 	var tz = HanCal._chineseTZ(jd);
14610 	var uni = Astro._universalFromLocal(jd, tz);
14611 	var moon = Astro._newMoonBefore(uni);
14612 	// floor to the start of the julian day
14613 	return Astro._floorToJD(Astro._localFromUniversal(moon, tz));
14614 };
14615 
14616 /**
14617  * @static
14618  * @protected
14619  * @param {number} year the year for which the leap year information is being sought
14620  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14621  * cycle is not given, then the year should be given as elapsed years since the beginning
14622  * of the epoch
14623  */
14624 HanCal._leapYearCalc = function(year, cycle) {
14625 	var ret = {
14626 		elapsedYear: HanCal._getElapsedYear(year, cycle)
14627 	};
14628 	ret.solstice1 = HanCal._solsticeBefore(ret.elapsedYear);
14629 	ret.solstice2 = HanCal._solsticeBefore(ret.elapsedYear+1);
14630 	// ceil to the end of the julian day
14631 	ret.m1 = HanCal._newMoonOnOrAfter(Astro._ceilToJD(ret.solstice1));
14632 	ret.m2 = HanCal._newMoonBefore(Astro._ceilToJD(ret.solstice2));
14633 	
14634 	return ret;
14635 };
14636 
14637 /**
14638  * @protected
14639  * @static
14640  * @param {number} jd julian day to calculate from
14641  * @returns {number} the current major solar term
14642  */
14643 HanCal._currentMajorST = function(jd) {
14644 	var s = Astro._solarLongitude(Astro._universalFromLocal(jd, HanCal._chineseTZ(jd)));
14645 	return MathUtils.amod(2 + Math.floor(s/30), 12);
14646 };
14647 
14648 /**
14649  * @protected
14650  * @static
14651  * @param {number} jd julian day to calculate from
14652  * @returns {boolean} true if there is no major solar term in the same year
14653  */
14654 HanCal._noMajorST = function(jd) {
14655 	return HanCal._currentMajorST(jd) === HanCal._currentMajorST(HanCal._newMoonOnOrAfter(jd+1));
14656 };
14657 
14658 /**
14659  * Return the number of months in the given year. The number of months in a year varies
14660  * for some luni-solar calendars because in some years, an extra month is needed to extend the 
14661  * days in a year to an entire solar year. The month is represented as a 1-based number
14662  * where 1=first month, 2=second month, etc.
14663  * 
14664  * @param {number} year a year for which the number of months is sought
14665  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14666  * cycle is not given, then the year should be given as elapsed years since the beginning
14667  * of the epoch
14668  * @return {number} The number of months in the given year
14669  */
14670 HanCal.prototype.getNumMonths = function(year, cycle) {
14671 	return this.isLeapYear(year, cycle) ? 13 : 12;
14672 };
14673 
14674 /**
14675  * Return the number of days in a particular month in a particular year. This function
14676  * can return a different number for a month depending on the year because of things
14677  * like leap years.
14678  * 
14679  * @param {number} month the elapsed month for which the length is sought
14680  * @param {number} year the elapsed year within which that month can be found
14681  * @return {number} the number of days within the given month in the given year
14682  */
14683 HanCal.prototype.getMonLength = function(month, year) {
14684 	// distance between two new moons in Nanjing China
14685 	var calc = HanCal._leapYearCalc(year);
14686 	var priorNewMoon = HanCal._newMoonOnOrAfter(calc.m1 + month * 29);
14687 	var postNewMoon = HanCal._newMoonOnOrAfter(priorNewMoon + 1);
14688 	return postNewMoon - priorNewMoon;
14689 };
14690 
14691 /**
14692  * Return the equivalent year in the 2820 year cycle that begins on 
14693  * Far 1, 474. This particular cycle obeys the cycle-of-years formula 
14694  * whereas the others do not specifically. This cycle can be used as
14695  * a proxy for other years outside of the cycle by shifting them into 
14696  * the cycle.   
14697  * @param {number} year year to find the equivalent cycle year for
14698  * @returns {number} the equivalent cycle year
14699  */
14700 HanCal.prototype.equivalentCycleYear = function(year) {
14701 	var y = year - (year >= 0 ? 474 : 473);
14702 	return MathUtils.mod(y, 2820) + 474;
14703 };
14704 
14705 /**
14706  * Return true if the given year is a leap year in the Han calendar.
14707  * If the year is given as a year/cycle combination, then the year should be in the 
14708  * range [1,60] and the given cycle is the cycle in which the year is located. If 
14709  * the year is greater than 60, then
14710  * it represents the total number of years elapsed in the proleptic calendar since
14711  * the beginning of the Chinese epoch in on 15 Feb, -2636 (Gregorian). In this 
14712  * case, the cycle parameter is ignored.
14713  * 
14714  * @param {number} year the year for which the leap year information is being sought
14715  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14716  * cycle is not given, then the year should be given as elapsed years since the beginning
14717  * of the epoch
14718  * @return {boolean} true if the given year is a leap year
14719  */
14720 HanCal.prototype.isLeapYear = function(year, cycle) {
14721 	var calc = HanCal._leapYearCalc(year, cycle);
14722 	return Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
14723 };
14724 
14725 /**
14726  * Return the month of the year that is the leap month. If the given year is
14727  * not a leap year, then this method will return -1.
14728  * 
14729  * @param {number} year the year for which the leap year information is being sought
14730  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14731  * cycle is not given, then the year should be given as elapsed years since the beginning
14732  * of the epoch
14733  * @return {number} the number of the month that is doubled in this leap year, or -1
14734  * if this is not a leap year
14735  */
14736 HanCal.prototype.getLeapMonth = function(year, cycle) {
14737 	var calc = HanCal._leapYearCalc(year, cycle);
14738 	
14739 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) != 12) {
14740 		return -1; // no leap month
14741 	}
14742 	
14743 	// search between rd1 and rd2 for the first month with no major solar term. That is our leap month.
14744 	var month = 0;
14745 	var m = HanCal._newMoonOnOrAfter(calc.m1+1);
14746 	while (!HanCal._noMajorST(m)) {
14747 		month++;
14748 		m = HanCal._newMoonOnOrAfter(m+1);
14749 	}
14750 	
14751 	// return the number of the month that is doubled
14752 	return month; 
14753 };
14754 
14755 /**
14756  * Return the date of Chinese New Years in the given calendar year.
14757  * 
14758  * @param {number} year the Chinese year for which the new year information is being sought
14759  * @param {number=} cycle if the given year < 60, this can specify the cycle. If the
14760  * cycle is not given, then the year should be given as elapsed years since the beginning
14761  * of the epoch
14762  * @return {number} the julian day of the beginning of the given year 
14763  */
14764 HanCal.prototype.newYears = function(year, cycle) {
14765 	var calc = HanCal._leapYearCalc(year, cycle);
14766 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
14767 	if (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12 &&
14768 			(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2)) ) {
14769 		return HanCal._newMoonOnOrAfter(m2+1);
14770 	}
14771 	return m2;
14772 };
14773 
14774 /**
14775  * Return the type of this calendar.
14776  * 
14777  * @return {string} the name of the type of this calendar 
14778  */
14779 HanCal.prototype.getType = function() {
14780 	return this.type;
14781 };
14782 
14783 /**
14784  * Return a date instance for this calendar type using the given
14785  * options.
14786  * @param {Object} options options controlling the construction of 
14787  * the date instance
14788  * @return {HanDate} a date appropriate for this calendar type
14789  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
14790  */
14791 HanCal.prototype.newDateInstance = function (options) {
14792 		return new HanDate(options);
14793 };
14794 
14795 /* register this calendar for the factory method */
14796 Calendar._constructors["han"] = HanCal;
14797 
14798 
14799 /*< HanRataDie.js */
14800 /*
14801  * HanDate.js - Represent a date in the Han algorithmic calendar
14802  * 
14803  * Copyright © 2014-2015, JEDLSoft
14804  *
14805  * Licensed under the Apache License, Version 2.0 (the "License");
14806  * you may not use this file except in compliance with the License.
14807  * You may obtain a copy of the License at
14808  *
14809  *     http://www.apache.org/licenses/LICENSE-2.0
14810  *
14811  * Unless required by applicable law or agreed to in writing, software
14812  * distributed under the License is distributed on an "AS IS" BASIS,
14813  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14814  *
14815  * See the License for the specific language governing permissions and
14816  * limitations under the License.
14817  */
14818 
14819 /* !depends
14820 ilib.js
14821 HanCal.js
14822 MathUtils.js
14823 RataDie.js
14824 */
14825 
14826 
14827 /**
14828  * Construct a new Han RD date number object. The constructor parameters can 
14829  * contain any of the following properties:
14830  * 
14831  * <ul>
14832  * <li><i>unixtime<i> - sets the time of this instance according to the given 
14833  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
14834  * 
14835  * <li><i>julianday</i> - sets the time of this instance according to the given
14836  * Julian Day instance or the Julian Day given as a float
14837  * 
14838  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
14839  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
14840  * linear count of years since the beginning of the epoch, much like other calendars. This linear
14841  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
14842  * to 60 and treated as if it were a year in the regular 60-year cycle.
14843  * 
14844  * <li><i>year</i> - any integer, including 0
14845  * 
14846  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
14847  * 
14848  * <li><i>day</i> - 1 to 31
14849  * 
14850  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
14851  * is always done with an unambiguous 24 hour representation
14852  * 
14853  * <li><i>minute</i> - 0 to 59
14854  * 
14855  * <li><i>second</i> - 0 to 59
14856  * 
14857  * <li><i>millisecond</i> - 0 to 999
14858  * 
14859  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
14860  * </ul>
14861  *
14862  * If the constructor is called with another Han date instance instead of
14863  * a parameter block, the other instance acts as a parameter block and its
14864  * settings are copied into the current instance.<p>
14865  * 
14866  * If the constructor is called with no arguments at all or if none of the 
14867  * properties listed above are present, then the RD is calculate based on 
14868  * the current date at the time of instantiation. <p>
14869  * 
14870  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
14871  * specified in the params, it is assumed that they have the smallest possible
14872  * value in the range for the property (zero or one).<p>
14873  * 
14874  * 
14875  * @private
14876  * @class
14877  * @constructor
14878  * @extends RataDie
14879  * @param {Object=} params parameters that govern the settings and behaviour of this Han RD date
14880  */
14881 var HanRataDie = function(params) {
14882 	this.rd = undefined;
14883 	if (params && params.cal) {
14884 		this.cal = params.cal;
14885 		RataDie.call(this, params);
14886 		if (params && typeof(params.callback) === 'function') {
14887 			params.callback(this);
14888 		}
14889 	} else {
14890 		new HanCal({
14891 			sync: params && params.sync,
14892 			loadParams: params && params.loadParams,
14893 			callback: ilib.bind(this, function(c) {
14894 				this.cal = c;
14895 				RataDie.call(this, params);
14896 				if (params && typeof(params.callback) === 'function') {
14897 					params.callback(this);
14898 				}
14899 			})
14900 		});
14901 	}
14902 };
14903 
14904 HanRataDie.prototype = new RataDie();
14905 HanRataDie.prototype.parent = RataDie;
14906 HanRataDie.prototype.constructor = HanRataDie;
14907 
14908 /**
14909  * The difference between a zero Julian day and the first Han date
14910  * which is February 15, -2636 (Gregorian).
14911  * @private
14912  * @const
14913  * @type number
14914  */
14915 HanRataDie.epoch = 758325.5;
14916 
14917 /**
14918  * Calculate the Rata Die (fixed day) number of the given date from the
14919  * date components.
14920  *
14921  * @protected
14922  * @param {Object} date the date components to calculate the RD from
14923  */
14924 HanRataDie.prototype._setDateComponents = function(date) {
14925 	var calc = HanCal._leapYearCalc(date.year, date.cycle);
14926 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
14927 	var newYears;
14928 	this.leapYear = (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12);
14929 	if (this.leapYear && (HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2)) ) {
14930 		newYears = HanCal._newMoonOnOrAfter(m2+1);
14931 	} else {
14932 		newYears = m2;
14933 	}
14934 
14935 	var priorNewMoon = HanCal._newMoonOnOrAfter(calc.m1 + date.month * 29); // this is a julian day
14936 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(priorNewMoon));
14937 	this.leapMonth = (this.leapYear && HanCal._noMajorST(priorNewMoon) && !this.priorLeapMonth);
14938 
14939 	var rdtime = (date.hour * 3600000 +
14940 		date.minute * 60000 +
14941 		date.second * 1000 +
14942 		date.millisecond) /
14943 		86400000;
14944 	
14945 	/*
14946 	console.log("getRataDie: converting " +  JSON.stringify(date) + " to an RD");
14947 	console.log("getRataDie: year is " +  date.year + " plus cycle " + date.cycle);
14948 	console.log("getRataDie: isLeapYear is " +  this.leapYear);
14949 	console.log("getRataDie: priorNewMoon is " +  priorNewMoon);
14950 	console.log("getRataDie: day in month is " +  date.day);
14951 	console.log("getRataDie: rdtime is " +  rdtime);
14952 	console.log("getRataDie: rd is " +  (priorNewMoon + date.day - 1 + rdtime));
14953 	*/
14954 	
14955 	this.rd = priorNewMoon + date.day - 1 + rdtime - RataDie.gregorianEpoch;
14956 };
14957 
14958 /**
14959  * Return the rd number of the particular day of the week on or before the 
14960  * given rd. eg. The Sunday on or before the given rd.
14961  * @private
14962  * @param {number} rd the rata die date of the reference date
14963  * @param {number} dayOfWeek the day of the week that is being sought relative 
14964  * to the current date
14965  * @return {number} the rd of the day of the week
14966  */
14967 HanRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
14968 	return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7);
14969 };
14970 
14971 /**
14972  * @protected
14973  * @static
14974  * @param {number} jd1 first julian day
14975  * @param {number} jd2 second julian day
14976  * @returns {boolean} true if there is a leap month earlier in the same year 
14977  * as the given months 
14978  */
14979 HanRataDie._priorLeapMonth = function(jd1, jd2) {
14980 	return jd2 >= jd1 &&
14981 		(HanRataDie._priorLeapMonth(jd1, HanCal._newMoonBefore(jd2)) ||
14982 				HanCal._noMajorST(jd2));
14983 };
14984 
14985 
14986 
14987 /*< HanDate.js */
14988 /*
14989  * HanDate.js - Represent a date in the Han algorithmic calendar
14990  * 
14991  * Copyright © 2014-2015, JEDLSoft
14992  *
14993  * Licensed under the Apache License, Version 2.0 (the "License");
14994  * you may not use this file except in compliance with the License.
14995  * You may obtain a copy of the License at
14996  *
14997  *     http://www.apache.org/licenses/LICENSE-2.0
14998  *
14999  * Unless required by applicable law or agreed to in writing, software
15000  * distributed under the License is distributed on an "AS IS" BASIS,
15001  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15002  *
15003  * See the License for the specific language governing permissions and
15004  * limitations under the License.
15005  */
15006 
15007 /* !depends
15008 ilib.js
15009 IDate.js
15010 GregorianDate.js 
15011 HanCal.js
15012 Astro.js 
15013 JSUtils.js
15014 MathUtils.js
15015 LocaleInfo.js 
15016 Locale.js
15017 TimeZone.js
15018 HanRataDie.js
15019 RataDie.js
15020 */
15021 
15022 
15023 
15024 
15025 /**
15026  * @class
15027  * 
15028  * Construct a new Han date object. The constructor parameters can 
15029  * contain any of the following properties:
15030  * 
15031  * <ul>
15032  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15033  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian
15034  * 
15035  * <li><i>julianday</i> - sets the time of this instance according to the given
15036  * Julian Day instance or the Julian Day given as a float
15037  * 
15038  * <li><i>cycle</i> - any integer giving the number of 60-year cycle in which the date is located.
15039  * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 
15040  * linear count of years since the beginning of the epoch, much like other calendars. This linear
15041  * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 
15042  * to 60 and treated as if it were a year in the regular 60-year cycle.
15043  * 
15044  * <li><i>year</i> - any integer, including 0
15045  * 
15046  * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc.
15047  * 
15048  * <li><i>day</i> - 1 to 31
15049  * 
15050  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15051  * is always done with an unambiguous 24 hour representation
15052  * 
15053  * <li><i>minute</i> - 0 to 59
15054  * 
15055  * <li><i>second</i> - 0 to 59
15056  * 
15057  * <li><i>millisecond</i> - 0 to 999
15058  * 
15059  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string 
15060  * of this han date. The date/time is kept in the local time. The time zone
15061  * is used later if this date is formatted according to a different time zone and
15062  * the difference has to be calculated, or when the date format has a time zone
15063  * component in it.
15064  * 
15065  * <li><i>locale</i> - locale for this han date. If the time zone is not 
15066  * given, it can be inferred from this locale. For locales that span multiple
15067  * time zones, the one with the largest population is chosen as the one that 
15068  * represents the locale.
15069  * 
15070  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15071  * </ul>
15072  *
15073  * If the constructor is called with another Han date instance instead of
15074  * a parameter block, the other instance acts as a parameter block and its
15075  * settings are copied into the current instance.<p>
15076  * 
15077  * If the constructor is called with no arguments at all or if none of the 
15078  * properties listed above 
15079  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
15080  * components are 
15081  * filled in with the current date at the time of instantiation. Note that if
15082  * you do not give the time zone when defaulting to the current time and the 
15083  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
15084  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
15085  * Mean Time").<p>
15086  * 
15087  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
15088  * specified in the params, it is assumed that they have the smallest possible
15089  * value in the range for the property (zero or one).<p>
15090  * 
15091  * 
15092  * @constructor
15093  * @extends Date
15094  * @param {Object=} params parameters that govern the settings and behaviour of this Han date
15095  */
15096 var HanDate = function(params) {
15097 	this.timezone = "local";
15098 	if (params) {
15099 		if (params.locale) {
15100 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
15101 			var li = new LocaleInfo(this.locale);
15102 			this.timezone = li.getTimeZone(); 
15103 		}
15104 		if (params.timezone) {
15105 			this.timezone = params.timezone;
15106 		}
15107 	}
15108 	
15109 	new HanCal({
15110 		sync: params && typeof(params) === 'boolean' ? params.sync : true,
15111 		loadParams: params && params.loadParams,
15112 		callback: ilib.bind(this, function (cal) {
15113 			this.cal = cal;
15114 	
15115 			if (params && (params.year || params.month || params.day || params.hour ||
15116 				params.minute || params.second || params.millisecond || params.cycle || params.cycleYear)) {
15117 				if (typeof(params.cycle) !== 'undefined') {
15118 					/**
15119 					 * Cycle number in the Han calendar.
15120 					 * @type number
15121 					 */
15122 					this.cycle = parseInt(params.cycle, 10) || 0;
15123 					
15124 					var year = (typeof(params.year) !== 'undefined' ? parseInt(params.year, 10) : parseInt(params.cycleYear, 10)) || 0;
15125 					
15126 					/**
15127 					 * Year in the Han calendar.
15128 					 * @type number
15129 					 */
15130 					this.year = HanCal._getElapsedYear(year, this.cycle);
15131 				} else {
15132 					if (typeof(params.year) !== 'undefined') {
15133 						this.year = parseInt(params.year, 10) || 0;
15134 						this.cycle = Math.floor((this.year - 1) / 60);
15135 					} else {
15136 						this.year = this.cycle = 0;
15137 					}
15138 				}	
15139 				
15140 				/**
15141 				 * The month number, ranging from 1 to 13
15142 				 * @type number
15143 				 */
15144 				this.month = parseInt(params.month, 10) || 1;
15145 	
15146 				/**
15147 				 * The day of the month. This ranges from 1 to 30.
15148 				 * @type number
15149 				 */
15150 				this.day = parseInt(params.day, 10) || 1;
15151 				
15152 				/**
15153 				 * The hour of the day. This can be a number from 0 to 23, as times are
15154 				 * stored unambiguously in the 24-hour clock.
15155 				 * @type number
15156 				 */
15157 				this.hour = parseInt(params.hour, 10) || 0;
15158 	
15159 				/**
15160 				 * The minute of the hours. Ranges from 0 to 59.
15161 				 * @type number
15162 				 */
15163 				this.minute = parseInt(params.minute, 10) || 0;
15164 	
15165 				/**
15166 				 * The second of the minute. Ranges from 0 to 59.
15167 				 * @type number
15168 				 */
15169 				this.second = parseInt(params.second, 10) || 0;
15170 	
15171 				/**
15172 				 * The millisecond of the second. Ranges from 0 to 999.
15173 				 * @type number
15174 				 */
15175 				this.millisecond = parseInt(params.millisecond, 10) || 0;
15176 			
15177 				// derived properties
15178 				
15179 				/**
15180 				 * Year in the cycle of the Han calendar
15181 				 * @type number
15182 				 */
15183 				this.cycleYear = MathUtils.amod(this.year, 60); 
15184 
15185 				/**
15186 				 * The day of the year. Ranges from 1 to 384.
15187 				 * @type number
15188 				 */
15189 				this.dayOfYear = parseInt(params.dayOfYear, 10);
15190 	
15191 				if (typeof(params.dst) === 'boolean') {
15192 					this.dst = params.dst;
15193 				}
15194 				
15195 				this.newRd({
15196 					cal: this.cal,
15197 					cycle: this.cycle,
15198 					year: this.year,
15199 					month: this.month,
15200 					day: this.day,
15201 					hour: this.hour,
15202 					minute: this.minute,
15203 					second: this.second,
15204 					millisecond: this.millisecond,
15205 					sync: params && typeof(params.sync) === 'boolean' ? params.sync : true,
15206 					loadParams: params && params.loadParams,
15207 					callback: ilib.bind(this, function (rd) {
15208 						if (rd) {
15209 							this.rd = rd;
15210 							
15211 							// add the time zone offset to the rd to convert to UTC
15212 							if (!this.tz) {
15213 								this.tz = new TimeZone({id: this.timezone});
15214 							}
15215 							// getOffsetMillis requires that this.year, this.rd, and this.dst 
15216 							// are set in order to figure out which time zone rules apply and 
15217 							// what the offset is at that point in the year
15218 							this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
15219 							if (this.offset !== 0) {
15220 								this.rd = this.newRd({
15221 									cal: this.cal,
15222 									rd: this.rd.getRataDie() - this.offset
15223 								});
15224 								this._calcLeap();
15225 							} else {
15226 								// re-use the derived properties from the RD calculations
15227 								this.leapMonth = this.rd.leapMonth;
15228 								this.priorLeapMonth = this.rd.priorLeapMonth;
15229 								this.leapYear = this.rd.leapYear;
15230 							}
15231 						}
15232 						
15233 						if (!this.rd) {
15234 							this.rd = this.newRd(JSUtils.merge(params || {}, {
15235 								cal: this.cal
15236 							}));
15237 							this._calcDateComponents();
15238 						}
15239 						
15240 						if (params && typeof(params.onLoad) === 'function') {
15241 							params.onLoad(this);
15242 						}
15243 					})
15244 				});
15245 			} else {
15246 				if (!this.rd) {
15247 					this.rd = this.newRd(JSUtils.merge(params || {}, {
15248 						cal: this.cal
15249 					}));
15250 					this._calcDateComponents();
15251 				}
15252 				
15253 				if (params && typeof(params.onLoad) === 'function') {
15254 					params.onLoad(this);
15255 				}
15256 			}
15257 		})
15258 	});
15259 
15260 };
15261 
15262 HanDate.prototype = new IDate({noinstance: true});
15263 HanDate.prototype.parent = IDate;
15264 HanDate.prototype.constructor = HanDate;
15265 
15266 /**
15267  * Return a new RD for this date type using the given params.
15268  * @protected
15269  * @param {Object=} params the parameters used to create this rata die instance
15270  * @returns {RataDie} the new RD instance for the given params
15271  */
15272 HanDate.prototype.newRd = function (params) {
15273 	return new HanRataDie(params);
15274 };
15275 
15276 /**
15277  * Return the year for the given RD
15278  * @protected
15279  * @param {number} rd RD to calculate from 
15280  * @returns {number} the year for the RD
15281  */
15282 HanDate.prototype._calcYear = function(rd) {
15283 	var gregdate = new GregorianDate({
15284 		rd: rd,
15285 		timezone: this.timezone
15286 	});
15287 	var hanyear = gregdate.year + 2697;
15288 	var newYears = this.cal.newYears(hanyear);
15289 	return hanyear - ((rd + RataDie.gregorianEpoch < newYears) ? 1 : 0);
15290 };
15291 
15292 /** 
15293  * @private 
15294  * Calculate the leap year and months from the RD.
15295  */
15296 HanDate.prototype._calcLeap = function() {
15297 	var jd = this.rd.getRataDie() + RataDie.gregorianEpoch;
15298 	
15299 	var calc = HanCal._leapYearCalc(this.year);
15300 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15301 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15302 	
15303 	var newYears = (this.leapYear &&
15304 		(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15305 				HanCal._newMoonOnOrAfter(m2+1) : m2;
15306 	
15307 	var m = HanCal._newMoonBefore(jd + 1);
15308 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(m));
15309 	this.leapMonth = (this.leapYear && HanCal._noMajorST(m) && !this.priorLeapMonth);
15310 };
15311 
15312 /**
15313  * @private
15314  * Calculate date components for the given RD date.
15315  */
15316 HanDate.prototype._calcDateComponents = function () {
15317 	var remainder,
15318 		jd = this.rd.getRataDie() + RataDie.gregorianEpoch;
15319 
15320 	// console.log("HanDate._calcDateComponents: calculating for jd " + jd);
15321 
15322 	if (typeof(this.offset) === "undefined") {
15323 		// now offset the jd by the time zone, then recalculate in case we were 
15324 		// near the year boundary
15325 		if (!this.tz) {
15326 			this.tz = new TimeZone({id: this.timezone});
15327 		}
15328 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
15329 	}
15330 	
15331 	if (this.offset !== 0) {
15332 		jd += this.offset;
15333 	}
15334 
15335 	// use the Gregorian calendar objects as a convenient way to short-cut some
15336 	// of the date calculations
15337 	
15338 	var gregyear = GregorianDate._calcYear(this.rd.getRataDie());
15339 	this.year = gregyear + 2697;
15340 	var calc = HanCal._leapYearCalc(this.year);
15341 	var m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15342 	this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15343 	var newYears = (this.leapYear &&
15344 		(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15345 				HanCal._newMoonOnOrAfter(m2+1) : m2;
15346 	
15347 	// See if it's between Jan 1 and the Chinese new years of that Gregorian year. If
15348 	// so, then the Han year is actually the previous one
15349 	if (jd < newYears) {
15350 		this.year--;
15351 		calc = HanCal._leapYearCalc(this.year);
15352 		m2 = HanCal._newMoonOnOrAfter(calc.m1+1);
15353 		this.leapYear = Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12;
15354 		newYears = (this.leapYear &&
15355 			(HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2))) ?
15356 					HanCal._newMoonOnOrAfter(m2+1) : m2;
15357 	}
15358 	// month is elapsed month, not the month number + leap month boolean
15359 	var m = HanCal._newMoonBefore(jd + 1);
15360 	this.month = Math.round((m - calc.m1) / 29.530588853000001);
15361 	
15362 	this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(m));
15363 	this.leapMonth = (this.leapYear && HanCal._noMajorST(m) && !this.priorLeapMonth);
15364 	
15365 	this.cycle = Math.floor((this.year - 1) / 60);
15366 	this.cycleYear = MathUtils.amod(this.year, 60);
15367 	this.day = Astro._floorToJD(jd) - m + 1;
15368 
15369 	/*
15370 	console.log("HanDate._calcDateComponents: year is " + this.year);
15371 	console.log("HanDate._calcDateComponents: isLeapYear is " + this.leapYear);
15372 	console.log("HanDate._calcDateComponents: cycle is " + this.cycle);
15373 	console.log("HanDate._calcDateComponents: cycleYear is " + this.cycleYear);
15374 	console.log("HanDate._calcDateComponents: month is " + this.month);
15375 	console.log("HanDate._calcDateComponents: isLeapMonth is " + this.leapMonth);
15376 	console.log("HanDate._calcDateComponents: day is " + this.day);
15377 	*/
15378 
15379 	// floor to the start of the julian day
15380 	remainder = jd - Astro._floorToJD(jd);
15381 	
15382 	// console.log("HanDate._calcDateComponents: time remainder is " + remainder);
15383 	
15384 	// now convert to milliseconds for the rest of the calculation
15385 	remainder = Math.round(remainder * 86400000);
15386 	
15387 	this.hour = Math.floor(remainder/3600000);
15388 	remainder -= this.hour * 3600000;
15389 	
15390 	this.minute = Math.floor(remainder/60000);
15391 	remainder -= this.minute * 60000;
15392 	
15393 	this.second = Math.floor(remainder/1000);
15394 	remainder -= this.second * 1000;
15395 	
15396 	this.millisecond = remainder;
15397 };
15398 
15399 /**
15400  * Return the year within the Chinese cycle of this date. Cycles are 60 
15401  * years long, and the value returned from this method is the number of the year 
15402  * within this cycle. The year returned from getYear() is the total elapsed 
15403  * years since the beginning of the Chinese epoch and does not include 
15404  * the cycles. 
15405  * 
15406  * @return {number} the year within the current Chinese cycle
15407  */
15408 HanDate.prototype.getCycleYears = function() {
15409 	return this.cycleYear;
15410 };
15411 
15412 /**
15413  * Return the Chinese cycle number of this date. Cycles are 60 years long,
15414  * and the value returned from getCycleYear() is the number of the year 
15415  * within this cycle. The year returned from getYear() is the total elapsed 
15416  * years since the beginning of the Chinese epoch and does not include 
15417  * the cycles. 
15418  * 
15419  * @return {number} the current Chinese cycle
15420  */
15421 HanDate.prototype.getCycles = function() {
15422 	return this.cycle;
15423 };
15424 
15425 /**
15426  * Return whether the year of this date is a leap year in the Chinese Han 
15427  * calendar. 
15428  * 
15429  * @return {boolean} true if the year of this date is a leap year in the 
15430  * Chinese Han calendar. 
15431  */
15432 HanDate.prototype.isLeapYear = function() {
15433 	return this.leapYear;
15434 };
15435 
15436 /**
15437  * Return whether the month of this date is a leap month in the Chinese Han 
15438  * calendar.
15439  * 
15440  * @return {boolean} true if the month of this date is a leap month in the 
15441  * Chinese Han calendar.
15442  */
15443 HanDate.prototype.isLeapMonth = function() {
15444 	return this.leapMonth;
15445 };
15446 
15447 /**
15448  * Return the day of the week of this date. The day of the week is encoded
15449  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
15450  * 
15451  * @return {number} the day of the week
15452  */
15453 HanDate.prototype.getDayOfWeek = function() {
15454 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
15455 	return MathUtils.mod(rd, 7);
15456 };
15457 
15458 /**
15459  * Return the ordinal day of the year. Days are counted from 1 and proceed linearly up to 
15460  * 365, regardless of months or weeks, etc. That is, Farvardin 1st is day 1, and 
15461  * December 31st is 365 in regular years, or 366 in leap years.
15462  * @return {number} the ordinal day of the year
15463  */
15464 HanDate.prototype.getDayOfYear = function() {
15465 	var newYears = this.cal.newYears(this.year);
15466 	var priorNewMoon = HanCal._newMoonOnOrAfter(newYears + (this.month -1) * 29);
15467 	return priorNewMoon - newYears + this.day;
15468 };
15469 
15470 /**
15471  * Return the era for this date as a number. The value for the era for Han 
15472  * calendars is -1 for "before the han era" (BP) and 1 for "the han era" (anno 
15473  * persico or AP). 
15474  * BP dates are any date before Farvardin 1, 1 AP. In the proleptic Han calendar, 
15475  * there is a year 0, so any years that are negative or zero are BP.
15476  * @return {number} 1 if this date is in the common era, -1 if it is before the 
15477  * common era 
15478  */
15479 HanDate.prototype.getEra = function() {
15480 	return (this.year < 1) ? -1 : 1;
15481 };
15482 
15483 /**
15484  * Return the name of the calendar that governs this date.
15485  * 
15486  * @return {string} a string giving the name of the calendar
15487  */
15488 HanDate.prototype.getCalendar = function() {
15489 	return "han";
15490 };
15491 
15492 // register with the factory method
15493 IDate._constructors["han"] = HanDate;
15494 
15495 
15496 /*< EthiopicCal.js */
15497 /*
15498  * ethiopic.js - Represent a Ethiopic calendar object.
15499  * 
15500  * Copyright © 2015, JEDLSoft
15501  *
15502  * Licensed under the Apache License, Version 2.0 (the "License");
15503  * you may not use this file except in compliance with the License.
15504  * You may obtain a copy of the License at
15505  *
15506  *     http://www.apache.org/licenses/LICENSE-2.0
15507  *
15508  * Unless required by applicable law or agreed to in writing, software
15509  * distributed under the License is distributed on an "AS IS" BASIS,
15510  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15511  *
15512  * See the License for the specific language governing permissions and
15513  * limitations under the License.
15514  */
15515 
15516 /* !depends ilib.js Calendar.js Utils.js MathUtils.js */
15517 
15518 
15519 
15520 /**
15521  * @class
15522  * Construct a new Ethiopic calendar object. This class encodes information about
15523  * a Ethiopic calendar.<p>
15524  * 
15525  * 
15526  * @constructor
15527  * @extends Calendar
15528  */
15529 var EthiopicCal = function() {
15530 	this.type = "ethiopic";
15531 };
15532 
15533 /**
15534  * Return the number of months in the given year. The number of months in a year varies
15535  * for lunar calendars because in some years, an extra month is needed to extend the 
15536  * days in a year to an entire solar year. The month is represented as a 1-based number
15537  * where 1=Maskaram, 2=Teqemt, etc. until 13=Paguemen.
15538  * 
15539  * @param {number} year a year for which the number of months is sought
15540  */
15541 EthiopicCal.prototype.getNumMonths = function(year) {
15542 	return 13;
15543 };
15544 
15545 /**
15546  * Return the number of days in a particular month in a particular year. This function
15547  * can return a different number for a month depending on the year because of things
15548  * like leap years.
15549  * 
15550  * @param {number|string} month the month for which the length is sought
15551  * @param {number} year the year within which that month can be found
15552  * @return {number} the number of days within the given month in the given year
15553  */
15554 EthiopicCal.prototype.getMonLength = function(month, year) {
15555 	var m = month;
15556 	switch (typeof(m)) {
15557         case "string": 
15558             m = parseInt(m, 10); 
15559             break;
15560         case "function":
15561         case "object":
15562         case "undefined":
15563             return 30;
15564             break;
15565     }    
15566 	if (m < 13) {
15567 		return 30;
15568 	} else {
15569 		return this.isLeapYear(year) ? 6 : 5;
15570 	}
15571 };
15572 
15573 /**
15574  * Return true if the given year is a leap year in the Ethiopic calendar.
15575  * The year parameter may be given as a number, or as a JulDate object.
15576  * @param {number|EthiopicDate|string} year the year for which the leap year information is being sought
15577  * @return {boolean} true if the given year is a leap year
15578  */
15579 EthiopicCal.prototype.isLeapYear = function(year) {
15580 	var y = year;
15581 	 switch (typeof(y)) {
15582         case "string":
15583             y = parseInt(y, 10);
15584             break;
15585         case "object":
15586             if (typeof(y.year) !== "number") { // in case it is an ilib.Date object
15587                 return false;
15588             }
15589             y = y.year;
15590             break;
15591         case "function":
15592         case "undefined":
15593             return false;
15594             break;
15595     }
15596 	return MathUtils.mod(y, 4) === 3;
15597 };
15598 
15599 /**
15600  * Return the type of this calendar.
15601  * 
15602  * @return {string} the name of the type of this calendar 
15603  */
15604 EthiopicCal.prototype.getType = function() {
15605 	return this.type;
15606 };
15607 
15608 /**
15609  * Return a date instance for this calendar type using the given
15610  * options.
15611  * @param {Object} options options controlling the construction of 
15612  * the date instance
15613  * @return {IDate} a date appropriate for this calendar type
15614  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
15615  */
15616 EthiopicCal.prototype.newDateInstance = function (options) {
15617 		return new EthiopicDate(options);
15618 };
15619 
15620 /* register this calendar for the factory method */
15621 Calendar._constructors["ethiopic"] = EthiopicCal;
15622 
15623 
15624 /*< EthiopicRataDie.js */
15625 /*
15626  * EthiopicRataDie.js - Represent an RD date in the Ethiopic calendar
15627  * 
15628  * Copyright © 2015, JEDLSoft
15629  *
15630  * Licensed under the Apache License, Version 2.0 (the "License");
15631  * you may not use this file except in compliance with the License.
15632  * You may obtain a copy of the License at
15633  *
15634  *     http://www.apache.org/licenses/LICENSE-2.0
15635  *
15636  * Unless required by applicable law or agreed to in writing, software
15637  * distributed under the License is distributed on an "AS IS" BASIS,
15638  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15639  *
15640  * See the License for the specific language governing permissions and
15641  * limitations under the License.
15642  */
15643 
15644 /* !depends 
15645 ilib.js
15646 EthiopicCal.js
15647 RataDie.js
15648 */
15649 
15650 
15651 /**
15652  * @class
15653  * Construct a new Ethiopic RD date number object. The constructor parameters can 
15654  * contain any of the following properties:
15655  * 
15656  * <ul>
15657  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15658  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
15659  * 
15660  * <li><i>julianday</i> - sets the time of this instance according to the given
15661  * Julian Day instance or the Julian Day given as a float
15662  * 
15663  * <li><i>year</i> - any integer, including 0
15664  * 
15665  * <li><i>month</i> - 1 to 12, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
15666  * 
15667  * <li><i>day</i> - 1 to 30
15668  * 
15669  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15670  * is always done with an unambiguous 24 hour representation
15671  * 
15672  * <li><i>minute</i> - 0 to 59
15673  * 
15674  * <li><i>second</i> - 0 to 59
15675  * 
15676  * <li><i>millisecond</i> - 0 to 999
15677  * 
15678  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15679  * </ul>
15680  *
15681  * If the constructor is called with another Ethiopic date instance instead of
15682  * a parameter block, the other instance acts as a parameter block and its
15683  * settings are copied into the current instance.<p>
15684  * 
15685  * If the constructor is called with no arguments at all or if none of the 
15686  * properties listed above are present, then the RD is calculate based on 
15687  * the current date at the time of instantiation. <p>
15688  * 
15689  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
15690  * specified in the params, it is assumed that they have the smallest possible
15691  * value in the range for the property (zero or one).<p>
15692  * 
15693  * 
15694  * @private
15695  * @constructor
15696  * @extends RataDie
15697  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic RD date
15698  */
15699 var EthiopicRataDie = function(params) {
15700 	this.cal = params && params.cal || new EthiopicCal();
15701 	this.rd = undefined;
15702 	RataDie.call(this, params);
15703 };
15704 
15705 EthiopicRataDie.prototype = new RataDie();
15706 EthiopicRataDie.prototype.parent = RataDie;
15707 EthiopicRataDie.prototype.constructor = EthiopicRataDie;
15708 
15709 /**
15710  * The difference between the zero Julian day and the first Ethiopic date
15711  * of Friday, August 29, 8 CE Julian at 6:00am UTC.<p> 
15712  * 
15713  * See <a href="http://us.wow.com/wiki/Time_in_Ethiopia?s_chn=90&s_pt=aolsem&v_t=aolsem"
15714  * Time in Ethiopia</a> for information about how time is handled in Ethiopia.
15715  * 
15716  * @protected
15717  * @type number
15718  */
15719 EthiopicRataDie.prototype.epoch = 1724219.75;
15720 
15721 /**
15722  * Calculate the Rata Die (fixed day) number of the given date from the
15723  * date components.
15724  * 
15725  * @protected
15726  * @param {Object} date the date components to calculate the RD from
15727  */
15728 EthiopicRataDie.prototype._setDateComponents = function(date) {
15729 	var year = date.year;
15730 	var years = 365 * (year - 1) + Math.floor(year/4);
15731 	var dayInYear = (date.month-1) * 30 + date.day;
15732 	var rdtime = (date.hour * 3600000 +
15733 		date.minute * 60000 +
15734 		date.second * 1000 +
15735 		date.millisecond) / 
15736 		86400000;
15737 	
15738 	/*
15739 	console.log("calcRataDie: converting " +  JSON.stringify(parts));
15740 	console.log("getRataDie: year is " +  years);
15741 	console.log("getRataDie: day in year is " +  dayInYear);
15742 	console.log("getRataDie: rdtime is " +  rdtime);
15743 	console.log("getRataDie: rd is " +  (years + dayInYear + rdtime));
15744 	*/
15745 	
15746 	this.rd = years + dayInYear + rdtime;
15747 };
15748 
15749 
15750 
15751 /*< EthiopicDate.js */
15752 /*
15753  * EthiopicDate.js - Represent a date in the Ethiopic calendar
15754  * 
15755  * Copyright © 2015, JEDLSoft
15756  *
15757  * Licensed under the Apache License, Version 2.0 (the "License");
15758  * you may not use this file except in compliance with the License.
15759  * You may obtain a copy of the License at
15760  *
15761  *     http://www.apache.org/licenses/LICENSE-2.0
15762  *
15763  * Unless required by applicable law or agreed to in writing, software
15764  * distributed under the License is distributed on an "AS IS" BASIS,
15765  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15766  *
15767  * See the License for the specific language governing permissions and
15768  * limitations under the License.
15769  */
15770 
15771 /* !depends 
15772 ilib.js
15773 IDate.js 
15774 EthiopicCal.js 
15775 MathUtils.js
15776 Locale.js
15777 LocaleInfo.js 
15778 TimeZone.js
15779 EthiopicRataDie.js
15780 */
15781 
15782 
15783 
15784 /**
15785  * @class
15786  * Construct a new date object for the Ethiopic Calendar. The constructor can be called
15787  * with a parameter object that contains any of the following properties:
15788  * 
15789  * <ul>
15790  * <li><i>unixtime<i> - sets the time of this instance according to the given 
15791  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
15792  * <li><i>julianday</i> - the Julian Day to set into this date
15793  * <li><i>year</i> - any integer
15794  * <li><i>month</i> - 1 to 13, where 1 means Maskaram, 2 means Teqemt, etc., and 13 means Paguemen
15795  * <li><i>day</i> - 1 to 30
15796  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
15797  * is always done with an unambiguous 24 hour representation
15798  * <li><i>minute</i> - 0 to 59
15799  * <li><i>second</i> - 0 to 59
15800  * <li><i>millisecond<i> - 0 to 999
15801  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
15802  * of this ethiopic date. The date/time is kept in the local time. The time zone
15803  * is used later if this date is formatted according to a different time zone and
15804  * the difference has to be calculated, or when the date format has a time zone
15805  * component in it.
15806  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
15807  * given, it can be inferred from this locale. For locales that span multiple
15808  * time zones, the one with the largest population is chosen as the one that 
15809  * represents the locale. 
15810  * 
15811  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
15812  * </ul>
15813  *  
15814  * If called with another Ethiopic date argument, the date components of the given
15815  * date are copied into the current one.<p>
15816  * 
15817  * If the constructor is called with no arguments at all or if none of the 
15818  * properties listed above 
15819  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
15820  * components are 
15821  * filled in with the current date at the time of instantiation. Note that if
15822  * you do not give the time zone when defaulting to the current time and the 
15823  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
15824  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
15825  * Mean Time").<p>
15826  * 
15827  * 
15828  * @constructor
15829  * @extends IDate
15830  * @param {Object=} params parameters that govern the settings and behaviour of this Ethiopic date
15831  */
15832 var EthiopicDate = function(params) {
15833 	this.cal = new EthiopicCal();
15834 	
15835 	if (params) {
15836 		if (typeof(params.noinstance) === 'boolean' && params.noinstance) {
15837 			// for doing inheritance, so don't need to fill in the data. The inheriting class only wants the methods.
15838 			return;
15839 		}
15840 		if (params.locale) {
15841 			this.locale = (typeof(params.locale) === 'string') ? new Locale(params.locale) : params.locale;
15842 			var li = new LocaleInfo(this.locale);
15843 			this.timezone = li.getTimeZone(); 
15844 		}
15845 		if (params.timezone) {
15846 			this.timezone = params.timezone;
15847 		}
15848 		
15849 		if (params.year || params.month || params.day || params.hour ||
15850 				params.minute || params.second || params.millisecond ) {
15851 			/**
15852 			 * Year in the Ethiopic calendar.
15853 			 * @type number
15854 			 */
15855 			this.year = parseInt(params.year, 10) || 0;
15856 			/**
15857 			 * The month number, ranging from 1 (Maskaram) to 13 (Paguemen).
15858 			 * @type number
15859 			 */
15860 			this.month = parseInt(params.month, 10) || 1;
15861 			/**
15862 			 * The day of the month. This ranges from 1 to 30.
15863 			 * @type number
15864 			 */
15865 			this.day = parseInt(params.day, 10) || 1;
15866 			/**
15867 			 * The hour of the day. This can be a number from 0 to 23, as times are
15868 			 * stored unambiguously in the 24-hour clock.
15869 			 * @type number
15870 			 */
15871 			this.hour = parseInt(params.hour, 10) || 0;
15872 			/**
15873 			 * The minute of the hours. Ranges from 0 to 59.
15874 			 * @type number
15875 			 */
15876 			this.minute = parseInt(params.minute, 10) || 0;
15877 			/**
15878 			 * The second of the minute. Ranges from 0 to 59.
15879 			 * @type number
15880 			 */
15881 			this.second = parseInt(params.second, 10) || 0;
15882 			/**
15883 			 * The millisecond of the second. Ranges from 0 to 999.
15884 			 * @type number
15885 			 */
15886 			this.millisecond = parseInt(params.millisecond, 10) || 0;
15887 			
15888 			/**
15889 			 * The day of the year. Ranges from 1 to 366.
15890 			 * @type number
15891 			 */
15892 			this.dayOfYear = parseInt(params.dayOfYear, 10);
15893 			
15894 			if (typeof(params.dst) === 'boolean') {
15895 				this.dst = params.dst;
15896 			}
15897 			
15898 			this.rd = this.newRd(this);
15899 			
15900 			// add the time zone offset to the rd to convert to UTC
15901 			if (!this.tz) {
15902 				this.tz = new TimeZone({id: this.timezone});
15903 			}
15904 			// getOffsetMillis requires that this.year, this.rd, and this.dst 
15905 			// are set in order to figure out which time zone rules apply and 
15906 			// what the offset is at that point in the year
15907 			this.offset = this.tz._getOffsetMillisWallTime(this) / 86400000;
15908 			if (this.offset !== 0) {
15909 				this.rd = this.newRd({
15910 					rd: this.rd.getRataDie() - this.offset
15911 				});
15912 			}
15913 		}
15914 	}
15915 	
15916 	if (!this.rd) {
15917 		this.rd = this.newRd(params);
15918 		this._calcDateComponents();
15919 	}
15920 };
15921 
15922 EthiopicDate.prototype = new IDate({ noinstance: true });
15923 EthiopicDate.prototype.parent = IDate;
15924 EthiopicDate.prototype.constructor = EthiopicDate;
15925 
15926 /**
15927  * Return a new RD for this date type using the given params.
15928  * @protected
15929  * @param {Object=} params the parameters used to create this rata die instance
15930  * @returns {RataDie} the new RD instance for the given params
15931  */
15932 EthiopicDate.prototype.newRd = function (params) {
15933 	return new EthiopicRataDie(params);
15934 };
15935 
15936 /**
15937  * Return the year for the given RD
15938  * @protected
15939  * @param {number} rd RD to calculate from 
15940  * @returns {number} the year for the RD
15941  */
15942 EthiopicDate.prototype._calcYear = function(rd) {
15943 	var year = Math.floor((4*(Math.floor(rd)-1) + 1463)/1461);
15944 	
15945 	return year;
15946 };
15947 
15948 /**
15949  * Calculate date components for the given RD date.
15950  * @protected
15951  */
15952 EthiopicDate.prototype._calcDateComponents = function () {
15953 	var remainder,
15954 		cumulative,
15955 		rd = this.rd.getRataDie();
15956 	
15957 	this.year = this._calcYear(rd);
15958 
15959 	if (typeof(this.offset) === "undefined") {
15960 		this.year = this._calcYear(rd);
15961 		
15962 		// now offset the RD by the time zone, then recalculate in case we were 
15963 		// near the year boundary
15964 		if (!this.tz) {
15965 			this.tz = new TimeZone({id: this.timezone});
15966 		}
15967 		this.offset = this.tz.getOffsetMillis(this) / 86400000;
15968 	}
15969 
15970 	if (this.offset !== 0) {
15971 		rd += this.offset;
15972 		this.year = this._calcYear(rd);
15973 	}
15974 	
15975 	var jan1 = this.newRd({
15976 		year: this.year,
15977 		month: 1,
15978 		day: 1,
15979 		hour: 0,
15980 		minute: 0,
15981 		second: 0,
15982 		millisecond: 0
15983 	});
15984 	remainder = rd + 1 - jan1.getRataDie();
15985 	
15986 	this.month = Math.floor((remainder-1)/30) + 1;
15987 	remainder = remainder - (this.month-1) * 30;
15988 	
15989 	this.day = Math.floor(remainder);
15990 	remainder -= this.day;
15991 	// now convert to milliseconds for the rest of the calculation
15992 	remainder = Math.round(remainder * 86400000);
15993 	
15994 	this.hour = Math.floor(remainder/3600000);
15995 	remainder -= this.hour * 3600000;
15996 	
15997 	this.minute = Math.floor(remainder/60000);
15998 	remainder -= this.minute * 60000;
15999 	
16000 	this.second = Math.floor(remainder/1000);
16001 	remainder -= this.second * 1000;
16002 	
16003 	this.millisecond = remainder;
16004 };
16005 
16006 /**
16007  * Return the day of the week of this date. The day of the week is encoded
16008  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
16009  * 
16010  * @return {number} the day of the week
16011  */
16012 EthiopicDate.prototype.getDayOfWeek = function() {
16013 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
16014 	return MathUtils.mod(rd-4, 7);
16015 };
16016 
16017 /**
16018  * Return the name of the calendar that governs this date.
16019  * 
16020  * @return {string} a string giving the name of the calendar
16021  */
16022 EthiopicDate.prototype.getCalendar = function() {
16023 	return "ethiopic";
16024 };
16025 
16026 //register with the factory method
16027 IDate._constructors["ethiopic"] = EthiopicDate;
16028 
16029 
16030 
16031 /*< CopticCal.js */
16032 /*
16033  * coptic.js - Represent a Coptic calendar object.
16034  * 
16035  * Copyright © 2015, JEDLSoft
16036  *
16037  * Licensed under the Apache License, Version 2.0 (the "License");
16038  * you may not use this file except in compliance with the License.
16039  * You may obtain a copy of the License at
16040  *
16041  *     http://www.apache.org/licenses/LICENSE-2.0
16042  *
16043  * Unless required by applicable law or agreed to in writing, software
16044  * distributed under the License is distributed on an "AS IS" BASIS,
16045  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16046  *
16047  * See the License for the specific language governing permissions and
16048  * limitations under the License.
16049  */
16050 
16051 
16052 /* !depends ilib.js Calendar.js Locale.js Utils.js EthiopicCal.js */
16053 
16054 
16055 /**
16056  * @class
16057  * Construct a new Coptic calendar object. This class encodes information about
16058  * a Coptic calendar.<p>
16059  * 
16060  * 
16061  * @constructor
16062  * @extends EthiopicCal
16063  */
16064 var CopticCal = function() {
16065 	this.type = "coptic";
16066 };
16067 
16068 CopticCal.prototype = new EthiopicCal();
16069 CopticCal.prototype.parent = EthiopicCal;
16070 CopticCal.prototype.constructor = CopticCal;
16071 
16072 /**
16073  * Return a date instance for this calendar type using the given
16074  * options.
16075  * @param {Object} options options controlling the construction of 
16076  * the date instance
16077  * @return {IDate} a date appropriate for this calendar type
16078  * @deprecated Since 11.0.5. Use DateFactory({calendar: cal.getType(), ...}) instead
16079  */
16080 CopticCal.prototype.newDateInstance = function (options) {
16081 		return new CopticDate(options);
16082 };
16083 
16084 /* register this calendar for the factory method */
16085 Calendar._constructors["coptic"] = CopticCal;
16086 
16087 
16088 /*< CopticRataDie.js */
16089 /*
16090  * CopticRataDie.js - Represent an RD date in the Coptic calendar
16091  * 
16092  * Copyright © 2015, JEDLSoft
16093  *
16094  * Licensed under the Apache License, Version 2.0 (the "License");
16095  * you may not use this file except in compliance with the License.
16096  * You may obtain a copy of the License at
16097  *
16098  *     http://www.apache.org/licenses/LICENSE-2.0
16099  *
16100  * Unless required by applicable law or agreed to in writing, software
16101  * distributed under the License is distributed on an "AS IS" BASIS,
16102  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16103  *
16104  * See the License for the specific language governing permissions and
16105  * limitations under the License.
16106  */
16107 
16108 /* !depends 
16109 ilib.js
16110 CopticCal.js 
16111 JSUtils.js
16112 EthiopicRataDie.js
16113 */
16114 
16115 
16116 /**
16117  * @class
16118  * Construct a new Coptic RD date number object. The constructor parameters can 
16119  * contain any of the following properties:
16120  * 
16121  * <ul>
16122  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16123  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
16124  * 
16125  * <li><i>julianday</i> - sets the time of this instance according to the given
16126  * Julian Day instance or the Julian Day given as a float
16127  * 
16128  * <li><i>year</i> - any integer, including 0
16129  * 
16130  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
16131  * 
16132  * <li><i>day</i> - 1 to 30
16133  * 
16134  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16135  * is always done with an unambiguous 24 hour representation
16136  * 
16137  * <li><i>minute</i> - 0 to 59
16138  * 
16139  * <li><i>second</i> - 0 to 59
16140  * 
16141  * <li><i>millisecond</i> - 0 to 999
16142  * 
16143  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16144  * </ul>
16145  *
16146  * If the constructor is called with another Coptic date instance instead of
16147  * a parameter block, the other instance acts as a parameter block and its
16148  * settings are copied into the current instance.<p>
16149  * 
16150  * If the constructor is called with no arguments at all or if none of the 
16151  * properties listed above are present, then the RD is calculate based on 
16152  * the current date at the time of instantiation. <p>
16153  * 
16154  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
16155  * specified in the params, it is assumed that they have the smallest possible
16156  * value in the range for the property (zero or one).<p>
16157  * 
16158  * 
16159  * @private
16160  * @constructor
16161  * @extends EthiopicRataDie
16162  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic RD date
16163  */
16164 var CopticRataDie = function(params) {
16165 	this.cal = params && params.cal || new CopticCal();
16166 	this.rd = undefined;
16167 	/**
16168 	 * The difference between the zero Julian day and the first Coptic date
16169 	 * of Friday, August 29, 284 CE Julian at 7:00am UTC. 
16170 	 * @private
16171 	 * @const
16172 	 * @type number
16173 	 */
16174 	this.epoch = 1825028.5;
16175 
16176 	var tmp = {};
16177 	if (params) {
16178 		JSUtils.shallowCopy(params, tmp);
16179 	}
16180 	tmp.cal = this.cal; // override the cal parameter that may be passed in
16181 	EthiopicRataDie.call(this, tmp);
16182 };
16183 
16184 CopticRataDie.prototype = new EthiopicRataDie();
16185 CopticRataDie.prototype.parent = EthiopicRataDie;
16186 CopticRataDie.prototype.constructor = CopticRataDie;
16187 
16188 
16189 /*< CopticDate.js */
16190 /*
16191  * CopticDate.js - Represent a date in the Coptic calendar
16192  * 
16193  * Copyright © 2015, JEDLSoft
16194  *
16195  * Licensed under the Apache License, Version 2.0 (the "License");
16196  * you may not use this file except in compliance with the License.
16197  * You may obtain a copy of the License at
16198  *
16199  *     http://www.apache.org/licenses/LICENSE-2.0
16200  *
16201  * Unless required by applicable law or agreed to in writing, software
16202  * distributed under the License is distributed on an "AS IS" BASIS,
16203  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16204  *
16205  * See the License for the specific language governing permissions and
16206  * limitations under the License.
16207  */
16208 
16209 /* !depends 
16210 ilib.js
16211 IDate.js 
16212 CopticCal.js 
16213 MathUtils.js
16214 JSUtils.js
16215 Locale.js
16216 LocaleInfo.js 
16217 TimeZone.js
16218 EthiopicDate.js
16219 CopticRataDie.js
16220 */
16221 
16222 
16223 
16224 
16225 /**
16226  * @class
16227  * Construct a new date object for the Coptic Calendar. The constructor can be called
16228  * with a parameter object that contains any of the following properties:
16229  * 
16230  * <ul>
16231  * <li><i>unixtime<i> - sets the time of this instance according to the given 
16232  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970 (Gregorian).
16233  * <li><i>julianday</i> - the Julian Day to set into this date
16234  * <li><i>year</i> - any integer
16235  * <li><i>month</i> - 1 to 13, where 1 means Thoout, 2 means Paope, etc., and 13 means Epagomene
16236  * <li><i>day</i> - 1 to 30
16237  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 
16238  * is always done with an unambiguous 24 hour representation
16239  * <li><i>minute</i> - 0 to 59
16240  * <li><i>second</i> - 0 to 59
16241  * <li><i>millisecond<i> - 0 to 999
16242  * <li><i>locale</i> - the TimeZone instance or time zone name as a string 
16243  * of this coptic date. The date/time is kept in the local time. The time zone
16244  * is used later if this date is formatted according to a different time zone and
16245  * the difference has to be calculated, or when the date format has a time zone
16246  * component in it.
16247  * <li><i>timezone</i> - the time zone of this instance. If the time zone is not 
16248  * given, it can be inferred from this locale. For locales that span multiple
16249  * time zones, the one with the largest population is chosen as the one that 
16250  * represents the locale. 
16251  * 
16252  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
16253  * </ul>
16254  *  
16255  * If called with another Coptic date argument, the date components of the given
16256  * date are copied into the current one.<p>
16257  * 
16258  * If the constructor is called with no arguments at all or if none of the 
16259  * properties listed above 
16260  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date 
16261  * components are 
16262  * filled in with the current date at the time of instantiation. Note that if
16263  * you do not give the time zone when defaulting to the current time and the 
16264  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
16265  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich 
16266  * Mean Time").<p>
16267  * 
16268  * 
16269  * @constructor
16270  * @extends EthiopicDate
16271  * @param {Object=} params parameters that govern the settings and behaviour of this Coptic date
16272  */
16273 var CopticDate = function(params) {
16274 	this.rd = undefined; // clear these out so that the EthiopicDate constructor can set it
16275 	EthiopicDate.call(this, params);
16276 	this.cal = new CopticCal();
16277 };
16278 
16279 CopticDate.prototype = new EthiopicDate({noinstance: true});
16280 CopticDate.prototype.parent = EthiopicDate.prototype;
16281 CopticDate.prototype.constructor = CopticDate;
16282 
16283 /**
16284  * Return a new RD for this date type using the given params.
16285  * @protected
16286  * @param {Object=} params the parameters used to create this rata die instance
16287  * @returns {RataDie} the new RD instance for the given params
16288  */
16289 CopticDate.prototype.newRd = function (params) {
16290 	return new CopticRataDie(params);
16291 };
16292 
16293 /**
16294  * Return the day of the week of this date. The day of the week is encoded
16295  * as number from 0 to 6, with 0=Sunday, 1=Monday, etc., until 6=Saturday.
16296  * 
16297  * @return {number} the day of the week
16298  */
16299 CopticDate.prototype.getDayOfWeek = function() {
16300 	var rd = Math.floor(this.rd.getRataDie() + (this.offset || 0));
16301 	return MathUtils.mod(rd-3, 7);
16302 };
16303 
16304 /**
16305  * Return the name of the calendar that governs this date.
16306  * 
16307  * @return {string} a string giving the name of the calendar
16308  */
16309 CopticDate.prototype.getCalendar = function() {
16310 	return "coptic";
16311 };
16312 
16313 //register with the factory method
16314 IDate._constructors["coptic"] = CopticDate;
16315 
16316 
16317 /*< CType.js */
16318 /*
16319  * CType.js - Character type definitions
16320  * 
16321  * Copyright © 2012-2015, JEDLSoft
16322  *
16323  * Licensed under the Apache License, Version 2.0 (the "License");
16324  * you may not use this file except in compliance with the License.
16325  * You may obtain a copy of the License at
16326  *
16327  *     http://www.apache.org/licenses/LICENSE-2.0
16328  *
16329  * Unless required by applicable law or agreed to in writing, software
16330  * distributed under the License is distributed on an "AS IS" BASIS,
16331  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16332  *
16333  * See the License for the specific language governing permissions and
16334  * limitations under the License.
16335  */
16336 
16337 // !depends ilib.js Locale.js SearchUtils.js Utils.js IString.js
16338 
16339 // !data ctype
16340 
16341 
16342 /**
16343  * Provides a set of static routines that return information about characters.
16344  * These routines emulate the C-library ctype functions. The characters must be 
16345  * encoded in utf-16, as no other charsets are currently supported. Only the first
16346  * character of the given string is tested.
16347  * @namespace
16348  */
16349 var CType = {};
16350 
16351 
16352 /**
16353  * Actual implementation for withinRange. Searches the given object for ranges.
16354  * The range names are taken from the Unicode range names in 
16355  * http://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt
16356  * 
16357  * <ul>
16358  * <li>Cn - Unassigned
16359  * <li>Lu - Uppercase_Letter
16360  * <li>Ll - Lowercase_Letter
16361  * <li>Lt - Titlecase_Letter
16362  * <li>Lm - Modifier_Letter
16363  * <li>Lo - Other_Letter
16364  * <li>Mn - Nonspacing_Mark
16365  * <li>Me - Enclosing_Mark
16366  * <li>Mc - Spacing_Mark
16367  * <li>Nd - Decimal_Number
16368  * <li>Nl - Letter_Number
16369  * <li>No - Other_Number
16370  * <li>Zs - Space_Separator
16371  * <li>Zl - Line_Separator
16372  * <li>Zp - Paragraph_Separator
16373  * <li>Cc - Control
16374  * <li>Cf - Format
16375  * <li>Co - Private_Use
16376  * <li>Cs - Surrogate
16377  * <li>Pd - Dash_Punctuation
16378  * <li>Ps - Open_Punctuation
16379  * <li>Pe - Close_Punctuation
16380  * <li>Pc - Connector_Punctuation
16381  * <li>Po - Other_Punctuation
16382  * <li>Sm - Math_Symbol
16383  * <li>Sc - Currency_Symbol
16384  * <li>Sk - Modifier_Symbol
16385  * <li>So - Other_Symbol
16386  * <li>Pi - Initial_Punctuation
16387  * <li>Pf - Final_Punctuation
16388  * </ul>
16389  * 
16390  * @protected
16391  * @param {number} num code point of the character to examine
16392  * @param {string} rangeName the name of the range to check
16393  * @param {Object} obj object containing the character range data
16394  * @return {boolean} true if the first character is within the named
16395  * range
16396  */
16397 CType._inRange = function(num, rangeName, obj) {
16398 	var range, i;
16399 	if (num < 0 || !rangeName || !obj) {
16400 		return false;
16401 	}
16402 	
16403 	range = obj[rangeName];
16404 	if (!range) {
16405 		return false;
16406 	}
16407 	
16408 	var compare = function(singlerange, target) {
16409 		if (singlerange.length === 1) {
16410 			return singlerange[0] - target;
16411 		} else {
16412 			return target < singlerange[0] ? singlerange[0] - target :
16413 				(target > singlerange[1] ? singlerange[1] - target : 0);
16414 		}
16415 	};
16416 	var result = SearchUtils.bsearch(num, range, compare);
16417 	return result < range.length && compare(range[result], num) === 0;
16418 };
16419 
16420 /**
16421  * Return whether or not the first character is within the named range
16422  * of Unicode characters. The valid list of range names are taken from 
16423  * the Unicode 6.0 spec. Characters in all ranges of Unicode are supported,
16424  * including those supported in Javascript via UTF-16. Currently, this method 
16425  * supports the following range names:
16426  * 
16427  * <ul>
16428  * <li><i>ascii</i> - basic ASCII
16429  * <li><i>latin</i> - Latin, Latin Extended Additional, Latin Extended-C, Latin Extended-D
16430  * <li><i>armenian</i>
16431  * <li><i>greek</i> - Greek, Greek Extended
16432  * <li><i>cyrillic</i> - Cyrillic, Cyrillic Extended-A, Cyrillic Extended-B
16433  * <li><i>georgian</i> - Georgian, Georgian Supplement
16434  * <li><i>glagolitic</i>
16435  * <li><i>gothic</i>
16436  * <li><i>ogham</i>
16437  * <li><i>oldpersian</i>
16438  * <li><i>runic</i>
16439  * <li><i>ipa</i> - IPA, Phonetic Extensions, Phonetic Extensions Supplement
16440  * <li><i>phonetic</i>
16441  * <li><i>modifiertone</i> - Modifier Tone Letters
16442  * <li><i>spacing</i>
16443  * <li><i>diacritics</i>
16444  * <li><i>halfmarks</i> - Combining Half Marks
16445  * <li><i>small</i> - Small Form Variants
16446  * <li><i>bamum</i> - Bamum, Bamum Supplement
16447  * <li><i>ethiopic</i> - Ethiopic, Ethiopic Extended, Ethiopic Extended-A
16448  * <li><i>nko</i>
16449  * <li><i>osmanya</i>
16450  * <li><i>tifinagh</i>
16451  * <li><i>val</i>
16452  * <li><i>arabic</i> - Arabic, Arabic Supplement, Arabic Presentation Forms-A, 
16453  * Arabic Presentation Forms-B
16454  * <li><i>carlan</i>
16455  * <li><i>hebrew</i>
16456  * <li><i>mandaic</i>
16457  * <li><i>samaritan</i>
16458  * <li><i>syriac</i>
16459  * <li><i>mongolian</i>
16460  * <li><i>phagspa</i>
16461  * <li><i>tibetan</i>
16462  * <li><i>bengali</i>
16463  * <li><i>devanagari</i> - Devanagari, Devanagari Extended
16464  * <li><i>gujarati</i>
16465  * <li><i>gurmukhi</i>
16466  * <li><i>kannada</i>
16467  * <li><i>lepcha</i>
16468  * <li><i>limbu</i>
16469  * <li><i>malayalam</i>
16470  * <li><i>meetaimayek</i>
16471  * <li><i>olchiki</i>
16472  * <li><i>oriya</i>
16473  * <li><i>saurashtra</i>
16474  * <li><i>sinhala</i>
16475  * <li><i>sylotinagri</i> - Syloti Nagri
16476  * <li><i>tamil</i>
16477  * <li><i>telugu</i>
16478  * <li><i>thaana</i>
16479  * <li><i>vedic</i>
16480  * <li><i>batak</i>
16481  * <li><i>balinese</i>
16482  * <li><i>buginese</i>
16483  * <li><i>cham</i>
16484  * <li><i>javanese</i>
16485  * <li><i>kayahli</i>
16486  * <li><i>khmer</i>
16487  * <li><i>lao</i>
16488  * <li><i>myanmar</i> - Myanmar, Myanmar Extended-A
16489  * <li><i>newtailue</i>
16490  * <li><i>rejang</i>
16491  * <li><i>sundanese</i>
16492  * <li><i>taile</i>
16493  * <li><i>taitham</i>
16494  * <li><i>taiviet</i>
16495  * <li><i>thai</i>
16496  * <li><i>buhld</i>
16497  * <li><i>hanunoo</i>
16498  * <li><i>tagalog</i>
16499  * <li><i>tagbanwa</i>
16500  * <li><i>bopomofo</i> - Bopomofo, Bopomofo Extended
16501  * <li><i>cjk</i> - the CJK unified ideographs (Han), CJK Unified Ideographs
16502  *  Extension A, CJK Unified Ideographs Extension B, CJK Unified Ideographs 
16503  *  Extension C, CJK Unified Ideographs Extension D, Ideographic Description 
16504  *  Characters (=isIdeo())
16505  * <li><i>cjkcompatibility</i> - CJK Compatibility, CJK Compatibility 
16506  * Ideographs, CJK Compatibility Forms, CJK Compatibility Ideographs Supplement
16507  * <li><i>cjkradicals</i> - the CJK radicals, KangXi radicals
16508  * <li><i>hangul</i> - Hangul Jamo, Hangul Syllables, Hangul Jamo Extended-A, 
16509  * Hangul Jamo Extended-B, Hangul Compatibility Jamo
16510  * <li><i>cjkpunct</i> - CJK symbols and punctuation
16511  * <li><i>cjkstrokes</i> - CJK strokes
16512  * <li><i>hiragana</i>
16513  * <li><i>katakana</i> - Katakana, Katakana Phonetic Extensions, Kana Supplement
16514  * <li><i>kanbun</i>
16515  * <li><i>lisu</i>
16516  * <li><i>yi</i> - Yi Syllables, Yi Radicals
16517  * <li><i>cherokee</i>
16518  * <li><i>canadian</i> - Unified Canadian Aboriginal Syllabics, Unified Canadian 
16519  * Aboriginal Syllabics Extended
16520  * <li><i>presentation</i> - Alphabetic presentation forms
16521  * <li><i>vertical</i> - Vertical Forms
16522  * <li><i>width</i> - Halfwidth and Fullwidth Forms
16523  * <li><i>punctuation</i> - General punctuation, Supplemental Punctuation
16524  * <li><i>box</i> - Box Drawing
16525  * <li><i>block</i> - Block Elements
16526  * <li><i>letterlike</i> - Letterlike symbols
16527  * <li><i>mathematical</i> - Mathematical alphanumeric symbols, Miscellaneous 
16528  * Mathematical Symbols-A, Miscellaneous Mathematical Symbols-B
16529  * <li><i>enclosedalpha</i> - Enclosed alphanumerics, Enclosed Alphanumeric Supplement
16530  * <li><i>enclosedcjk</i> - Enclosed CJK letters and months, Enclosed Ideographic Supplement
16531  * <li><i>cjkcompatibility</i> - CJK compatibility
16532  * <li><i>apl</i> - APL symbols
16533  * <li><i>controlpictures</i> - Control pictures
16534  * <li><i>misc</i> - Miscellaneous technical
16535  * <li><i>ocr</i> - Optical character recognition (OCR)
16536  * <li><i>combining</i> - Combining Diacritical Marks, Combining Diacritical Marks 
16537  * for Symbols, Combining Diacritical Marks Supplement
16538  * <li><i>digits</i> - ASCII digits (=isDigit())
16539  * <li><i>indicnumber</i> - Common Indic Number Forms
16540  * <li><i>numbers</i> - Number dorms
16541  * <li><i>supersub</i> - Super- and subscripts
16542  * <li><i>arrows</i> - Arrows, Miscellaneous Symbols and Arrows, Supplemental Arrows-A,
16543  * Supplemental Arrows-B
16544  * <li><i>operators</i> - Mathematical operators, supplemental 
16545  * mathematical operators 
16546  * <li><i>geometric</i> - Geometric shapes
16547  * <li><i>ancient</i> - Ancient symbols
16548  * <li><i>braille</i> - Braille patterns
16549  * <li><i>currency</i> - Currency symbols
16550  * <li><i>dingbats</i>
16551  * <li><i>gamesymbols</i>
16552  * <li><i>yijing</i> - Yijing Hexagram Symbols
16553  * <li><i>specials</i>
16554  * <li><i>variations</i> - Variation Selectors, Variation Selectors Supplement
16555  * <li><i>privateuse</i> - Private Use Area, Supplementary Private Use Area-A, 
16556  * Supplementary Private Use Area-B
16557  * <li><i>supplementarya</i> - Supplementary private use area-A
16558  * <li><i>supplementaryb</i> - Supplementary private use area-B
16559  * <li><i>highsurrogates</i> - High Surrogates, High Private Use Surrogates
16560  * <li><i>lowsurrogates</i>
16561  * <li><i>reserved</i>
16562  * <li><i>noncharacters</i>
16563  * </ul><p>
16564  * 
16565  * 
16566  * @protected
16567  * @param {string|IString|number} ch character or code point to examine
16568  * @param {string} rangeName the name of the range to check
16569  * @return {boolean} true if the first character is within the named
16570  * range
16571  */
16572 CType.withinRange = function(ch, rangeName) {
16573 	if (!rangeName) {
16574 		return false;
16575 	}
16576 	var num;
16577 	switch (typeof(ch)) {
16578 		case 'number':
16579 			num = ch;
16580 			break;
16581 		case 'string':
16582 			num = IString.toCodePoint(ch, 0);
16583 			break;
16584 		case 'undefined':
16585 			return false;
16586 		default:
16587 			num = ch._toCodePoint(0);
16588 			break;
16589 	}
16590 
16591 	return CType._inRange(num, rangeName.toLowerCase(), ilib.data.ctype);
16592 };
16593 
16594 /**
16595  * @protected
16596  * @param {boolean} sync
16597  * @param {Object|undefined} loadParams
16598  * @param {function(*)|undefined} onLoad
16599  */
16600 CType._init = function(sync, loadParams, onLoad) {
16601 	CType._load("ctype", sync, loadParams, onLoad);
16602 };
16603 
16604 /**
16605  * @protected
16606  * @param {string} name
16607  * @param {boolean} sync
16608  * @param {Object|undefined} loadParams
16609  * @param {function(*)|undefined} onLoad
16610  */
16611 CType._load = function (name, sync, loadParams, onLoad) {
16612 	if (!ilib.data[name]) {
16613 		var loadName = name ? name + ".json" : "CType.json";
16614 		Utils.loadData({
16615 			name: loadName,
16616 			locale: "-",
16617 			nonlocale: true,
16618 			sync: sync,
16619 			loadParams: loadParams, 
16620 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(ct) {
16621 				ilib.data[name] = ct;
16622 				if (onLoad && typeof(onLoad) === 'function') {
16623 					onLoad(ilib.data[name]);
16624 				}
16625 			})
16626 		});
16627 	} else {
16628 		if (onLoad && typeof(onLoad) === 'function') {
16629 			onLoad(ilib.data[name]);
16630 		}
16631 	}
16632 };
16633 
16634 
16635 
16636 /*< isDigit.js */
16637 /*
16638  * isDigit.js - Character type is digit
16639  * 
16640  * Copyright © 2012-2015, JEDLSoft
16641  *
16642  * Licensed under the Apache License, Version 2.0 (the "License");
16643  * you may not use this file except in compliance with the License.
16644  * You may obtain a copy of the License at
16645  *
16646  *     http://www.apache.org/licenses/LICENSE-2.0
16647  *
16648  * Unless required by applicable law or agreed to in writing, software
16649  * distributed under the License is distributed on an "AS IS" BASIS,
16650  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16651  *
16652  * See the License for the specific language governing permissions and
16653  * limitations under the License.
16654  */
16655 
16656 // !depends CType.js IString.js ilib.js
16657 
16658 // !data ctype
16659 
16660 
16661 /**
16662  * Return whether or not the first character is a digit character in the
16663  * Latin script.<p>
16664  * 
16665  * @static
16666  * @param {string|IString|number} ch character or code point to examine
16667  * @return {boolean} true if the first character is a digit character in the
16668  * Latin script. 
16669  */
16670 var isDigit = function (ch) {
16671 	var num;
16672 	switch (typeof(ch)) {
16673 		case 'number':
16674 			num = ch;
16675 			break;
16676 		case 'string':
16677 			num = IString.toCodePoint(ch, 0);
16678 			break;
16679 		case 'undefined':
16680 			return false;
16681 		default:
16682 			num = ch._toCodePoint(0);
16683 			break;
16684 	}
16685 	return CType._inRange(num, 'digit', ilib.data.ctype);
16686 };
16687 
16688 /**
16689  * @protected
16690  * @param {boolean} sync
16691  * @param {Object|undefined} loadParams
16692  * @param {function(*)|undefined} onLoad
16693  */
16694 isDigit._init = function (sync, loadParams, onLoad) {
16695 	CType._init(sync, loadParams, onLoad);
16696 };
16697 
16698 
16699 
16700 /*< isSpace.js */
16701 /*
16702  * isSpace.js - Character type is space char
16703  * 
16704  * Copyright © 2012-2015, JEDLSoft
16705  *
16706  * Licensed under the Apache License, Version 2.0 (the "License");
16707  * you may not use this file except in compliance with the License.
16708  * You may obtain a copy of the License at
16709  *
16710  *     http://www.apache.org/licenses/LICENSE-2.0
16711  *
16712  * Unless required by applicable law or agreed to in writing, software
16713  * distributed under the License is distributed on an "AS IS" BASIS,
16714  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16715  *
16716  * See the License for the specific language governing permissions and
16717  * limitations under the License.
16718  */
16719 
16720 // !depends CType.js IString.js
16721 
16722 // !data ctype ctype_z
16723 
16724 
16725 
16726 /**
16727  * Return whether or not the first character is a whitespace character.<p>
16728  * 
16729  * @static
16730  * @param {string|IString|number} ch character or code point to examine
16731  * @return {boolean} true if the first character is a whitespace character.
16732  */
16733 var isSpace = function (ch) {
16734 	var num;
16735 	switch (typeof(ch)) {
16736 		case 'number':
16737 			num = ch;
16738 			break;
16739 		case 'string':
16740 			num = IString.toCodePoint(ch, 0);
16741 			break;
16742 		case 'undefined':
16743 			return false;
16744 		default:
16745 			num = ch._toCodePoint(0);
16746 			break;
16747 	}
16748 
16749 	return CType._inRange(num, 'space', ilib.data.ctype) ||
16750 		CType._inRange(num, 'Zs', ilib.data.ctype_z) ||
16751 		CType._inRange(num, 'Zl', ilib.data.ctype_z) ||
16752 		CType._inRange(num, 'Zp', ilib.data.ctype_z);
16753 };
16754 
16755 /**
16756  * @protected
16757  * @param {boolean} sync
16758  * @param {Object|undefined} loadParams
16759  * @param {function(*)|undefined} onLoad
16760  */
16761 isSpace._init = function (sync, loadParams, onLoad) {
16762 	CType._load("ctype_z", sync, loadParams, function () {
16763 		CType._init(sync, loadParams, onLoad);
16764 	});
16765 };
16766 
16767 
16768 /*< Currency.js */
16769 /*
16770  * Currency.js - Currency definition
16771  * 
16772  * Copyright © 2012-2015, JEDLSoft
16773  *
16774  * Licensed under the Apache License, Version 2.0 (the "License");
16775  * you may not use this file except in compliance with the License.
16776  * You may obtain a copy of the License at
16777  *
16778  *     http://www.apache.org/licenses/LICENSE-2.0
16779  *
16780  * Unless required by applicable law or agreed to in writing, software
16781  * distributed under the License is distributed on an "AS IS" BASIS,
16782  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16783  *
16784  * See the License for the specific language governing permissions and
16785  * limitations under the License.
16786  */
16787 
16788 // !depends ilib.js Utils.js Locale.js LocaleInfo.js
16789 
16790 // !data currency
16791 
16792 
16793 /**
16794  * @class
16795  * Create a new currency information instance. Instances of this class encode 
16796  * information about a particular currency.<p>
16797  * 
16798  * Note: that if you are looking to format currency for display, please see
16799  * the number formatting class {NumFmt}. This class only gives information
16800  * about currencies.<p> 
16801  * 
16802  * The options can contain any of the following properties:
16803  * 
16804  * <ul>
16805  * <li><i>locale</i> - specify the locale for this instance
16806  * <li><i>code</i> - find info on a specific currency with the given ISO 4217 code 
16807  * <li><i>sign</i> - search for a currency that uses this sign
16808  * <li><i>onLoad</i> - a callback function to call when the currency data is fully 
16809  * loaded. When the onLoad option is given, this class will attempt to
16810  * load any missing locale data using the ilib loader callback.
16811  * When the constructor is done (even if the data is already preassembled), the 
16812  * onLoad function is called with the current instance as a parameter, so this
16813  * callback can be used with preassembled or dynamic loading or a mix of the two. 
16814  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
16815  * asynchronously. If this option is given as "false", then the "onLoad"
16816  * callback must be given, as the instance returned from this constructor will
16817  * not be usable for a while.
16818  * <li><i>loadParams</i> - an object containing parameters to pass to the 
16819  * loader callback function when locale data is missing. The parameters are not
16820  * interpretted or modified in any way. They are simply passed along. The object 
16821  * may contain any property/value pairs as long as the calling code is in
16822  * agreement with the loader callback function as to what those parameters mean.
16823  * </ul>
16824  * 
16825  * When searching for a currency by its sign, this class cannot guarantee 
16826  * that it will return info about a specific currency. The reason is that currency 
16827  * signs are sometimes shared between different currencies and the sign is 
16828  * therefore ambiguous. If you need a 
16829  * guarantee, find the currency using the code instead.<p>
16830  * 
16831  * The way this class finds a currency by sign is the following. If the sign is 
16832  * unambiguous, then
16833  * the currency is returned. If there are multiple currencies that use the same
16834  * sign, and the current locale uses that sign, then the default currency for
16835  * the current locale is returned. If there are multiple, but the current locale
16836  * does not use that sign, then the currency with the largest circulation is
16837  * returned. For example, if you are in the en-GB locale, and the sign is "$",
16838  * then this class will notice that there are multiple currencies with that
16839  * sign (USD, CAD, AUD, HKD, MXP, etc.) Since "$" is not used in en-GB, it will 
16840  * pick the one with the largest circulation, which in this case is the US Dollar
16841  * (USD).<p>
16842  * 
16843  * If neither the code or sign property is set, the currency that is most common 
16844  * for the locale
16845  * will be used instead. If the locale is not set, the default locale will be used.
16846  * If the code is given, but it is not found in the list of known currencies, this
16847  * constructor will throw an exception. If the sign is given, but it is not found,
16848  * this constructor will default to the currency for the current locale. If both
16849  * the code and sign properties are given, then the sign property will be ignored
16850  * and only the code property used. If the locale is given, but it is not a known
16851  * locale, this class will default to the default locale instead.<p>
16852  * 
16853  * 
16854  * @constructor
16855  * @param options {Object} a set of properties to govern how this instance is constructed.
16856  * @throws "currency xxx is unknown" when the given currency code is not in the list of 
16857  * known currencies. xxx is replaced with the requested code.
16858  */
16859 var Currency = function (options) {
16860 	this.sync = true;
16861 	
16862 	if (options) {
16863 		if (options.code) {
16864 			this.code = options.code;
16865 		}
16866 		if (options.locale) {
16867 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
16868 		}
16869 		if (options.sign) {
16870 			this.sign = options.sign;
16871 		}
16872 		if (typeof(options.sync) !== 'undefined') {
16873 			this.sync = options.sync;
16874 		}
16875 		if (options.loadParams) {
16876 			this.loadParams = options.loadParams;
16877 		}
16878 	}
16879 	
16880 	this.locale = this.locale || new Locale();
16881 	if (typeof(ilib.data.currency) === 'undefined') {
16882 		Utils.loadData({
16883 			name: "currency.json",
16884 			object: Currency, 
16885 			locale: "-",
16886 			sync: this.sync, 
16887 			loadParams: this.loadParams, 
16888 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(currency) {
16889 				ilib.data.currency = currency;
16890 				this._loadLocinfo(options && options.onLoad);
16891 			})
16892 		});
16893 	} else {
16894 		this._loadLocinfo(options && options.onLoad);
16895 	}
16896 };
16897 
16898 /**
16899  * Return an array of the ids for all ISO 4217 currencies that
16900  * this copy of ilib knows about.
16901  * 
16902  * @static
16903  * @return {Array.<string>} an array of currency ids that this copy of ilib knows about.
16904  */
16905 Currency.getAvailableCurrencies = function() {
16906 	var ret = [],
16907 		cur,
16908 		currencies = new ResBundle({
16909 			name: "currency"
16910 		}).getResObj();
16911 	
16912 	for (cur in currencies) {
16913 		if (cur && currencies[cur]) {
16914 			ret.push(cur);
16915 		}
16916 	}
16917 	
16918 	return ret;
16919 };
16920 
16921 Currency.prototype = {
16922 	/**
16923 	 * @private
16924 	 */
16925 	_loadLocinfo: function(onLoad) {
16926 		new LocaleInfo(this.locale, {
16927 			onLoad: ilib.bind(this, function (li) {
16928 				var currInfo;
16929 				
16930 				this.locinfo = li;
16931 		    	if (this.code) {
16932 		    		currInfo = ilib.data.currency[this.code];
16933 		    		if (!currInfo) {
16934 		    			throw "currency " + this.code + " is unknown";
16935 		    		}
16936 		    	} else if (this.sign) {
16937 		    		currInfo = ilib.data.currency[this.sign]; // maybe it is really a code...
16938 		    		if (typeof(currInfo) !== 'undefined') {
16939 		    			this.code = this.sign;
16940 		    		} else {
16941 		    			this.code = this.locinfo.getCurrency();
16942 		    			currInfo = ilib.data.currency[this.code];
16943 		    			if (currInfo.sign !== this.sign) {
16944 		    				// current locale does not use the sign, so search for it
16945 		    				for (var cur in ilib.data.currency) {
16946 		    					if (cur && ilib.data.currency[cur]) {
16947 		    						currInfo = ilib.data.currency[cur];
16948 		    						if (currInfo.sign === this.sign) {
16949 		    							// currency data is already ordered so that the currency with the
16950 		    							// largest circulation is at the beginning, so all we have to do
16951 		    							// is take the first one in the list that matches
16952 		    							this.code = cur;
16953 		    							break;
16954 		    						}
16955 		    					}
16956 		    				}
16957 		    			}
16958 		    		}
16959 		    	}
16960 		    	
16961 		    	if (!currInfo || !this.code) {
16962 		    		this.code = this.locinfo.getCurrency();
16963 		    		currInfo = ilib.data.currency[this.code];
16964 		    	}
16965 		    	
16966 		    	this.name = currInfo.name;
16967 		    	this.fractionDigits = currInfo.decimals;
16968 		    	this.sign = currInfo.sign;
16969 		    	
16970 				if (typeof(onLoad) === 'function') {
16971 					onLoad(this);
16972 				}
16973 			})
16974 		});
16975 	},
16976 	
16977 	/**
16978 	 * Return the ISO 4217 currency code for this instance.
16979 	 * @return {string} the ISO 4217 currency code for this instance
16980 	 */
16981 	getCode: function () {
16982 		return this.code;
16983 	},
16984 	
16985 	/**
16986 	 * Return the default number of fraction digits that is typically used
16987 	 * with this type of currency.
16988 	 * @return {number} the number of fraction digits for this currency
16989 	 */
16990 	getFractionDigits: function () {
16991 		return this.fractionDigits;
16992 	},
16993 	
16994 	/**
16995 	 * Return the sign commonly used to represent this currency.
16996 	 * @return {string} the sign commonly used to represent this currency
16997 	 */
16998 	getSign: function () {
16999 		return this.sign;
17000 	},
17001 	
17002 	/**
17003 	 * Return the name of the currency in English.
17004 	 * @return {string} the name of the currency in English
17005 	 */
17006 	getName: function () {
17007 		return this.name;
17008 	},
17009 	
17010 	/**
17011 	 * Return the locale for this currency. If the options to the constructor 
17012 	 * included a locale property in order to find the currency that is appropriate
17013 	 * for that locale, then the locale is returned here. If the options did not
17014 	 * include a locale, then this method returns undefined.
17015 	 * @return {Locale} the locale used in the constructor of this instance,
17016 	 * or undefined if no locale was given in the constructor
17017 	 */
17018 	getLocale: function () {
17019 		return this.locale;
17020 	}
17021 };
17022 
17023 
17024 
17025 /*< INumber.js */
17026 /*
17027  * INumber.js - Parse a number in any locale
17028  * 
17029  * Copyright © 2012-2015, JEDLSoft
17030  *
17031  * Licensed under the Apache License, Version 2.0 (the "License");
17032  * you may not use this file except in compliance with the License.
17033  * You may obtain a copy of the License at
17034  *
17035  *     http://www.apache.org/licenses/LICENSE-2.0
17036  *
17037  * Unless required by applicable law or agreed to in writing, software
17038  * distributed under the License is distributed on an "AS IS" BASIS,
17039  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17040  *
17041  * See the License for the specific language governing permissions and
17042  * limitations under the License.
17043  */
17044 
17045 /*
17046 !depends 
17047 ilib.js 
17048 Locale.js 
17049 isDigit.js 
17050 isSpace.js
17051 LocaleInfo.js
17052 Utils.js
17053 Currency.js
17054 */
17055 
17056 
17057 
17058 
17059 
17060 
17061 /**
17062  * @class
17063  * Parse a string as a number, ignoring all locale-specific formatting.<p>
17064  * 
17065  * This class is different from the standard Javascript parseInt() and parseFloat() 
17066  * functions in that the number to be parsed can have formatting characters in it 
17067  * that are not supported by those two
17068  * functions, and it handles numbers written in other locales properly. For example, 
17069  * if you pass the string "203,231.23" to the parseFloat() function in Javascript, it 
17070  * will return you the number 203. The INumber class will parse it correctly and 
17071  * the value() function will return the number 203231.23. If you pass parseFloat() the 
17072  * string "203.231,23" with the locale set to de-DE, it will return you 203 again. This
17073  * class will return the correct number 203231.23 again.<p>
17074  * 
17075  * The options object may contain any of the following properties:
17076  * 
17077  * <ul>
17078  * <li><i>locale</i> - specify the locale of the string to parse. This is used to
17079  * figure out what the decimal point character is. If not specified, the default locale
17080  * for the app or browser is used.
17081  * <li><i>type</i> - specify whether this string should be interpretted as a number,
17082  * currency, or percentage amount. When the number is interpretted as a currency
17083  * amount, the getCurrency() method will return something useful, otherwise it will
17084  * return undefined. If
17085  * the number is to be interpretted as percentage amount and there is a percentage sign
17086  * in the string, then the number will be returned
17087  * as a fraction from the valueOf() method. If there is no percentage sign, then the 
17088  * number will be returned as a regular number. That is "58.3%" will be returned as the 
17089  * number 0.583 but "58.3" will be returned as 58.3. Valid values for this property 
17090  * are "number", "currency", and "percentage". Default if this is not specified is
17091  * "number".
17092  * <li><i>onLoad</i> - a callback function to call when the locale data is fully 
17093  * loaded. When the onLoad option is given, this class will attempt to
17094  * load any missing locale data using the ilib loader callback.
17095  * When the constructor is done (even if the data is already preassembled), the 
17096  * onLoad function is called with the current instance as a parameter, so this
17097  * callback can be used with preassembled or dynamic loading or a mix of the two. 
17098  * 
17099  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
17100  * asynchronously. If this option is given as "false", then the "onLoad"
17101  * callback must be given, as the instance returned from this constructor will
17102  * not be usable for a while.
17103  *  
17104  * <li><i>loadParams</i> - an object containing parameters to pass to the 
17105  * loader callback function when locale data is missing. The parameters are not
17106  * interpretted or modified in any way. They are simply passed along. The object 
17107  * may contain any property/value pairs as long as the calling code is in
17108  * agreement with the loader callback function as to what those parameters mean.
17109  * </ul>
17110  * <p>
17111  * 
17112  * This class is named INumber ("ilib number") so as not to conflict with the 
17113  * built-in Javascript Number class.
17114  * 
17115  * @constructor
17116  * @param {string|number|INumber|Number|undefined} str a string to parse as a number, or a number value
17117  * @param {Object=} options Options controlling how the instance should be created 
17118  */
17119 var INumber = function (str, options) {
17120 	var i, stripped = "", 
17121 		sync = true,
17122 		loadParams,
17123 		onLoad;
17124 	
17125 	this.locale = new Locale();
17126 	this.type = "number";
17127 	
17128 	if (options) {
17129 		if (options.locale) {
17130 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
17131 		}
17132 		if (options.type) {
17133 			switch (options.type) {
17134 				case "number":
17135 				case "currency":
17136 				case "percentage":
17137 					this.type = options.type;
17138 					break;
17139 				default:
17140 					break;
17141 			}
17142 		}
17143 		if (typeof(options.sync) !== 'undefined') {
17144 			sync = (options.sync == true);
17145 		}
17146 		loadParams = options.loadParams;
17147 		onLoad = options.onLoad;
17148 	}
17149 	
17150 	isDigit._init(sync, loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
17151 		isSpace._init(sync, loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
17152 			new LocaleInfo(this.locale, {
17153 				sync: sync,
17154 				onLoad: ilib.bind(this, function (li) {
17155 					this.decimal = li.getDecimalSeparator();
17156 					
17157 					switch (typeof(str)) {
17158 					case 'string':
17159 						// stripping should work for all locales, because you just ignore all the
17160 						// formatting except the decimal char
17161 						var unary = true; // looking for the unary minus still?
17162 						var lastNumericChar = 0;
17163 						this.str = str || "0";
17164 						i = 0;
17165 						for (i = 0; i < this.str.length; i++) {
17166 							if (unary && this.str.charAt(i) === '-') {
17167 								unary = false;
17168 								stripped += this.str.charAt(i);
17169 								lastNumericChar = i;
17170 							} else if (isDigit(this.str.charAt(i))) {
17171 								stripped += this.str.charAt(i);
17172 								unary = false;
17173 								lastNumericChar = i;
17174 							} else if (this.str.charAt(i) === this.decimal) {
17175 								stripped += "."; // always convert to period
17176 								unary = false;
17177 								lastNumericChar = i;
17178 							} // else ignore
17179 						}
17180 						// record what we actually parsed
17181 						this.parsed = this.str.substring(0, lastNumericChar+1);
17182 						this.value = parseFloat(stripped);
17183 						break;
17184 					case 'number':
17185 						this.str = "" + str;
17186 						this.value = str;
17187 						break;
17188 						
17189 					case 'object':
17190 						this.value = /** @type {number} */ str.valueOf();
17191 						this.str = "" + this.value;
17192 						break;
17193 						
17194 					case 'undefined':
17195 						this.value = 0;
17196 						this.str = "0";
17197 						break;
17198 					}
17199 					
17200 					switch (this.type) {
17201 						default:
17202 							// don't need to do anything special for other types
17203 							break;
17204 						case "percentage":
17205 							if (this.str.indexOf(li.getPercentageSymbol()) !== -1) {
17206 								this.value /= 100;
17207 							}
17208 							break;
17209 						case "currency":
17210 							stripped = "";
17211 							i = 0;
17212 							while (i < this.str.length &&
17213 								   !isDigit(this.str.charAt(i)) &&
17214 								   !isSpace(this.str.charAt(i))) {
17215 								stripped += this.str.charAt(i++);
17216 							}
17217 							if (stripped.length === 0) {
17218 								while (i < this.str.length && 
17219 									   isDigit(this.str.charAt(i)) ||
17220 									   isSpace(this.str.charAt(i)) ||
17221 									   this.str.charAt(i) === '.' ||
17222 									   this.str.charAt(i) === ',' ) {
17223 									i++;
17224 								}
17225 								while (i < this.str.length && 
17226 									   !isDigit(this.str.charAt(i)) &&
17227 									   !isSpace(this.str.charAt(i))) {
17228 									stripped += this.str.charAt(i++);
17229 								}
17230 							}
17231 							new Currency({
17232 								locale: this.locale, 
17233 								sign: stripped,
17234 								sync: sync,
17235 								onLoad: ilib.bind(this, function (cur) {
17236 									this.currency = cur;
17237 									if (options && typeof(options.onLoad) === 'function') {
17238 										options.onLoad(this);
17239 									}				
17240 								})
17241 							});
17242 							return;
17243 					}
17244 					
17245 					if (options && typeof(options.onLoad) === 'function') {
17246 						options.onLoad(this);
17247 					}
17248 				})
17249 			});
17250 		}));
17251 	}));
17252 };
17253 
17254 INumber.prototype = {
17255 	/**
17256 	 * Return the locale for this formatter instance.
17257 	 * @return {Locale} the locale instance for this formatter
17258 	 */
17259 	getLocale: function () {
17260 		return this.locale;
17261 	},
17262 	
17263 	/**
17264 	 * Return the original string that this number instance was created with.
17265 	 * @return {string} the original string
17266 	 */
17267 	toString: function () {
17268 		return this.str;
17269 	},
17270 	
17271 	/**
17272 	 * If the type of this INumber instance is "currency", then the parser will attempt
17273 	 * to figure out which currency this amount represents. The amount can be written
17274 	 * with any of the currency signs or ISO 4217 codes that are currently
17275 	 * recognized by ilib, and the currency signs may occur before or after the
17276 	 * numeric portion of the string. If no currency can be recognized, then the 
17277 	 * default currency for the locale is returned. If multiple currencies can be
17278 	 * recognized (for example if the currency sign is "$"), then this method 
17279 	 * will prefer the one for the current locale. If multiple currencies can be
17280 	 * recognized, but none are used in the current locale, then the first currency
17281 	 * encountered will be used. This may produce random results, though the larger
17282 	 * currencies occur earlier in the list. For example, if the sign found in the
17283 	 * string is "$" and that is not the sign of the currency of the current locale
17284 	 * then the US dollar will be recognized, as it is the largest currency that uses
17285 	 * the "$" as its sign.
17286 	 * 
17287 	 * @return {Currency|undefined} the currency instance for this amount, or 
17288 	 * undefined if this INumber object is not of type currency
17289 	 */
17290 	getCurrency: function () {
17291 		return this.currency;
17292 	},
17293 	
17294 	/**
17295 	 * Return the value of this INumber object as a primitive number instance.
17296 	 * @return {number} the value of this number instance
17297 	 */
17298 	valueOf: function () {
17299 		return this.value;
17300 	}
17301 };
17302 
17303 
17304 /*< NumFmt.js */
17305 /*
17306  * NumFmt.js - Number formatter definition
17307  *
17308  * Copyright © 2012-2015, JEDLSoft
17309  *
17310  * Licensed under the Apache License, Version 2.0 (the "License");
17311  * you may not use this file except in compliance with the License.
17312  * You may obtain a copy of the License at
17313  *
17314  *     http://www.apache.org/licenses/LICENSE-2.0
17315  *
17316  * Unless required by applicable law or agreed to in writing, software
17317  * distributed under the License is distributed on an "AS IS" BASIS,
17318  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17319  *
17320  * See the License for the specific language governing permissions and
17321  * limitations under the License.
17322  */
17323 
17324 /*
17325 !depends 
17326 ilib.js 
17327 Locale.js
17328 LocaleInfo.js
17329 Utils.js
17330 MathUtils.js
17331 Currency.js
17332 IString.js
17333 JSUtils.js
17334 INumber.js
17335 */
17336 
17337 // !data localeinfo currency
17338 
17339 
17340 
17341 /**
17342  * @class
17343  * Create a new number formatter instance. Locales differ in the way that digits
17344  * in a formatted number are grouped, in the way the decimal character is represented,
17345  * etc. Use this formatter to get it right for any locale.<p>
17346  *
17347  * This formatter can format plain numbers, currency amounts, and percentage amounts.<p>
17348  *
17349  * As with all formatters, the recommended
17350  * practice is to create one formatter and use it multiple times to format various
17351  * numbers.<p>
17352  *
17353  * The options can contain any of the following properties:
17354  *
17355  * <ul>
17356  * <li><i>locale</i> - use the conventions of the specified locale when figuring out how to
17357  * format a number.
17358  * <li><i>type</i> - the type of this formatter. Valid values are "number", "currency", or
17359  * "percentage". If this property is not specified, the default is "number".
17360  * <li><i>currency</i> - the ISO 4217 3-letter currency code to use when the formatter type
17361  * is "currency". This property is required for currency formatting. If the type property
17362  * is "currency" and the currency property is not specified, the constructor will throw a
17363  * an exception.
17364  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
17365  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
17366  * the integral part of the number.
17367  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
17368  * appear in the formatted output. If the number does not have enough fractional digits
17369  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
17370  * If the type of the formatter is "currency" and this
17371  * property is not specified, then the minimum fraction digits is set to the normal number
17372  * of digits used with that currency, which is almost always 0, 2, or 3 digits.
17373  * <li><i>useNative</i> - the flag used to determaine whether to use the native script settings
17374  * for formatting the numbers .
17375  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
17376  * this property governs how the least significant digits are rounded to conform to that
17377  * maximum. The value of this property is a string with one of the following values:
17378  * <ul>
17379  *   <li><i>up</i> - round away from zero
17380  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
17381  *   <li><i>ceiling</i> - round towards positive infinity
17382  *   <li><i>floor</i> - round towards negative infinity
17383  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
17384  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
17385  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
17386  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
17387  * </ul>
17388  * When the type of the formatter is "currency" and the <i>roundingMode</i> property is not
17389  * set, then the standard legal rounding rules for the locale are followed. If the type
17390  * is "number" or "percentage" and the <i>roundingMode</i> property is not set, then the
17391  * default mode is "halfdown".</i>.
17392  *
17393  * <li><i>style</i> - When the type of this formatter is "currency", the currency amount
17394  * can be formatted in the following styles: "common" and "iso". The common style is the
17395  * one commonly used in every day writing where the currency unit is represented using a
17396  * symbol. eg. "$57.35" for fifty-seven dollars and thirty five cents. The iso style is
17397  * the international style where the currency unit is represented using the ISO 4217 code.
17398  * eg. "USD 57.35" for the same amount. The default is "common" style if the style is
17399  * not specified.<p>
17400  *
17401  * When the type of this formatter is "number", the style can be one of the following:
17402  * <ul>
17403  *   <li><i>standard - format a fully specified floating point number properly for the locale
17404  *   <li><i>scientific</i> - use scientific notation for all numbers. That is, 1 integral 
17405  *   digit, followed by a number of fractional digits, followed by an "e" which denotes 
17406  *   exponentiation, followed digits which give the power of 10 in the exponent. 
17407  *   <li><i>native</i> - format a floating point number using the native digits and 
17408  *   formatting symbols for the script of the locale. 
17409  *   <li><i>nogrouping</i> - format a floating point number without grouping digits for
17410  *   the integral portion of the number
17411  * </ul>
17412  * Note that if you specify a maximum number
17413  * of integral digits, the formatter with a standard style will give you standard
17414  * formatting for smaller numbers and scientific notation for larger numbers. The default
17415  * is standard style if this is not specified.
17416  *
17417  * <li><i>onLoad</i> - a callback function to call when the format data is fully
17418  * loaded. When the onLoad option is given, this class will attempt to
17419  * load any missing locale data using the ilib loader callback.
17420  * When the constructor is done (even if the data is already preassembled), the
17421  * onLoad function is called with the current instance as a parameter, so this
17422  * callback can be used with preassembled or dynamic loading or a mix of the two.
17423  *
17424  * <li>sync - tell whether to load any missing locale data synchronously or
17425  * asynchronously. If this option is given as "false", then the "onLoad"
17426  * callback must be given, as the instance returned from this constructor will
17427  * not be usable for a while.
17428  *
17429  * <li><i>loadParams</i> - an object containing parameters to pass to the
17430  * loader callback function when locale data is missing. The parameters are not
17431  * interpretted or modified in any way. They are simply passed along. The object
17432  * may contain any property/value pairs as long as the calling code is in
17433  * agreement with the loader callback function as to what those parameters mean.
17434  * </ul>
17435  * <p>
17436  *
17437  *
17438  * @constructor
17439  * @param {Object.<string,*>} options A set of options that govern how the formatter will behave
17440  */
17441 var NumFmt = function (options) {
17442 	var sync = true;
17443 	this.locale = new Locale();
17444 	/** 
17445 	 * @private
17446 	 * @type {string} 
17447 	 */
17448 	this.type = "number";
17449 	var loadParams = undefined;
17450 
17451 	if (options) {
17452 		if (options.locale) {
17453 			this.locale = (typeof (options.locale) === 'string') ? new Locale(options.locale) : options.locale;
17454 		}
17455 
17456 		if (options.type) {
17457 			if (options.type === 'number' ||
17458 				options.type === 'currency' ||
17459 				options.type === 'percentage') {
17460 				this.type = options.type;
17461 			}
17462 		}
17463 
17464 		if (options.currency) {
17465 			/** 
17466 			 * @private 
17467 			 * @type {string} 
17468 			 */
17469 			this.currency = options.currency;
17470 		}
17471 
17472 		if (typeof (options.maxFractionDigits) === 'number') {
17473 			/** 
17474 			 * @private 
17475 			 * @type {number|undefined} 
17476 			 */
17477 			this.maxFractionDigits = this._toPrimitive(options.maxFractionDigits);
17478 		}
17479 		if (typeof (options.minFractionDigits) === 'number') {
17480 			/** 
17481 			 * @private 
17482 			 * @type {number|undefined} 
17483 			 */
17484 			this.minFractionDigits = this._toPrimitive(options.minFractionDigits);
17485 			// enforce the limits to avoid JS exceptions
17486 			if (this.minFractionDigits < 0) {
17487 				this.minFractionDigits = 0;
17488 			}
17489 			if (this.minFractionDigits > 20) {
17490 				this.minFractionDigits = 20;
17491 			}
17492 		}
17493 		if (options.style) {
17494 			/** 
17495 			 * @private 
17496 			 * @type {string} 
17497 			 */
17498 			this.style = options.style;
17499 		}
17500 		if (typeof(options.useNative) === 'boolean') {
17501 			/** 
17502 			 * @private 
17503 			 * @type {boolean} 
17504 			 * */
17505 			this.useNative = options.useNative;
17506 		}
17507 		/** 
17508 		 * @private 
17509 		 * @type {string} 
17510 		 */
17511 		this.roundingMode = options.roundingMode;
17512 
17513 		if (typeof (options.sync) !== 'undefined') {
17514 			/** @type {boolean} */
17515 			sync = (options.sync == true);
17516 		}
17517 		
17518 		loadParams = options.loadParams;
17519 	}
17520 
17521 	/** 
17522 	 * @private 
17523 	 * @type {LocaleInfo|undefined} 
17524 	 */
17525 	this.localeInfo = undefined;
17526 	
17527 	new LocaleInfo(this.locale, {
17528 		sync: sync,
17529 		loadParams: loadParams,
17530 		onLoad: ilib.bind(this, function (li) {
17531 			/** 
17532 			 * @private 
17533 			 * @type {LocaleInfo|undefined} 
17534 			 */
17535 			this.localeInfo = li;
17536 
17537 			if (this.type === "number") {
17538 				this.templateNegative = new IString(this.localeInfo.getNegativeNumberFormat() || "-{n}");
17539 			} else if (this.type === "currency") {
17540 				var templates;
17541 
17542 				if (!this.currency || typeof (this.currency) != 'string') {
17543 					throw "A currency property is required in the options to the number formatter constructor when the type property is set to currency.";
17544 				}
17545 
17546 				new Currency({
17547 					locale: this.locale,
17548 					code: this.currency,
17549 					sync: sync,
17550 					loadParams: loadParams,
17551 					onLoad: ilib.bind(this, function (cur) {
17552 						this.currencyInfo = cur;
17553 						if (this.style !== "common" && this.style !== "iso") {
17554 							this.style = "common";
17555 						}
17556 						
17557 						if (typeof(this.maxFractionDigits) !== 'number' && typeof(this.minFractionDigits) !== 'number') {
17558 							this.minFractionDigits = this.maxFractionDigits = this.currencyInfo.getFractionDigits();
17559 						}
17560 
17561 						templates = this.localeInfo.getCurrencyFormats();
17562 						this.template = new IString(templates[this.style] || templates.common);
17563 						this.templateNegative = new IString(templates[this.style + "Negative"] || templates["commonNegative"]);
17564 						this.sign = (this.style === "iso") ? this.currencyInfo.getCode() : this.currencyInfo.getSign();
17565 						
17566 						if (!this.roundingMode) {
17567 							this.roundingMode = this.currencyInfo && this.currencyInfo.roundingMode;
17568 						}
17569 
17570 						this._init();
17571 
17572 						if (options && typeof (options.onLoad) === 'function') {
17573 							options.onLoad(this);
17574 						}
17575 					})
17576 				});
17577 				return;
17578 			} else if (this.type === "percentage") {
17579 				this.template =  new IString(this.localeInfo.getPercentageFormat() || "{n}%");
17580 				this.templateNegative = new IString(this.localeInfo.getNegativePercentageFormat() || this.localeInfo.getNegativeNumberFormat() + "%");
17581 			}
17582 
17583 			this._init();
17584 
17585 			if (options && typeof (options.onLoad) === 'function') {
17586 				options.onLoad(this);
17587 			}
17588 		})
17589 	});
17590 };
17591 
17592 /**
17593  * Return an array of available locales that this formatter can format
17594  * @static
17595  * @return {Array.<Locale>|undefined} an array of available locales
17596  */
17597 NumFmt.getAvailableLocales = function () {
17598 	return undefined;
17599 };
17600 
17601 /**
17602  * @private
17603  * @const
17604  * @type string
17605  */
17606 NumFmt.zeros = "0000000000000000000000000000000000000000000000000000000000000000000000";
17607 
17608 NumFmt.prototype = {
17609 	/**
17610 	 * Return true if this formatter uses native digits to format the number. If the useNative
17611 	 * option is given to the constructor, then this flag will be honoured. If the useNative
17612 	 * option is not given to the constructor, this this formatter will use native digits if
17613 	 * the locale typically uses native digits.
17614 	 * 
17615 	 *  @return {boolean} true if this formatter will format with native digits, false otherwise
17616 	 */
17617 	getUseNative: function() {
17618 		if (typeof(this.useNative) === "boolean") {
17619 			return this.useNative;
17620 		} 
17621 		return (this.localeInfo.getDigitsStyle() === "native");
17622 	},
17623 	
17624 	/**
17625 	 * @private
17626 	 */
17627 	_init: function () {
17628 		if (this.maxFractionDigits < this.minFractionDigits) {
17629 			this.minFractionDigits = this.maxFractionDigits;
17630 		}
17631 
17632 		if (!this.roundingMode) {
17633 			this.roundingMode = this.localeInfo.getRoundingMode();
17634 		}
17635 
17636 		if (!this.roundingMode) {
17637 			this.roundingMode = "halfdown";
17638 		}
17639 
17640 		// set up the function, so we only have to figure it out once
17641 		// and not every time we do format()
17642 		this.round = MathUtils[this.roundingMode];
17643 		if (!this.round) {
17644 			this.roundingMode = "halfdown";
17645 			this.round = MathUtils[this.roundingMode];
17646 		}
17647 		
17648 		if (this.style === "nogrouping") {
17649 			this.prigroupSize = this.secgroupSize = 0;
17650 		} else {
17651 			this.prigroupSize = this.localeInfo.getPrimaryGroupingDigits();
17652 			this.secgroupSize = this.localeInfo.getSecondaryGroupingDigits();
17653 			this.groupingSeparator = this.getUseNative() ? this.localeInfo.getNativeGroupingSeparator() : this.localeInfo.getGroupingSeparator();
17654 		} 
17655 		this.decimalSeparator = this.getUseNative() ? this.localeInfo.getNativeDecimalSeparator() : this.localeInfo.getDecimalSeparator();
17656 		
17657 		if (this.getUseNative()) {
17658 			var nd = this.localeInfo.getNativeDigits() || this.localeInfo.getDigits();
17659 			if (nd) {
17660 				this.digits = nd.split("");
17661 			}
17662 		}
17663 		
17664 		this.exponentSymbol = this.localeInfo.getExponential() || "e";
17665 	},
17666 
17667 	/*
17668 	 * @private
17669 	 */
17670 	_pad: function (str, length, left) {
17671 		return (str.length >= length) ?
17672 			str :
17673 			(left ?
17674 			NumFmt.zeros.substring(0, length - str.length) + str :
17675 			str + NumFmt.zeros.substring(0, length - str.length));
17676 	},
17677 
17678 	/**
17679 	 * @private
17680 	 * @param {INumber|Number|string|number} num object, string, or number to convert to a primitive number
17681 	 * @return {number} the primitive number equivalent of the argument
17682 	 */
17683 	_toPrimitive: function (num) {
17684 		var n = 0;
17685 
17686 		switch (typeof (num)) {
17687 		case 'number':
17688 			n = num;
17689 			break;
17690 		case 'string':
17691 			n = parseFloat(num);
17692 			break;
17693 		case 'object':
17694 			// Number.valueOf() is incorrectly documented as being of type "string" rather than "number", so coerse 
17695 			// the type here to shut the type checker up
17696 			n = /** @type {number} */ num.valueOf();
17697 			break;
17698 		}
17699 
17700 		return n;
17701 	},
17702 
17703 	/**
17704 	 * Format the number using scientific notation as a positive number. Negative
17705 	 * formatting to be applied later.
17706 	 * @private
17707 	 * @param {number} num the number to format
17708 	 * @return {string} the formatted number
17709 	 */
17710 	_formatScientific: function (num) {
17711 		var n = new Number(num);
17712 		var formatted;
17713 		
17714 		var factor,
17715 			str = n.toExponential(),
17716 			parts = str.split("e"),
17717 			significant = parts[0],
17718 			exponent = parts[1],
17719 			numparts,
17720 			integral,
17721 			fraction;
17722 
17723 		if (this.maxFractionDigits > 0) {
17724 			// if there is a max fraction digits setting, round the fraction to 
17725 			// the right length first by dividing or multiplying by powers of 10. 
17726 			// manipulate the fraction digits so as to
17727 			// avoid the rounding errors of floating point numbers
17728 			factor = Math.pow(10, this.maxFractionDigits);
17729 			significant = this.round(significant * factor) / factor;
17730 		}
17731 		numparts = ("" + significant).split(".");
17732 		integral = numparts[0];
17733 		fraction = numparts[1];
17734 		
17735 		if (typeof(this.maxFractionDigits) !== 'undefined') {
17736 			fraction = fraction.substring(0, this.maxFractionDigits);
17737 		}
17738 		if (typeof(this.minFractionDigits) !== 'undefined') {
17739 			fraction = this._pad(fraction || "", this.minFractionDigits, false);
17740 		}
17741 		formatted = integral;
17742 		if (fraction.length) {
17743 			formatted += this.decimalSeparator + fraction;	
17744 		} 
17745 		formatted += this.exponentSymbol + exponent;
17746 		return formatted;
17747 	},
17748 
17749 	/**
17750 	 * Formats the number as a positive number. Negative formatting to be applied later.
17751 	 * @private
17752 	 * @param {number} num the number to format
17753 	 * @return {string} the formatted number
17754 	 */
17755 	_formatStandard: function (num) {
17756 		var i;
17757 		var k;
17758 		
17759 		if (typeof(this.maxFractionDigits) !== 'undefined' && this.maxFractionDigits > -1) {
17760 			var factor = Math.pow(10, this.maxFractionDigits);
17761 			num = this.round(num * factor) / factor;
17762 		}
17763 
17764 		num = Math.abs(num);
17765 
17766 		var parts = ("" + num).split("."),
17767 			integral = parts[0],
17768 			fraction = parts[1],
17769 			cycle,
17770 			formatted;
17771 		
17772 		integral = integral.toString();
17773 
17774 		if (this.minFractionDigits > 0) {
17775 			fraction = this._pad(fraction || "", this.minFractionDigits, false);
17776 		}
17777 
17778 		if (this.secgroupSize > 0) {
17779 			if (integral.length > this.prigroupSize) {
17780 				var size1 = this.prigroupSize;
17781 				var size2 = integral.length;
17782 				var size3 = size2 - size1;
17783 				integral = integral.slice(0, size3) + this.groupingSeparator + integral.slice(size3);
17784 				var num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
17785 				k = num_sec.length;
17786 				while (k > this.secgroupSize) {
17787 					var secsize1 = this.secgroupSize;
17788 					var secsize2 = num_sec.length;
17789 					var secsize3 = secsize2 - secsize1;
17790 					integral = integral.slice(0, secsize3) + this.groupingSeparator + integral.slice(secsize3);
17791 					num_sec = integral.substring(0, integral.indexOf(this.groupingSeparator));
17792 					k = num_sec.length;
17793 				}
17794 			}
17795 
17796 			formatted = integral;
17797 		} else if (this.prigroupSize !== 0) {
17798 			cycle = MathUtils.mod(integral.length - 1, this.prigroupSize);
17799 
17800 			formatted = "";
17801 
17802 			for (i = 0; i < integral.length - 1; i++) {
17803 				formatted += integral.charAt(i);
17804 				if (cycle === 0) {
17805 					formatted += this.groupingSeparator;
17806 				}
17807 				cycle = MathUtils.mod(cycle - 1, this.prigroupSize);
17808 			}
17809 			formatted += integral.charAt(integral.length - 1);
17810 		} else {
17811 			formatted = integral;
17812 		}
17813 
17814 		if (fraction && (typeof(this.maxFractionDigits) === 'undefined' || this.maxFractionDigits > 0)) {
17815 			formatted += this.decimalSeparator;
17816 			formatted += fraction;
17817 		}
17818 		
17819 		if (this.digits) {
17820 			formatted = JSUtils.mapString(formatted, this.digits);
17821 		}
17822 		
17823 		return formatted;
17824 	},
17825 
17826 	/**
17827 	 * Format a number according to the settings of this number formatter instance.
17828 	 * @param num {number|string|INumber|Number} a floating point number to format
17829 	 * @return {string} a string containing the formatted number
17830 	 */
17831 	format: function (num) {
17832 		var formatted, n;
17833 
17834 		if (typeof (num) === 'undefined') {
17835 			return "";
17836 		}
17837 
17838 		// convert to a real primitive number type
17839 		n = this._toPrimitive(num);
17840 
17841 		if (this.type === "number") {
17842 			formatted = (this.style === "scientific") ?
17843 				this._formatScientific(n) :
17844 				this._formatStandard(n);
17845 
17846 			if (num < 0) {
17847 				formatted = this.templateNegative.format({n: formatted});
17848 			}
17849 		} else {
17850 			formatted = this._formatStandard(n);
17851 			var template = (n < 0) ? this.templateNegative : this.template;
17852 			formatted = template.format({
17853 				n: formatted,
17854 				s: this.sign
17855 			});
17856 		}
17857 
17858 		return formatted;
17859 	},
17860 
17861 	/**
17862 	 * Return the type of formatter. Valid values are "number", "currency", and
17863 	 * "percentage".
17864 	 *
17865 	 * @return {string} the type of formatter
17866 	 */
17867 	getType: function () {
17868 		return this.type;
17869 	},
17870 
17871 	/**
17872 	 * Return the locale for this formatter instance.
17873 	 * @return {Locale} the locale instance for this formatter
17874 	 */
17875 	getLocale: function () {
17876 		return this.locale;
17877 	},
17878 
17879 	/**
17880 	 * Returns true if this formatter groups together digits in the integral
17881 	 * portion of a number, based on the options set up in the constructor. In
17882 	 * most western European cultures, this means separating every 3 digits
17883 	 * of the integral portion of a number with a particular character.
17884 	 *
17885 	 * @return {boolean} true if this formatter groups digits in the integral
17886 	 * portion of the number
17887 	 */
17888 	isGroupingUsed: function () {
17889 		return (this.groupingSeparator !== 'undefined' && this.groupingSeparator.length > 0);
17890 	},
17891 
17892 	/**
17893 	 * Returns the maximum fraction digits set up in the constructor.
17894 	 *
17895 	 * @return {number} the maximum number of fractional digits this
17896 	 * formatter will format, or -1 for no maximum
17897 	 */
17898 	getMaxFractionDigits: function () {
17899 		return typeof (this.maxFractionDigits) !== 'undefined' ? this.maxFractionDigits : -1;
17900 	},
17901 
17902 	/**
17903 	 * Returns the minimum fraction digits set up in the constructor. If
17904 	 * the formatter has the type "currency", then the minimum fraction
17905 	 * digits is the amount of digits that is standard for the currency
17906 	 * in question unless overridden in the options to the constructor.
17907 	 *
17908 	 * @return {number} the minimum number of fractional digits this
17909 	 * formatter will format, or -1 for no minimum
17910 	 */
17911 	getMinFractionDigits: function () {
17912 		return typeof (this.minFractionDigits) !== 'undefined' ? this.minFractionDigits : -1;
17913 	},
17914 
17915 	/**
17916 	 * Returns the ISO 4217 code for the currency that this formatter formats.
17917 	 * IF the typeof this formatter is not "currency", then this method will
17918 	 * return undefined.
17919 	 *
17920 	 * @return {string} the ISO 4217 code for the currency that this formatter
17921 	 * formats, or undefined if this not a currency formatter
17922 	 */
17923 	getCurrency: function () {
17924 		return this.currencyInfo && this.currencyInfo.getCode();
17925 	},
17926 
17927 	/**
17928 	 * Returns the rounding mode set up in the constructor. The rounding mode
17929 	 * controls how numbers are rounded when the integral or fraction digits
17930 	 * of a number are limited.
17931 	 *
17932 	 * @return {string} the name of the rounding mode used in this formatter
17933 	 */
17934 	getRoundingMode: function () {
17935 		return this.roundingMode;
17936 	},
17937 
17938 	/**
17939 	 * If this formatter is a currency formatter, then the style determines how the
17940 	 * currency is denoted in the formatted output. This method returns the style
17941 	 * that this formatter will produce. (See the constructor comment for more about
17942 	 * the styles.)
17943 	 * @return {string} the name of the style this formatter will use to format
17944 	 * currency amounts, or "undefined" if this formatter is not a currency formatter
17945 	 */
17946 	getStyle: function () {
17947 		return this.style;
17948 	}
17949 };
17950 
17951 
17952 /*< DurationFmt.js */
17953 /*
17954  * DurFmt.js - Date formatter definition
17955  * 
17956  * Copyright © 2012-2015, JEDLSoft
17957  *
17958  * Licensed under the Apache License, Version 2.0 (the "License");
17959  * you may not use this file except in compliance with the License.
17960  * You may obtain a copy of the License at
17961  *
17962  *     http://www.apache.org/licenses/LICENSE-2.0
17963  *
17964  * Unless required by applicable law or agreed to in writing, software
17965  * distributed under the License is distributed on an "AS IS" BASIS,
17966  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17967  *
17968  * See the License for the specific language governing permissions and
17969  * limitations under the License.
17970  */
17971 
17972 /*
17973 !depends 
17974 ilib.js 
17975 Locale.js 
17976 DateFmt.js
17977 IString.js 
17978 ResBundle.js 
17979 LocaleInfo.js
17980 JSUtils.js
17981 Utils.js
17982 */
17983 
17984 // !data dateformats sysres
17985 // !resbundle sysres
17986 
17987 
17988 /**
17989  * @class
17990  * Create a new duration formatter instance. The duration formatter is immutable once
17991  * it is created, but can format as many different durations as needed with the same
17992  * options. Create different duration formatter instances for different purposes
17993  * and then keep them cached for use later if you have more than one duration to
17994  * format.<p>
17995  * 
17996  * Duration formatters format lengths of time. The duration formatter is meant to format 
17997  * durations of such things as the length of a song or a movie or a meeting, or the 
17998  * current position in that song or movie while playing it. If you wish to format a 
17999  * period of time that has a specific start and end date/time, then use a
18000  * [DateRngFmt] instance instead and call its format method.<p>
18001  *  
18002  * The options may contain any of the following properties:
18003  * 
18004  * <ul>
18005  * <li><i>locale</i> - locale to use when formatting the duration. If the locale is
18006  * not specified, then the default locale of the app or web page will be used.
18007  * 
18008  * <li><i>length</i> - Specify the length of the format to use. The length is the approximate size of the 
18009  * formatted string.
18010  * 
18011  * <ul>
18012  * <li><i>short</i> - use a short representation of the duration. This is the most compact format possible for the locale. eg. 1y 1m 1w 1d 1:01:01
18013  * <li><i>medium</i> - use a medium length representation of the duration. This is a slightly longer format. eg. 1 yr 1 mo 1 wk 1 dy 1 hr 1 mi 1 se
18014  * <li><i>long</i> - use a long representation of the duration. This is a fully specified format, but some of the textual 
18015  * parts may still be abbreviated. eg. 1 yr 1 mo 1 wk 1 day 1 hr 1 min 1 sec
18016  * <li><i>full</i> - use a full representation of the duration. This is a fully specified format where all the textual 
18017  * parts are spelled out completely. eg. 1 year, 1 month, 1 week, 1 day, 1 hour, 1 minute and 1 second
18018  * </ul>
18019  * 
18020  * <li><i>style<i> - whether hours, minutes, and seconds should be formatted as a text string
18021  * or as a regular time as on a clock. eg. text is "1 hour, 15 minutes", whereas clock is "1:15:00". Valid
18022  * values for this property are "text" or "clock". Default if this property is not specified
18023  * is "text".
18024  * 
18025  *<li><i>useNative</i> - the flag used to determaine whether to use the native script settings 
18026  * for formatting the numbers .
18027  * 
18028  * <li><i>onLoad</i> - a callback function to call when the format data is fully 
18029  * loaded. When the onLoad option is given, this class will attempt to
18030  * load any missing locale data using the ilib loader callback.
18031  * When the constructor is done (even if the data is already preassembled), the 
18032  * onLoad function is called with the current instance as a parameter, so this
18033  * callback can be used with preassembled or dynamic loading or a mix of the two. 
18034  * 
18035  * <li>sync - tell whether to load any missing locale data synchronously or 
18036  * asynchronously. If this option is given as "false", then the "onLoad"
18037  * callback must be given, as the instance returned from this constructor will
18038  * not be usable for a while.
18039  *  
18040  * <li><i>loadParams</i> - an object containing parameters to pass to the 
18041  * loader callback function when locale data is missing. The parameters are not
18042  * interpretted or modified in any way. They are simply passed along. The object 
18043  * may contain any property/value pairs as long as the calling code is in
18044  * agreement with the loader callback function as to what those parameters mean.
18045  * </ul>
18046  * <p>
18047  * 
18048  * 
18049  * @constructor
18050  * @param {?Object} options options governing the way this date formatter instance works
18051  */
18052 var DurationFmt = function(options) {
18053 	var sync = true;
18054 	var loadParams = undefined;
18055 	
18056 	this.locale = new Locale();
18057 	this.length = "short";
18058 	this.style = "text";
18059 	
18060 	if (options) {
18061 		if (options.locale) {
18062 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
18063 		}
18064 		
18065 		if (options.length) {
18066 			if (options.length === 'short' ||
18067 				options.length === 'medium' ||
18068 				options.length === 'long' ||
18069 				options.length === 'full') {
18070 				this.length = options.length;
18071 			}
18072 		}
18073 		
18074 		if (options.style) {
18075 			if (options.style === 'text' || options.style === 'clock') {
18076 				this.style = options.style;
18077 			}
18078 		}
18079 		
18080 		if (typeof(options.sync) !== 'undefined') {
18081 			sync = (options.sync == true);
18082 		}
18083 		
18084 		if (typeof(options.useNative) === 'boolean') {
18085 			this.useNative = options.useNative;
18086 		}
18087 		
18088 		loadParams = options.loadParams;
18089 	}
18090 	
18091 	new ResBundle({
18092 		locale: this.locale,
18093 		name: "sysres",
18094 		sync: sync,
18095 		loadParams: loadParams,
18096 		onLoad: ilib.bind(this, function (sysres) {
18097 			switch (this.length) {
18098 				case 'short':
18099 					this.components = {
18100 						year: sysres.getString("#{num}y"),
18101 						month: sysres.getString("#{num}m", "durationShortMonths"),
18102 						week: sysres.getString("#{num}w"),
18103 						day: sysres.getString("#{num}d"),
18104 						hour: sysres.getString("#{num}h"),
18105 						minute: sysres.getString("#{num}m", "durationShortMinutes"),
18106 						second: sysres.getString("#{num}s"),
18107 						millisecond: sysres.getString("#{num}m", "durationShortMillis"),
18108 						separator: sysres.getString(" ", "separatorShort"),
18109 						finalSeparator: "" // not used at this length
18110 					};
18111 					break;
18112 					
18113 				case 'medium':
18114 					this.components = {
18115 						year: sysres.getString("1#1 yr|#{num} yrs", "durationMediumYears"),
18116 						month: sysres.getString("1#1 mo|#{num} mos"),
18117 						week: sysres.getString("1#1 wk|#{num} wks", "durationMediumWeeks"),
18118 						day: sysres.getString("1#1 dy|#{num} dys"),
18119 						hour: sysres.getString("1#1 hr|#{num} hrs", "durationMediumHours"),
18120 						minute: sysres.getString("1#1 mi|#{num} min"),
18121 						second: sysres.getString("1#1 se|#{num} sec"),
18122 						millisecond: sysres.getString("#{num} ms"),
18123 						separator: sysres.getString(" ", "separatorMedium"),
18124 						finalSeparator: "" // not used at this length
18125 					};
18126 					break;
18127 					
18128 				case 'long':
18129 					this.components = {
18130 						year: sysres.getString("1#1 yr|#{num} yrs"),
18131 						month: sysres.getString("1#1 mon|#{num} mons"),
18132 						week: sysres.getString("1#1 wk|#{num} wks"),
18133 						day: sysres.getString("1#1 day|#{num} days", "durationLongDays"),
18134 						hour: sysres.getString("1#1 hr|#{num} hrs"),
18135 						minute: sysres.getString("1#1 min|#{num} min"),
18136 						second: sysres.getString("1#1 sec|#{num} sec"),
18137 						millisecond: sysres.getString("#{num} ms"),
18138 						separator: sysres.getString(", ", "separatorLong"),
18139 						finalSeparator: "" // not used at this length
18140 					};
18141 					break;
18142 					
18143 				case 'full':
18144 					this.components = {
18145 						year: sysres.getString("1#1 year|#{num} years"),
18146 						month: sysres.getString("1#1 month|#{num} months"),
18147 						week: sysres.getString("1#1 week|#{num} weeks"),
18148 						day: sysres.getString("1#1 day|#{num} days"),
18149 						hour: sysres.getString("1#1 hour|#{num} hours"),
18150 						minute: sysres.getString("1#1 minute|#{num} minutes"),
18151 						second: sysres.getString("1#1 second|#{num} seconds"),
18152 						millisecond: sysres.getString("1#1 millisecond|#{num} milliseconds"),
18153 						separator: sysres.getString(", ", "separatorFull"),
18154 						finalSeparator: sysres.getString(" and ", "finalSeparatorFull")
18155 					};
18156 					break;
18157 			}
18158 			
18159 			if (this.style === 'clock') {
18160 				new DateFmt({
18161 					locale: this.locale,
18162 					calendar: "gregorian",
18163 					type: "time",
18164 					time: "ms",
18165 					sync: sync,
18166 					loadParams: loadParams,
18167 					useNative: this.useNative,
18168 					onLoad: ilib.bind(this, function (fmtMS) {
18169 						this.timeFmtMS = fmtMS;
18170 						new DateFmt({
18171 							locale: this.locale,
18172 							calendar: "gregorian",
18173 							type: "time",
18174 							time: "hm",
18175 							sync: sync,
18176 							loadParams: loadParams,
18177 							useNative: this.useNative,
18178 							onLoad: ilib.bind(this, function (fmtHM) {
18179 								this.timeFmtHM = fmtHM;		
18180 								new DateFmt({
18181 									locale: this.locale,
18182 									calendar: "gregorian",
18183 									type: "time",
18184 									time: "hms",
18185 									sync: sync,
18186 									loadParams: loadParams,
18187 									useNative: this.useNative,
18188 									onLoad: ilib.bind(this, function (fmtHMS) {
18189 										this.timeFmtHMS = fmtHMS;		
18190 
18191 										// munge with the template to make sure that the hours are not formatted mod 12
18192 										this.timeFmtHM.template = this.timeFmtHM.template.replace(/hh?/, 'H');
18193 										this.timeFmtHM.templateArr = this.timeFmtHM._tokenize(this.timeFmtHM.template);
18194 										this.timeFmtHMS.template = this.timeFmtHMS.template.replace(/hh?/, 'H');
18195 										this.timeFmtHMS.templateArr = this.timeFmtHMS._tokenize(this.timeFmtHMS.template);
18196 										
18197 										this._init(this.timeFmtHM.locinfo, options && options.onLoad);
18198 									})
18199 								});
18200 							})
18201 						});
18202 					})
18203 				});
18204 				return;
18205 			}
18206 
18207 			new LocaleInfo(this.locale, {
18208 				sync: sync,
18209 				loadParams: loadParams,
18210 				onLoad: ilib.bind(this, function (li) {
18211 					this._init(li, options && options.onLoad);
18212 				})
18213 			});
18214 		})
18215 	});
18216 };
18217 
18218 /**
18219  * @private
18220  * @static
18221  */
18222 DurationFmt.complist = {
18223 	"text": ["year", "month", "week", "day", "hour", "minute", "second", "millisecond"],
18224 	"clock": ["year", "month", "week", "day"]
18225 };
18226 
18227 /**
18228  * @private
18229  */
18230 DurationFmt.prototype._mapDigits = function(str) {
18231 	if (this.useNative && this.digits) {
18232 		return JSUtils.mapString(str.toString(), this.digits);
18233 	}
18234 	return str;
18235 };
18236 
18237 /**
18238  * @private
18239  * @param {LocaleInfo} locinfo
18240  * @param {function(DurationFmt)|undefined} onLoad
18241  */
18242 DurationFmt.prototype._init = function(locinfo, onLoad) {
18243 	var digits;
18244 	if (typeof(this.useNative) === 'boolean') {
18245 		// if the caller explicitly said to use native or not, honour that despite what the locale data says...
18246 		if (this.useNative) {
18247 			digits = locinfo.getNativeDigits();
18248 			if (digits) {
18249 				this.digits = digits;
18250 			}
18251 		}
18252 	} else if (locinfo.getDigitsStyle() === "native") {
18253 		// else if the locale usually uses native digits, then use them 
18254 		digits = locinfo.getNativeDigits();
18255 		if (digits) {
18256 			this.useNative = true;
18257 			this.digits = digits;
18258 		}
18259 	} // else use western digits always
18260 
18261 	if (typeof(onLoad) === 'function') {
18262 		onLoad(this);
18263 	}
18264 };
18265 
18266 /**
18267  * Format a duration according to the format template of this formatter instance.<p>
18268  * 
18269  * The components parameter should be an object that contains any or all of these 
18270  * numeric properties:
18271  * 
18272  * <ul>
18273  * <li>year
18274  * <li>month
18275  * <li>week
18276  * <li>day
18277  * <li>hour
18278  * <li>minute
18279  * <li>second
18280  * </ul>
18281  * <p>
18282  *
18283  * When a property is left out of the components parameter or has a value of 0, it will not
18284  * be formatted into the output string, except for times that include 0 minutes and 0 seconds.
18285  * 
18286  * This formatter will not ensure that numbers for each component property is within the
18287  * valid range for that component. This allows you to format durations that are longer
18288  * than normal range. For example, you could format a duration has being "33 hours" rather
18289  * than "1 day, 9 hours".
18290  * 
18291  * @param {Object} components date/time components to be formatted into a duration string
18292  * @return {IString} a string with the duration formatted according to the style and 
18293  * locale set up for this formatter instance. If the components parameter is empty or 
18294  * undefined, an empty string is returned.
18295  */
18296 DurationFmt.prototype.format = function (components) {
18297 	var i, list, temp, fmt, secondlast = true, str = "";
18298 	
18299 	list = DurationFmt.complist[this.style];
18300 	//for (i = 0; i < list.length; i++) {
18301 	for (i = list.length-1; i >= 0; i--) {
18302 		//console.log("Now dealing with " + list[i]);
18303 		if (typeof(components[list[i]]) !== 'undefined' && components[list[i]] != 0) {
18304 			if (str.length > 0) {
18305 				str = ((this.length === 'full' && secondlast) ? this.components.finalSeparator : this.components.separator) + str;
18306 				secondlast = false;
18307 			}
18308 			str = this.components[list[i]].formatChoice(components[list[i]], {num: this._mapDigits(components[list[i]])}) + str;
18309 		}
18310 	}
18311 
18312 	if (this.style === 'clock') {
18313 		if (typeof(components.hour) !== 'undefined') {
18314 			fmt = (typeof(components.second) !== 'undefined') ? this.timeFmtHMS : this.timeFmtHM;
18315 		} else {
18316 			fmt = this.timeFmtMS;
18317 		}
18318 				
18319 		if (str.length > 0) {
18320 			str += this.components.separator;
18321 		}
18322 		str += fmt._formatTemplate(components, fmt.templateArr);
18323 	}
18324 	
18325 	return new IString(str);
18326 };
18327 
18328 /**
18329  * Return the locale that was used to construct this duration formatter object. If the
18330  * locale was not given as parameter to the constructor, this method returns the default
18331  * locale of the system.
18332  * 
18333  * @return {Locale} locale that this duration formatter was constructed with
18334  */
18335 DurationFmt.prototype.getLocale = function () {
18336 	return this.locale;
18337 };
18338 
18339 /**
18340  * Return the length that was used to construct this duration formatter object. If the
18341  * length was not given as parameter to the constructor, this method returns the default
18342  * length. Valid values are "short", "medium", "long", and "full".
18343  * 
18344  * @return {string} length that this duration formatter was constructed with
18345  */
18346 DurationFmt.prototype.getLength = function () {
18347 	return this.length;
18348 };
18349 
18350 /**
18351  * Return the style that was used to construct this duration formatter object. Returns
18352  * one of "text" or "clock".
18353  * 
18354  * @return {string} style that this duration formatter was constructed with
18355  */
18356 DurationFmt.prototype.getStyle = function () {
18357 	return this.style;
18358 };
18359 
18360 
18361 /*< isAlpha.js */
18362 /*
18363  * ctype.islpha.js - Character type is alphabetic
18364  * 
18365  * Copyright © 2012-2015, JEDLSoft
18366  *
18367  * Licensed under the Apache License, Version 2.0 (the "License");
18368  * you may not use this file except in compliance with the License.
18369  * You may obtain a copy of the License at
18370  *
18371  *     http://www.apache.org/licenses/LICENSE-2.0
18372  *
18373  * Unless required by applicable law or agreed to in writing, software
18374  * distributed under the License is distributed on an "AS IS" BASIS,
18375  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18376  *
18377  * See the License for the specific language governing permissions and
18378  * limitations under the License.
18379  */
18380 
18381 // !depends CType.js IString.js ilib.js
18382 
18383 // !data ctype_l
18384 
18385 
18386 /**
18387  * Return whether or not the first character is alphabetic.<p>
18388  * 
18389  * @static
18390  * @param {string|IString|number} ch character or code point to examine
18391  * @return {boolean} true if the first character is alphabetic.
18392  */
18393 var isAlpha = function (ch) {
18394 	var num;
18395 	switch (typeof(ch)) {
18396 		case 'number':
18397 			num = ch;
18398 			break;
18399 		case 'string':
18400 			num = IString.toCodePoint(ch, 0);
18401 			break;
18402 		case 'undefined':
18403 			return false;
18404 		default:
18405 			num = ch._toCodePoint(0);
18406 			break;
18407 	}
18408 	return CType._inRange(num, 'Lu', ilib.data.ctype_l) ||
18409 		CType._inRange(num, 'Ll', ilib.data.ctype_l) ||
18410 		CType._inRange(num, 'Lt', ilib.data.ctype_l) ||
18411 		CType._inRange(num, 'Lm', ilib.data.ctype_l) ||
18412 		CType._inRange(num, 'Lo', ilib.data.ctype_l);
18413 };
18414 
18415 /**
18416  * @protected
18417  * @param {boolean} sync
18418  * @param {Object|undefined} loadParams
18419  * @param {function(*)|undefined} onLoad
18420  */
18421 isAlpha._init = function (sync, loadParams, onLoad) {
18422 	CType._load("ctype_l", sync, loadParams, onLoad);
18423 };
18424 
18425 
18426 /*< isAlnum.js */
18427 /*
18428  * isAlnum.js - Character type is alphanumeric
18429  * 
18430  * Copyright © 2012-2015, JEDLSoft
18431  *
18432  * Licensed under the Apache License, Version 2.0 (the "License");
18433  * you may not use this file except in compliance with the License.
18434  * You may obtain a copy of the License at
18435  *
18436  *     http://www.apache.org/licenses/LICENSE-2.0
18437  *
18438  * Unless required by applicable law or agreed to in writing, software
18439  * distributed under the License is distributed on an "AS IS" BASIS,
18440  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18441  *
18442  * See the License for the specific language governing permissions and
18443  * limitations under the License.
18444  */
18445 
18446 // !depends CType.js IString.js isAlpha.js isDigit.js
18447 
18448 
18449 /**
18450  * Return whether or not the first character is alphabetic or numeric.<p>
18451  * 
18452  * @static
18453  * @param {string|IString|number} ch character or code point to examine
18454  * @return {boolean} true if the first character is alphabetic or numeric
18455  */
18456 var isAlnum = function (ch) {
18457 	var num;
18458 	switch (typeof(ch)) {
18459 		case 'number':
18460 			num = ch;
18461 			break;
18462 		case 'string':
18463 			num = IString.toCodePoint(ch, 0);
18464 			break;
18465 		case 'undefined':
18466 			return false;
18467 		default:
18468 			num = ch._toCodePoint(0);
18469 			break;
18470 	}
18471 	return isAlpha(num) || isDigit(num);
18472 };
18473 
18474 /**
18475  * @protected
18476  * @param {boolean} sync
18477  * @param {Object|undefined} loadParams
18478  * @param {function(*)|undefined} onLoad
18479  */
18480 isAlnum._init = function (sync, loadParams, onLoad) {
18481 	isAlpha._init(sync, loadParams, function () {
18482 		isDigit._init(sync, loadParams, onLoad);
18483 	});
18484 };
18485 
18486 
18487 
18488 /*< isAscii.js */
18489 /*
18490  * isAscii.js - Character type is ASCII
18491  * 
18492  * Copyright © 2012-2015, JEDLSoft
18493  *
18494  * Licensed under the Apache License, Version 2.0 (the "License");
18495  * you may not use this file except in compliance with the License.
18496  * You may obtain a copy of the License at
18497  *
18498  *     http://www.apache.org/licenses/LICENSE-2.0
18499  *
18500  * Unless required by applicable law or agreed to in writing, software
18501  * distributed under the License is distributed on an "AS IS" BASIS,
18502  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18503  *
18504  * See the License for the specific language governing permissions and
18505  * limitations under the License.
18506  */
18507 
18508 // !depends CType.js IString.js ilib.js
18509 
18510 // !data ctype
18511 
18512 
18513 /**
18514  * Return whether or not the first character is in the ASCII range.<p>
18515  * 
18516  * @static
18517  * @param {string|IString|number} ch character or code point to examine
18518  * @return {boolean} true if the first character is in the ASCII range.
18519  */
18520 var isAscii = function (ch) {
18521 	var num;
18522 	switch (typeof(ch)) {
18523 		case 'number':
18524 			num = ch;
18525 			break;
18526 		case 'string':
18527 			num = IString.toCodePoint(ch, 0);
18528 			break;
18529 		case 'undefined':
18530 			return false;
18531 		default:
18532 			num = ch._toCodePoint(0);
18533 			break;
18534 	}
18535 	return CType._inRange(num, 'ascii', ilib.data.ctype);
18536 };
18537 
18538 /**
18539  * @protected
18540  * @param {boolean} sync
18541  * @param {Object|undefined} loadParams
18542  * @param {function(*)|undefined} onLoad
18543  */
18544 isAscii._init = function (sync, loadParams, onLoad) {
18545 	CType._init(sync, loadParams, onLoad);
18546 };
18547 
18548 
18549 /*< isBlank.js */
18550 /*
18551  * isBlank.js - Character type is blank
18552  * 
18553  * Copyright © 2012-2015, JEDLSoft
18554  *
18555  * Licensed under the Apache License, Version 2.0 (the "License");
18556  * you may not use this file except in compliance with the License.
18557  * You may obtain a copy of the License at
18558  *
18559  *     http://www.apache.org/licenses/LICENSE-2.0
18560  *
18561  * Unless required by applicable law or agreed to in writing, software
18562  * distributed under the License is distributed on an "AS IS" BASIS,
18563  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18564  *
18565  * See the License for the specific language governing permissions and
18566  * limitations under the License.
18567  */
18568 
18569 // !depends CType.js IString.js ilib.js
18570 
18571 // !data ctype
18572 
18573 
18574 /**
18575  * Return whether or not the first character is a blank character.<p>
18576  * 
18577  * @static
18578  * ie. a space or a tab.
18579  * @param {string|IString|number} ch character or code point to examine
18580  * @return {boolean} true if the first character is a blank character.
18581  */
18582 var isBlank = function (ch) {
18583 	var num;
18584 	switch (typeof(ch)) {
18585 		case 'number':
18586 			num = ch;
18587 			break;
18588 		case 'string':
18589 			num = IString.toCodePoint(ch, 0);
18590 			break;
18591 		case 'undefined':
18592 			return false;
18593 		default:
18594 			num = ch._toCodePoint(0);
18595 			break;
18596 	}
18597 	return CType._inRange(num, 'blank', ilib.data.ctype);
18598 };
18599 
18600 /**
18601  * @protected
18602  * @param {boolean} sync
18603  * @param {Object|undefined} loadParams
18604  * @param {function(*)|undefined} onLoad
18605  */
18606 isBlank._init = function (sync, loadParams, onLoad) {
18607 	CType._init(sync, loadParams, onLoad);
18608 };
18609 
18610 
18611 /*< isCntrl.js */
18612 /*
18613  * isCntrl.js - Character type is control character
18614  * 
18615  * Copyright © 2012-2015, JEDLSoft
18616  *
18617  * Licensed under the Apache License, Version 2.0 (the "License");
18618  * you may not use this file except in compliance with the License.
18619  * You may obtain a copy of the License at
18620  *
18621  *     http://www.apache.org/licenses/LICENSE-2.0
18622  *
18623  * Unless required by applicable law or agreed to in writing, software
18624  * distributed under the License is distributed on an "AS IS" BASIS,
18625  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18626  *
18627  * See the License for the specific language governing permissions and
18628  * limitations under the License.
18629  */
18630 
18631 // !depends CType.js IString.js ilib.js
18632 
18633 // !data ctype_c
18634 
18635 
18636 /**
18637  * Return whether or not the first character is a control character.<p>
18638  * 
18639  * @static
18640  * @param {string|IString|number} ch character or code point to examine
18641  * @return {boolean} true if the first character is a control character.
18642  */
18643 var isCntrl = function (ch) {
18644 	var num;
18645 	switch (typeof(ch)) {
18646 		case 'number':
18647 			num = ch;
18648 			break;
18649 		case 'string':
18650 			num = IString.toCodePoint(ch, 0);
18651 			break;
18652 		case 'undefined':
18653 			return false;
18654 		default:
18655 			num = ch._toCodePoint(0);
18656 			break;
18657 	}
18658 	return CType._inRange(num, 'Cc', ilib.data.ctype_c);
18659 };
18660 
18661 /**
18662  * @protected
18663  * @param {boolean} sync
18664  * @param {Object|undefined} loadParams
18665  * @param {function(*)|undefined} onLoad
18666  */
18667 isCntrl._init = function (sync, loadParams, onLoad) {
18668 	CType._load("ctype_c", sync, loadParams, onLoad);
18669 };
18670 
18671 
18672 /*< isGraph.js */
18673 /*
18674  * isGraph.js - Character type is graph char
18675  * 
18676  * Copyright © 2012-2015, JEDLSoft
18677  *
18678  * Licensed under the Apache License, Version 2.0 (the "License");
18679  * you may not use this file except in compliance with the License.
18680  * You may obtain a copy of the License at
18681  *
18682  *     http://www.apache.org/licenses/LICENSE-2.0
18683  *
18684  * Unless required by applicable law or agreed to in writing, software
18685  * distributed under the License is distributed on an "AS IS" BASIS,
18686  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18687  *
18688  * See the License for the specific language governing permissions and
18689  * limitations under the License.
18690  */
18691 
18692 // !depends IString.js isSpace.js isCntrl.js ilib.js
18693 
18694 
18695 /**
18696  * Return whether or not the first character is any printable character
18697  * other than space.<p>
18698  * 
18699  * @static
18700  * @param {string|IString|number} ch character or code point to examine
18701  * @return {boolean} true if the first character is any printable character
18702  * other than space. 
18703  */
18704 var isGraph = function (ch) {
18705 	var num;
18706 	switch (typeof(ch)) {
18707 		case 'number':
18708 			num = ch;
18709 			break;
18710 		case 'string':
18711 			num = IString.toCodePoint(ch, 0);
18712 			break;
18713 		case 'undefined':
18714 			return false;
18715 		default:
18716 			num = ch._toCodePoint(0);
18717 			break;
18718 	}
18719 	return typeof(ch) !== 'undefined' && ch.length > 0 && !isSpace(num) && !isCntrl(num);
18720 };
18721 
18722 /**
18723  * @protected
18724  * @param {boolean} sync
18725  * @param {Object|undefined} loadParams
18726  * @param {function(*)|undefined} onLoad
18727  */
18728 isGraph._init = function (sync, loadParams, onLoad) {
18729 	isSpace._init(sync, loadParams, function () {
18730 		isCntrl._init(sync, loadParams, onLoad);
18731 	});
18732 };
18733 
18734 
18735 
18736 /*< isIdeo.js */
18737 /*
18738  * CType.js - Character type definitions
18739  * 
18740  * Copyright © 2012-2015, JEDLSoft
18741  *
18742  * Licensed under the Apache License, Version 2.0 (the "License");
18743  * you may not use this file except in compliance with the License.
18744  * You may obtain a copy of the License at
18745  *
18746  *     http://www.apache.org/licenses/LICENSE-2.0
18747  *
18748  * Unless required by applicable law or agreed to in writing, software
18749  * distributed under the License is distributed on an "AS IS" BASIS,
18750  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18751  *
18752  * See the License for the specific language governing permissions and
18753  * limitations under the License.
18754  */
18755 
18756 // !depends CType.js IString.js
18757 
18758 // !data ctype
18759 
18760 
18761 /**
18762  * Return whether or not the first character is an ideographic character.<p>
18763  * 
18764  * @static
18765  * @param {string|IString|number} ch character or code point to examine
18766  * @return {boolean} true if the first character is an ideographic character.
18767  */
18768 var isIdeo = function (ch) {
18769 	var num;
18770 	switch (typeof(ch)) {
18771 		case 'number':
18772 			num = ch;
18773 			break;
18774 		case 'string':
18775 			num = IString.toCodePoint(ch, 0);
18776 			break;
18777 		case 'undefined':
18778 			return false;
18779 		default:
18780 			num = ch._toCodePoint(0);
18781 			break;
18782 	}
18783 
18784 	return CType._inRange(num, 'cjk', ilib.data.ctype) ||
18785 		CType._inRange(num, 'cjkradicals', ilib.data.ctype) ||
18786 		CType._inRange(num, 'enclosedcjk', ilib.data.ctype) ||
18787 		CType._inRange(num, 'cjkpunct', ilib.data.ctype) ||
18788 		CType._inRange(num, 'cjkcompatibility', ilib.data.ctype);
18789 };
18790 
18791 /**
18792  * @protected
18793  * @param {boolean} sync
18794  * @param {Object|undefined} loadParams
18795  * @param {function(*)|undefined} onLoad
18796  */
18797 isIdeo._init = function (sync, loadParams, onLoad) {
18798 	CType._init(sync, loadParams, onLoad);
18799 };
18800 
18801 
18802 /*< isLower.js */
18803 /*
18804  * isLower.js - Character type is lower case letter
18805  * 
18806  * Copyright © 2012-2015, JEDLSoft
18807  *
18808  * Licensed under the Apache License, Version 2.0 (the "License");
18809  * you may not use this file except in compliance with the License.
18810  * You may obtain a copy of the License at
18811  *
18812  *     http://www.apache.org/licenses/LICENSE-2.0
18813  *
18814  * Unless required by applicable law or agreed to in writing, software
18815  * distributed under the License is distributed on an "AS IS" BASIS,
18816  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18817  *
18818  * See the License for the specific language governing permissions and
18819  * limitations under the License.
18820  */
18821 
18822 // !depends CType.js IString.js
18823 
18824 // !data ctype_l
18825 
18826 
18827 
18828 /**
18829  * Return whether or not the first character is lower-case. For alphabetic
18830  * characters in scripts that do not make a distinction between upper- and 
18831  * lower-case, this function always returns true.<p>
18832  * 
18833  * @static
18834  * @param {string|IString|number} ch character or code point to examine
18835  * @return {boolean} true if the first character is lower-case.
18836  */
18837 var isLower = function (ch) {
18838 	var num;
18839 	switch (typeof(ch)) {
18840 		case 'number':
18841 			num = ch;
18842 			break;
18843 		case 'string':
18844 			num = IString.toCodePoint(ch, 0);
18845 			break;
18846 		case 'undefined':
18847 			return false;
18848 		default:
18849 			num = ch._toCodePoint(0);
18850 			break;
18851 	}
18852 
18853 	return CType._inRange(num, 'Ll', ilib.data.ctype_l);
18854 };
18855 
18856 /**
18857  * @protected
18858  * @param {boolean} sync
18859  * @param {Object|undefined} loadParams
18860  * @param {function(*)|undefined} onLoad
18861  */
18862 isLower._init = function (sync, loadParams, onLoad) {
18863 	CType._load("ctype_l", sync, loadParams, onLoad);
18864 };
18865 
18866 
18867 /*< isPrint.js */
18868 /*
18869  * isPrint.js - Character type is printable char
18870  * 
18871  * Copyright © 2012-2015, JEDLSoft
18872  *
18873  * Licensed under the Apache License, Version 2.0 (the "License");
18874  * you may not use this file except in compliance with the License.
18875  * You may obtain a copy of the License at
18876  *
18877  *     http://www.apache.org/licenses/LICENSE-2.0
18878  *
18879  * Unless required by applicable law or agreed to in writing, software
18880  * distributed under the License is distributed on an "AS IS" BASIS,
18881  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18882  *
18883  * See the License for the specific language governing permissions and
18884  * limitations under the License.
18885  */
18886 
18887 // !depends CType.js isCntrl.js
18888 
18889 
18890 /**
18891  * Return whether or not the first character is any printable character,
18892  * including space.<p>
18893  * 
18894  * @static
18895  * @param {string|IString|number} ch character or code point to examine
18896  * @return {boolean} true if the first character is printable.
18897  */
18898 var isPrint = function (ch) {
18899 	return typeof(ch) !== 'undefined' && ch.length > 0 && !isCntrl(ch);
18900 };
18901 
18902 /**
18903  * @protected
18904  * @param {boolean} sync
18905  * @param {Object|undefined} loadParams
18906  * @param {function(*)|undefined} onLoad
18907  */
18908 isPrint._init = function (sync, loadParams, onLoad) {
18909 	isCntrl._init(sync, loadParams, onLoad);
18910 };
18911 
18912 
18913 /*< isPunct.js */
18914 /*
18915  * isPunct.js - Character type is punctuation
18916  * 
18917  * Copyright © 2012-2015, JEDLSoft
18918  *
18919  * Licensed under the Apache License, Version 2.0 (the "License");
18920  * you may not use this file except in compliance with the License.
18921  * You may obtain a copy of the License at
18922  *
18923  *     http://www.apache.org/licenses/LICENSE-2.0
18924  *
18925  * Unless required by applicable law or agreed to in writing, software
18926  * distributed under the License is distributed on an "AS IS" BASIS,
18927  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18928  *
18929  * See the License for the specific language governing permissions and
18930  * limitations under the License.
18931  */
18932 
18933 // !depends CType.js IString.js
18934 
18935 // !data ctype_p
18936 
18937 
18938 
18939 /**
18940  * Return whether or not the first character is punctuation.<p>
18941  * 
18942  * @static
18943  * @param {string|IString|number} ch character or code point to examine
18944  * @return {boolean} true if the first character is punctuation.
18945  */
18946 var isPunct = function (ch) {
18947 	var num;
18948 	switch (typeof(ch)) {
18949 		case 'number':
18950 			num = ch;
18951 			break;
18952 		case 'string':
18953 			num = IString.toCodePoint(ch, 0);
18954 			break;
18955 		case 'undefined':
18956 			return false;
18957 		default:
18958 			num = ch._toCodePoint(0);
18959 			break;
18960 	}
18961 
18962 	return CType._inRange(num, 'Pd', ilib.data.ctype_p) ||
18963 		CType._inRange(num, 'Ps', ilib.data.ctype_p) ||
18964 		CType._inRange(num, 'Pe', ilib.data.ctype_p) ||
18965 		CType._inRange(num, 'Pc', ilib.data.ctype_p) ||
18966 		CType._inRange(num, 'Po', ilib.data.ctype_p) ||
18967 		CType._inRange(num, 'Pi', ilib.data.ctype_p) ||
18968 		CType._inRange(num, 'Pf', ilib.data.ctype_p);
18969 };
18970 
18971 /**
18972  * @protected
18973  * @param {boolean} sync
18974  * @param {Object|undefined} loadParams
18975  * @param {function(*)|undefined} onLoad
18976  */
18977 isPunct._init = function (sync, loadParams, onLoad) {
18978 	CType._load("ctype_p", sync, loadParams, onLoad);
18979 };
18980 
18981 
18982 
18983 /*< isUpper.js */
18984 /*
18985  * isUpper.js - Character type is upper-case letter
18986  * 
18987  * Copyright © 2012-2015, JEDLSoft
18988  *
18989  * Licensed under the Apache License, Version 2.0 (the "License");
18990  * you may not use this file except in compliance with the License.
18991  * You may obtain a copy of the License at
18992  *
18993  *     http://www.apache.org/licenses/LICENSE-2.0
18994  *
18995  * Unless required by applicable law or agreed to in writing, software
18996  * distributed under the License is distributed on an "AS IS" BASIS,
18997  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18998  *
18999  * See the License for the specific language governing permissions and
19000  * limitations under the License.
19001  */
19002 
19003 // !depends CType.js IString.js
19004 
19005 // !data ctype_l
19006 
19007 
19008 
19009 /**
19010  * Return whether or not the first character is upper-case. For alphabetic
19011  * characters in scripts that do not make a distinction between upper- and 
19012  * lower-case, this function always returns true.<p>
19013  * 
19014  * @static
19015  * @param {string|IString|number} ch character or code point to examine
19016  * @return {boolean} true if the first character is upper-case.
19017  */
19018 var isUpper = function (ch) {
19019 	var num;
19020 	switch (typeof(ch)) {
19021 		case 'number':
19022 			num = ch;
19023 			break;
19024 		case 'string':
19025 			num = IString.toCodePoint(ch, 0);
19026 			break;
19027 		case 'undefined':
19028 			return false;
19029 		default:
19030 			num = ch._toCodePoint(0);
19031 			break;
19032 	}
19033 
19034 	return CType._inRange(num, 'Lu', ilib.data.ctype_l);
19035 };
19036 
19037 /**
19038  * @protected
19039  * @param {boolean} sync
19040  * @param {Object|undefined} loadParams
19041  * @param {function(*)|undefined} onLoad
19042  */
19043 isUpper._init = function (sync, loadParams, onLoad) {
19044 	CType._load("ctype_l", sync, loadParams, onLoad);
19045 };
19046 
19047 
19048 /*< isXdigit.js */
19049 /*
19050  * isXdigit.js - Character type is hex digit
19051  * 
19052  * Copyright © 2012-2015, JEDLSoft
19053  *
19054  * Licensed under the Apache License, Version 2.0 (the "License");
19055  * you may not use this file except in compliance with the License.
19056  * You may obtain a copy of the License at
19057  *
19058  *     http://www.apache.org/licenses/LICENSE-2.0
19059  *
19060  * Unless required by applicable law or agreed to in writing, software
19061  * distributed under the License is distributed on an "AS IS" BASIS,
19062  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19063  *
19064  * See the License for the specific language governing permissions and
19065  * limitations under the License.
19066  */
19067 
19068 // !depends CType.js IString.js
19069 
19070 // !data ctype
19071 
19072 
19073 
19074 /**
19075  * Return whether or not the first character is a hexadecimal digit written
19076  * in the Latin script. (0-9 or A-F)<p>
19077  * 
19078  * @static
19079  * @param {string|IString|number} ch character or code point to examine
19080  * @return {boolean} true if the first character is a hexadecimal digit written
19081  * in the Latin script.
19082  */
19083 var isXdigit = function (ch) {
19084 	var num;
19085 	switch (typeof(ch)) {
19086 		case 'number':
19087 			num = ch;
19088 			break;
19089 		case 'string':
19090 			num = IString.toCodePoint(ch, 0);
19091 			break;
19092 		case 'undefined':
19093 			return false;
19094 		default:
19095 			num = ch._toCodePoint(0);
19096 			break;
19097 	}
19098 
19099 	return CType._inRange(num, 'xdigit', ilib.data.ctype);
19100 };
19101 
19102 /**
19103  * @protected
19104  * @param {boolean} sync
19105  * @param {Object|undefined} loadParams
19106  * @param {function(*)|undefined} onLoad
19107  */
19108 isXdigit._init = function (sync, loadParams, onLoad) {
19109 	CType._init(sync, loadParams, onLoad);
19110 };
19111 
19112 
19113 /*< isScript.js */
19114 /*
19115  * isScript.js - Character type is script
19116  * 
19117  * Copyright © 2012-2015, JEDLSoft
19118  *
19119  * Licensed under the Apache License, Version 2.0 (the "License");
19120  * you may not use this file except in compliance with the License.
19121  * You may obtain a copy of the License at
19122  *
19123  *     http://www.apache.org/licenses/LICENSE-2.0
19124  *
19125  * Unless required by applicable law or agreed to in writing, software
19126  * distributed under the License is distributed on an "AS IS" BASIS,
19127  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19128  *
19129  * See the License for the specific language governing permissions and
19130  * limitations under the License.
19131  */
19132 
19133 // !depends CType.js IString.js
19134 
19135 // !data scriptToRange
19136 
19137 
19138 
19139 /**
19140  * Return whether or not the first character in the given string is 
19141  * in the given script. The script is given as the 4-letter ISO
19142  * 15924 script code.<p>
19143  * 
19144  * @static
19145  * @param {string|IString|number} ch character or code point to examine
19146  * @param {string} script the 4-letter ISO 15924 to query against
19147  * @return {boolean} true if the first character is in the given script, and
19148  * false otherwise
19149  */
19150 var isScript = function (ch, script) {
19151 	var num;
19152 	switch (typeof(ch)) {
19153 		case 'number':
19154 			num = ch;
19155 			break;
19156 		case 'string':
19157 			num = IString.toCodePoint(ch, 0);
19158 			break;
19159 		case 'undefined':
19160 			return false;
19161 		default:
19162 			num = ch._toCodePoint(0);
19163 			break;
19164 	}
19165 
19166 	return CType._inRange(num, script, ilib.data.scriptToRange);
19167 };
19168 
19169 /**
19170  * @protected
19171  * @param {boolean} sync
19172  * @param {Object|undefined} loadParams
19173  * @param {function(*)|undefined} onLoad
19174  */
19175 isScript._init = function (sync, loadParams, onLoad) {
19176 	CType._load("scriptToRange", sync, loadParams, onLoad);
19177 };
19178 
19179 
19180 /*< ScriptInfo.js */
19181 /*
19182  * ScriptInfo.js - information about scripts
19183  * 
19184  * Copyright © 2012-2015, JEDLSoft
19185  *
19186  * Licensed under the Apache License, Version 2.0 (the "License");
19187  * you may not use this file except in compliance with the License.
19188  * You may obtain a copy of the License at
19189  *
19190  *     http://www.apache.org/licenses/LICENSE-2.0
19191  *
19192  * Unless required by applicable law or agreed to in writing, software
19193  * distributed under the License is distributed on an "AS IS" BASIS,
19194  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19195  *
19196  * See the License for the specific language governing permissions and
19197  * limitations under the License.
19198  */
19199 
19200 // !depends ilib.js Utils.js
19201 
19202 // !data scripts
19203 
19204 
19205 /**
19206  * @class
19207  * Create a new script info instance. This class encodes information about
19208  * scripts, which are sets of characters used in a writing system.<p>
19209  * 
19210  * The options object may contain any of the following properties:
19211  * 
19212  * <ul>
19213  * <li><i>onLoad</i> - a callback function to call when the script info object is fully 
19214  * loaded. When the onLoad option is given, the script info object will attempt to
19215  * load any missing locale data using the ilib loader callback.
19216  * When the constructor is done (even if the data is already preassembled), the 
19217  * onLoad function is called with the current instance as a parameter, so this
19218  * callback can be used with preassembled or dynamic loading or a mix of the two.
19219  * 
19220  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
19221  * asynchronously. If this option is given as "false", then the "onLoad"
19222  * callback must be given, as the instance returned from this constructor will
19223  * not be usable for a while. 
19224  *
19225  * <li><i>loadParams</i> - an object containing parameters to pass to the 
19226  * loader callback function when locale data is missing. The parameters are not
19227  * interpretted or modified in any way. They are simply passed along. The object 
19228  * may contain any property/value pairs as long as the calling code is in
19229  * agreement with the loader callback function as to what those parameters mean.
19230  * </ul>
19231  * 
19232  * 
19233  * @constructor
19234  * @param {string} script The ISO 15924 4-letter identifier for the script
19235  * @param {Object} options parameters to initialize this matcher 
19236  */
19237 var ScriptInfo = function(script, options) {
19238 	var sync = true,
19239 	    loadParams = undefined;
19240 	
19241 	this.script = script;
19242 	
19243 	if (options) {
19244 		if (typeof(options.sync) !== 'undefined') {
19245 			sync = (options.sync == true);
19246 		}
19247 		
19248 		if (typeof(options.loadParams) !== 'undefined') {
19249 			loadParams = options.loadParams;
19250 		}
19251 	}
19252 
19253 	if (!ScriptInfo.cache) {
19254 		ScriptInfo.cache = {};
19255 	}
19256 
19257 	if (!ilib.data.scripts) {
19258 		Utils.loadData({
19259 			object: ScriptInfo, 
19260 			locale: "-", 
19261 			name: "scripts.json", 
19262 			sync: sync, 
19263 			loadParams: loadParams, 
19264 			callback: ilib.bind(this, function (info) {
19265 				if (!info) {
19266 					info = {"Latn":{"nb":215,"nm":"Latin","lid":"Latin","rtl":false,"ime":false,"casing":true}};
19267 					var spec = this.locale.getSpec().replace(/-/g, "_");
19268 					ScriptInfo.cache[spec] = info;
19269 				}
19270 				ilib.data.scripts = info;
19271 				this.info = script && ilib.data.scripts[script];
19272 				if (options && typeof(options.onLoad) === 'function') {
19273 					options.onLoad(this);
19274 				}
19275 			})
19276 		});
19277 	} else {
19278 		this.info = ilib.data.scripts[script];
19279 	}
19280 
19281 };
19282 
19283 /**
19284  * @private
19285  */
19286 ScriptInfo._getScriptsArray = function() {
19287 	var ret = [],
19288 		script = undefined,
19289 		scripts = ilib.data.scripts;
19290 
19291 	for (script in scripts) {
19292 		if (script && scripts[script]) {
19293 			ret.push(script);
19294 		}
19295 	}
19296 	
19297 	return ret;
19298 };
19299 
19300 /**
19301  * Return an array of all ISO 15924 4-letter identifier script identifiers that
19302  * this copy of ilib knows about.
19303  * @static
19304  * @param {boolean} sync whether to find the available ids synchronously (true) or asynchronously (false)
19305  * @param {Object} loadParams arbitrary object full of properties to pass to the loader
19306  * @param {function(Array.<string>)} onLoad callback function to call when the data is finished loading
19307  * @return {Array.<string>} an array of all script identifiers that this copy of
19308  * ilib knows about
19309  */
19310 ScriptInfo.getAllScripts = function(sync, loadParams, onLoad) {
19311 	if (!ilib.data.scripts) {
19312 		Utils.loadData({
19313 			object: ScriptInfo, 
19314 			locale: "-", 
19315 			name: "scripts.json", 
19316 			sync: sync, 
19317 			loadParams: loadParams, 
19318 			callback: ilib.bind(this, function (info) {
19319 				ilib.data.scripts = info;
19320 				
19321 				if (typeof(onLoad) === 'function') {
19322 					onLoad(ScriptInfo._getScriptsArray());
19323 				}
19324 			})
19325 		});
19326 	}
19327 	
19328 	return ScriptInfo._getScriptsArray();
19329 };
19330 
19331 ScriptInfo.prototype = {
19332 	/**
19333 	 * Return the 4-letter ISO 15924 identifier associated
19334 	 * with this script.
19335 	 * @return {string} the 4-letter ISO code for this script
19336 	 */
19337 	getCode: function () {
19338 		return this.info && this.script;
19339 	},
19340 	
19341 	/**
19342 	 * Get the ISO 15924 code number associated with this
19343 	 * script.
19344 	 * 
19345 	 * @return {number} the ISO 15924 code number
19346 	 */
19347 	getCodeNumber: function () {
19348 		return this.info && this.info.nb || 0;
19349 	},
19350 	
19351 	/**
19352 	 * Get the name of this script in English.
19353 	 * 
19354 	 * @return {string} the name of this script in English
19355 	 */
19356 	getName: function () {
19357 		return this.info && this.info.nm;
19358 	},
19359 	
19360 	/**
19361 	 * Get the long identifier assciated with this script.
19362 	 * 
19363 	 * @return {string} the long identifier of this script
19364 	 */
19365 	getLongCode: function () {
19366 		return this.info && this.info.lid;
19367 	},
19368 	
19369 	/**
19370 	 * Return the usual direction that text in this script is written
19371 	 * in. Possible return values are "rtl" for right-to-left,
19372 	 * "ltr" for left-to-right, and "ttb" for top-to-bottom.
19373 	 * 
19374 	 * @return {string} the usual direction that text in this script is
19375 	 * written in
19376 	 */
19377 	getScriptDirection: function() {
19378 		return (this.info && typeof(this.info.rtl) !== 'undefined' && this.info.rtl) ? "rtl" : "ltr";
19379 	},
19380 	
19381 	/**
19382 	 * Return true if this script typically requires an input method engine
19383 	 * to enter its characters.
19384 	 * 
19385 	 * @return {boolean} true if this script typically requires an IME
19386 	 */
19387 	getNeedsIME: function () {
19388 		return this.info && this.info.ime ? true : false; // converts undefined to false
19389 	},
19390 	
19391 	/**
19392 	 * Return true if this script uses lower- and upper-case characters.
19393 	 * 
19394 	 * @return {boolean} true if this script uses letter case
19395 	 */
19396 	getCasing: function () {
19397 		return this.info && this.info.casing ? true : false; // converts undefined to false
19398 	}
19399 };
19400 
19401 
19402 /*< Name.js */
19403 /*
19404  * Name.js - Person name parser
19405  *
19406  * Copyright © 2013-2015, JEDLSoft
19407  *
19408  * Licensed under the Apache License, Version 2.0 (the "License");
19409  * you may not use this file except in compliance with the License.
19410  * You may obtain a copy of the License at
19411  *
19412  *     http://www.apache.org/licenses/LICENSE-2.0
19413  *
19414  * Unless required by applicable law or agreed to in writing, software
19415  * distributed under the License is distributed on an "AS IS" BASIS,
19416  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19417  *
19418  * See the License for the specific language governing permissions and
19419  * limitations under the License.
19420  */
19421 
19422 /* !depends 
19423 ilib.js 
19424 Locale.js
19425 Utils.js 
19426 isAlpha.js 
19427 isIdeo.js 
19428 isPunct.js 
19429 isSpace.js
19430 JSUtils.js 
19431 IString.js
19432 */
19433 
19434 // !data name
19435 
19436 // notes:
19437 // icelandic given names: http://en.wiktionary.org/wiki/Appendix:Icelandic_given_names
19438 // danish approved given names: http://www.familiestyrelsen.dk/samliv/navne/
19439 // http://www.mentalfloss.com/blogs/archives/59277
19440 // other countries with first name restrictions: Norway, China, New Zealand, Japan, Sweden, Germany, Hungary
19441 
19442 
19443 
19444 /**
19445  * @class
19446  * A class to parse names of people. Different locales have different conventions when it
19447  * comes to naming people.<p>
19448  *
19449  * The options can contain any of the following properties:
19450  *
19451  * <ul>
19452  * <li><i>locale</i> - use the rules and conventions of the given locale in order to parse
19453  * the name
19454  * <li><i>style</i> - explicitly use the named style to parse the name. Valid values so
19455  * far are "western" and "asian". If this property is not specified, then the style will
19456  * be gleaned from the name itself. This class will count the total number of Latin or Asian
19457  * characters. If the majority of the characters are in one style, that style will be
19458  * used to parse the whole name.
19459  * <li><i>order</i> - explicitly use the given order for names. In some locales, such
19460  * as Russian, names may be written equally validly as "givenName familyName" or "familyName
19461  * givenName". This option tells the parser which order to prefer, and overrides the
19462  * default order for the locale. Valid values are "gf" (given-family) or "fg" (family-given).
19463  * <li><i>useSpaces</i> - explicitly specifies whether to use spaces or not between the given name , middle name
19464  * and family name.
19465  * <li>onLoad - a callback function to call when the name info is fully
19466  * loaded and the name has been parsed. When the onLoad option is given, the name object
19467  * will attempt to load any missing locale data using the ilib loader callback.
19468  * When the constructor is done (even if the data is already preassembled), the
19469  * onLoad function is called with the current instance as a parameter, so this
19470  * callback can be used with preassembled or dynamic loading or a mix of the two.
19471  *
19472  * <li>sync - tell whether to load any missing locale data synchronously or
19473  * asynchronously. If this option is given as "false", then the "onLoad"
19474  * callback must be given, as the instance returned from this constructor will
19475  * not be usable for a while.
19476  *
19477  * <li><i>loadParams</i> - an object containing parameters to pass to the
19478  * loader callback function when locale data is missing. The parameters are not
19479  * interpretted or modified in any way. They are simply passed along. The object
19480  * may contain any property/value pairs as long as the calling code is in
19481  * agreement with the loader callback function as to what those parameters mean.
19482  * </ul>
19483  *
19484  * When the parser has completed its parsing, it fills in the fields listed below.<p>
19485  *
19486  * For names that include auxilliary words, such as the family name "van der Heijden", all
19487  * of the auxilliary words ("van der") will be included in the field.<p>
19488  *
19489  * For names in Spanish locales, it is assumed that the family name is doubled. That is,
19490  * a person may have a paternal family name followed by a maternal family name. All
19491  * family names will be listed in the familyName field as normal, separated by spaces.
19492  * When formatting the short version of such names, only the paternal family name will
19493  * be used.
19494  *
19495  *
19496  * @constructor
19497  * @param {string|Name=} name the name to parse
19498  * @param {Object=} options Options governing the construction of this name instance
19499  */
19500 var Name = function (name, options) {
19501     var sync = true;
19502 
19503     if (!name || name.length === 0) {
19504     	return;
19505     }
19506 
19507     this.loadParams = {};
19508 
19509     if (options) {
19510         if (options.locale) {
19511             this.locale = (typeof (options.locale) === 'string') ? new Locale(options.locale) : options.locale;
19512         }
19513 
19514         if (options.style && (options.style === "asian" || options.style === "western")) {
19515             this.style = options.style;
19516         }
19517 
19518         if (options.order && (options.order === "gmf" || options.order === "fmg" || options.order === "fgm")) {
19519             this.order = options.order;
19520         }
19521 
19522         if (typeof (options.sync) !== 'undefined') {
19523             sync = (options.sync == true);
19524         }
19525 
19526         if (typeof (options.loadParams) !== 'undefined') {
19527             this.loadParams = options.loadParams;
19528         }
19529     }
19530 
19531     if (!Name.cache) {
19532         Name.cache = {};
19533     }
19534 
19535 	this.locale = this.locale || new Locale();
19536 	
19537 	isAlpha._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
19538 		isIdeo._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
19539 			isPunct._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
19540 				isSpace._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
19541 					Utils.loadData({
19542 						object: Name, 
19543 						locale: this.locale, 
19544 						name: "name.json", 
19545 						sync: sync, 
19546 						loadParams: this.loadParams, 
19547 						callback: ilib.bind(this, function (info) {
19548 							if (!info) {
19549 								info = Name.defaultInfo;
19550 								var spec = this.locale.getSpec().replace(/-/g, "_");
19551 								Name.cache[spec] = info;
19552 							}
19553                             if (typeof (name) === 'object') {
19554     							// copy constructor
19555 							    /**
19556 							     * The prefixes for this name
19557 							     * @type {string|Array.<string>}
19558 							     */
19559 							    this.prefix = name.prefix;
19560 							    /**
19561 							     * The given (personal) name in this name.
19562 							     * @type {string|Array.<string>}
19563 							     */
19564 							    this.givenName = name.givenName;
19565 							    /**
19566 							     * The middle names used in this name. If there are multiple middle names, they all
19567 							     * appear in this field separated by spaces.
19568 							     * @type {string|Array.<string>}
19569 							     */
19570 							    this.middleName = name.middleName;
19571 							    /**
19572 							     * The family names in this name. If there are multiple family names, they all
19573 							     * appear in this field separated by spaces.
19574 							     * @type {string|Array.<string>}
19575 							     */
19576 							    this.familyName = name.familyName;
19577 							    /**
19578 							     * The suffixes for this name. If there are multiple suffixes, they all
19579 							     * appear in this field separated by spaces.
19580 							     * @type {string|Array.<string>}
19581 							     */
19582 							    this.suffix = name.suffix;
19583 
19584 							    // private properties
19585 							    this.locale = name.locale;
19586 							    this.style = name.style;
19587 							    this.order = name.order;
19588 							    this.useSpaces = name.useSpaces;
19589 							    this.isAsianName = name.isAsianName;
19590 					    	    return;
19591 						    }
19592 							/** 
19593 							 * @type {{
19594 							 *   nameStyle:string,
19595 							 *   order:string,
19596 							 *   prefixes:Array.<string>,
19597 							 *   suffixes:Array.<string>,
19598 							 *   auxillaries:Array.<string>,
19599 							 *   honorifics:Array.<string>,
19600 							 *   knownFamilyNames:Array.<string>,
19601 							 *   noCompoundFamilyNames:boolean,
19602 							 *   sortByHeadWord:boolean
19603 							 * }} */
19604 							this.info = info;
19605 							this._init(name);
19606 							if (options && typeof(options.onLoad) === 'function') {
19607 								options.onLoad(this);
19608 							}
19609 						})
19610 					});					
19611 				}));
19612 			}));
19613 		}));
19614 	}));
19615 };
19616 
19617 Name.defaultInfo = ilib.data.name ||  {
19618 	"components": {
19619 		"short": {
19620 			"g": 1,
19621 			"f": 1
19622 		},
19623 		"medium": {
19624 			"g": 1,
19625 			"m": 1,
19626 			"f": 1
19627 		},
19628 		"long": {
19629 			"p": 1,
19630 			"g": 1,
19631 			"m": 1,
19632 			"f": 1
19633 		},
19634 		"full": {
19635 			"p": 1,
19636 			"g": 1,
19637 			"m": 1,
19638 			"f": 1,
19639 			"s": 1
19640 		}
19641 	},
19642 	"format": "{prefix} {givenName} {middleName} {familyName}{suffix}",
19643 	"sortByHeadWord": false,
19644 	"nameStyle": "western",
19645 	"conjunctions": {
19646 		"and1": "and",
19647 		"and2": "and",
19648 		"or1": "or",
19649 		"or2": "or"
19650 	},
19651 	"auxillaries": {
19652 		"von": 1,
19653 		"von der": 1,
19654 		"von den": 1,
19655 		"van": 1,
19656 		"van der": 1,
19657         "van de": 1,
19658         "van den": 1,
19659         "de": 1,
19660         "di": 1,
19661 	    "de": 1,
19662 		"la": 1,
19663 		"lo": 1,
19664         "des": 1,
19665         "le": 1,
19666         "les": 1,
19667 		"du": 1,
19668         "de la": 1,
19669         "del": 1,
19670         "de los": 1,
19671         "de las": 1
19672 	},
19673 	"prefixes": [
19674 		"doctor",
19675 		"dr",
19676 		"mr",
19677 		"mrs",
19678 		"ms",
19679 		"mister",
19680 		"madame",
19681 		"madamoiselle",
19682 		"miss",
19683 		"monsieur",
19684 		"señor",
19685         "señora",
19686         "señorita"
19687 	],
19688 	"suffixes": [
19689 		",",
19690 		"junior",
19691 		"jr",
19692 		"senior",
19693 		"sr",
19694 		"i",
19695 		"ii",
19696 		"iii",
19697 		"esq",
19698 		"phd",
19699 		"md"
19700 	],
19701     "patronymicName":[ ],
19702     "familyNames":[ ]
19703 };
19704 
19705 /**
19706  * Return true if the given character is in the range of the Han, Hangul, or kana
19707  * scripts.
19708  * @static
19709  * @protected
19710  */
19711 Name._isAsianChar = function(c) {
19712 	return isIdeo(c) ||
19713 		CType.withinRange(c, "hangul") ||
19714 		CType.withinRange(c, "hiragana") ||
19715 		CType.withinRange(c, "katakana");
19716 };
19717 
19718 
19719 /**
19720  * @static
19721  * @protected
19722  */
19723 Name._isAsianName = function (name, language) {
19724     // the idea is to count the number of asian chars and the number
19725     // of latin chars. If one is greater than the other, choose
19726     // that style.
19727     var asian = 0,
19728         latin = 0,
19729         i;
19730 
19731     if (name && name.length > 0) {
19732         for (i = 0; i < name.length; i++) {
19733         	var c = name.charAt(i);
19734 
19735             if (Name._isAsianChar(c)) {
19736                 if (language =="ko" || language =="ja" || language =="zh") {
19737                     return true;
19738                 }
19739                 asian++;
19740             } else if (isAlpha(c)) {
19741                 if (!language =="ko" || !language =="ja" || !language =="zh") {
19742                     return false;
19743                 }
19744                 latin++;
19745             }
19746         }
19747 
19748         return latin < asian;
19749     }
19750 
19751     return false;
19752 };
19753 
19754 /**
19755  * Return true if any Latin letters are found in the string. Return
19756  * false if all the characters are non-Latin.
19757  * @static
19758  * @protected
19759  */
19760 Name._isEuroName = function (name, language) {
19761     var c,
19762         n = new IString(name),
19763         it = n.charIterator();
19764 
19765     while (it.hasNext()) {
19766         c = it.next();
19767 
19768         if (!Name._isAsianChar(c) && !isPunct(c) && !isSpace(c)) {
19769             return true;
19770         } else if (Name._isAsianChar(c) && (language =="ko" || language =="ja" || language =="zh")) {
19771             return false;
19772         }
19773     }
19774     return false;
19775 };
19776 
19777 Name.prototype = {
19778     /**
19779      * @protected
19780      */
19781     _init: function (name) {
19782         var parts, prefixArray, prefix, prefixLower,
19783             suffixArray, suffix, suffixLower,
19784             i, info, hpSuffix;
19785         var currentLanguage = this.locale.getLanguage();
19786 
19787         if (name) {
19788             // for DFISH-12905, pick off the part that the LDAP server automatically adds to our names in HP emails
19789             i = name.search(/\s*[,\/\(\[\{<]/);
19790             if (i !== -1) {
19791                 hpSuffix = name.substring(i);
19792                 hpSuffix = hpSuffix.replace(/\s+/g, ' '); // compress multiple whitespaces
19793                 suffixArray = hpSuffix.split(" ");
19794                 var conjunctionIndex = this._findLastConjunction(suffixArray);
19795                 if (conjunctionIndex > -1) {
19796                     // it's got conjunctions in it, so this is not really a suffix
19797                     hpSuffix = undefined;
19798                 } else {
19799                     name = name.substring(0, i);
19800                 }
19801             }
19802 
19803             this.isAsianName = Name._isAsianName(name, currentLanguage);
19804             if (this.info.nameStyle === "asian" || this.info.order === "fmg" || this.info.order === "fgm") {
19805                 info = this.isAsianName ? this.info : ilib.data.name;
19806             } else {
19807                 info = this.isAsianName ? ilib.data.name : this.info;
19808             }
19809 
19810             if (this.isAsianName) {
19811                 // all-asian names
19812                 if (this.useSpaces == false) {
19813                     name = name.replace(/\s+/g, ''); // eliminate all whitespaces
19814                 }
19815                 parts = name.trim().split('');
19816             }
19817             //} 
19818             else {
19819                 name = name.replace(/, /g, ' , ');
19820                 name = name.replace(/\s+/g, ' '); // compress multiple whitespaces
19821                 parts = name.trim().split(' ');
19822             }
19823 
19824             // check for prefixes
19825             if (parts.length > 1) {
19826                 for (i = parts.length; i > 0; i--) {
19827                     prefixArray = parts.slice(0, i);
19828                     prefix = prefixArray.join(this.isAsianName ? '' : ' ');
19829                     prefixLower = prefix.toLowerCase();
19830                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
19831                     if (ilib.isArray(this.info.prefixes) &&
19832                         (JSUtils.indexOf(this.info.prefixes, prefixLower) > -1 || this._isConjunction(prefixLower))) {
19833                         if (this.prefix) {
19834                             if (!this.isAsianName) {
19835                                 this.prefix += ' ';
19836                             }
19837                             this.prefix += prefix;
19838                         } else {
19839                             this.prefix = prefix;
19840                         }
19841                         parts = parts.slice(i);
19842                         i = parts.length;
19843                     }
19844                 }
19845             }
19846             // check for suffixes
19847             if (parts.length > 1) {
19848                 for (i = parts.length; i > 0; i--) {
19849                     suffixArray = parts.slice(-i);
19850                     suffix = suffixArray.join(this.isAsianName ? '' : ' ');
19851                     suffixLower = suffix.toLowerCase();
19852                     suffixLower = suffixLower.replace(/[\.]/g, ''); // ignore periods
19853                     if (ilib.isArray(this.info.suffixes) && JSUtils.indexOf(this.info.suffixes, suffixLower) > -1) {
19854                         if (this.suffix) {
19855                             if (!this.isAsianName && !isPunct(this.suffix.charAt(0))) {
19856                                 this.suffix = ' ' + this.suffix;
19857                             }
19858                             this.suffix = suffix + this.suffix;
19859                         } else {
19860                             this.suffix = suffix;
19861                         }
19862                         parts = parts.slice(0, parts.length - i);
19863                         i = parts.length;
19864                     }
19865                 }
19866             }
19867 
19868             if (hpSuffix) {
19869                 this.suffix = (this.suffix && this.suffix + hpSuffix) || hpSuffix;
19870             }
19871 
19872             // adjoin auxillary words to their headwords
19873             if (parts.length > 1 && !this.isAsianName) {
19874                 parts = this._joinAuxillaries(parts, this.isAsianName);
19875             }
19876 
19877             if (this.isAsianName) {
19878                 this._parseAsianName(parts, currentLanguage);
19879             } else {
19880                 this._parseWesternName(parts);
19881             }
19882 
19883             this._joinNameArrays();
19884         }
19885     },
19886 
19887     /**
19888 	 * @return {number} 
19889 	 *
19890 	_findSequence: function(parts, hash, isAsian) {
19891 		var sequence, sequenceLower, sequenceArray, aux = [], i, ret = {};
19892 		
19893 		if (parts.length > 0 && hash) {
19894 			//console.info("_findSequence: finding sequences");
19895 			for (var start = 0; start < parts.length-1; start++) {
19896 				for ( i = parts.length; i > start; i-- ) {
19897 					sequenceArray = parts.slice(start, i);
19898 					sequence = sequenceArray.join(isAsian ? '' : ' ');
19899 					sequenceLower = sequence.toLowerCase();
19900 					sequenceLower = sequenceLower.replace(/[,\.]/g, '');  // ignore commas and periods
19901 					
19902 					//console.info("_findSequence: checking sequence: '" + sequenceLower + "'");
19903 					
19904 					if ( sequenceLower in hash ) {
19905 						ret.match = sequenceArray;
19906 						ret.start = start;
19907 						ret.end = i;
19908 						return ret;
19909 						//console.info("_findSequence: Found sequence '" + sequence + "' New parts list is " + JSON.stringify(parts));
19910 					}
19911 				}
19912 			}
19913 		}
19914 	
19915 		return undefined;
19916 	},
19917 	*/
19918 
19919     /**
19920      * @protected
19921      * @param {Array} parts
19922      * @param {Array} names
19923      * @param {boolean} isAsian
19924      * @param {boolean=} noCompoundPrefix
19925      */
19926     _findPrefix: function (parts, names, isAsian, noCompoundPrefix) {
19927         var i, prefix, prefixLower, prefixArray, aux = [];
19928 
19929         if (parts.length > 0 && names) {
19930             for (i = parts.length; i > 0; i--) {
19931                 prefixArray = parts.slice(0, i);
19932                 prefix = prefixArray.join(isAsian ? '' : ' ');
19933                 prefixLower = prefix.toLowerCase();
19934                 prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
19935 
19936                 if (prefixLower in names) {
19937                     aux = aux.concat(isAsian ? prefix : prefixArray);
19938                     if (noCompoundPrefix) {
19939                     	// don't need to parse further. Just return it as is.
19940                     	return aux;
19941                     }
19942                     parts = parts.slice(i);
19943                     i = parts.length + 1;
19944                 }
19945             }
19946         }
19947 
19948         return aux;
19949     },
19950 
19951     /**
19952      * @protected
19953      */
19954     _findSuffix: function (parts, names, isAsian) {
19955         var i, j, seq = "";
19956 
19957         for (i = 0; i < names.length; i++) {
19958             if (parts.length >= names[i].length) {
19959                 j = 0;
19960                 while (j < names[i].length && parts[parts.length - j] === names[i][names[i].length - j]) {
19961                     j++;
19962                 }
19963                 if (j >= names[i].length) {
19964                     seq = parts.slice(parts.length - j).join(isAsian ? "" : " ") + (isAsian ? "" : " ") + seq;
19965                     parts = parts.slice(0, parts.length - j);
19966                     i = -1; // restart the search
19967                 }
19968             }
19969         }
19970 
19971         this.suffix = seq;
19972         return parts;
19973     },
19974 
19975     /**
19976      * @protected
19977      * Tell whether or not the given word is a conjunction in this language.
19978      * @param {string} word the word to test
19979      * @return {boolean} true if the word is a conjunction
19980      */
19981     _isConjunction: function _isConjunction(word) {
19982         return (this.info.conjunctions.and1 === word ||
19983             this.info.conjunctions.and2 === word ||
19984             this.info.conjunctions.or1 === word ||
19985             this.info.conjunctions.or2 === word ||
19986             ("&" === word) ||
19987             ("+" === word));
19988     },
19989 
19990     /**
19991      * Find the last instance of 'and' in the name
19992      * @protected
19993      * @param {Array.<string>} parts
19994      * @return {number}
19995      */
19996     _findLastConjunction: function _findLastConjunction(parts) {
19997         var conjunctionIndex = -1,
19998             index, part;
19999 
20000         for (index = 0; index < parts.length; index++) {
20001             part = parts[index];
20002             if (typeof (part) === 'string') {
20003                 part = part.toLowerCase();
20004                 // also recognize English
20005                 if ("and" === part || "or" === part || "&" === part || "+" === part) {
20006                     conjunctionIndex = index;
20007                 }
20008                 if (this._isConjunction(part)) {
20009                     conjunctionIndex = index;
20010                 }
20011             }
20012         }
20013         return conjunctionIndex;
20014     },
20015 
20016     /**
20017      * @protected
20018      * @param {Array.<string>} parts the current array of name parts
20019      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20020      * @return {Array.<string>} the remaining parts after the prefixes have been removed
20021      */
20022     _extractPrefixes: function (parts, isAsian) {
20023         var i = this._findPrefix(parts, this.info.prefixes, isAsian);
20024         if (i > 0) {
20025             this.prefix = parts.slice(0, i).join(isAsian ? "" : " ");
20026             return parts.slice(i);
20027         }
20028         // prefixes not found, so just return the array unmodified
20029         return parts;
20030     },
20031 
20032     /**
20033      * @protected
20034      * @param {Array.<string>} parts the current array of name parts
20035      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20036      * @return {Array.<string>} the remaining parts after the suffices have been removed
20037      */
20038     _extractSuffixes: function (parts, isAsian) {
20039         var i = this._findSuffix(parts, this.info.suffixes, isAsian);
20040         if (i > 0) {
20041             this.suffix = parts.slice(i).join(isAsian ? "" : " ");
20042             return parts.slice(0, i);
20043         }
20044         // suffices not found, so just return the array unmodified
20045         return parts;
20046     },
20047 
20048     /**
20049      * Adjoin auxillary words to their head words.
20050      * @protected
20051      * @param {Array.<string>} parts the current array of name parts
20052      * @param {boolean} isAsian true if the name is being parsed as an Asian name
20053      * @return {Array.<string>} the parts after the auxillary words have been plucked onto their head word
20054      */
20055     _joinAuxillaries: function (parts, isAsian) {
20056         var start, i, prefixArray, prefix, prefixLower;
20057 
20058         if (this.info.auxillaries && (parts.length > 2 || this.prefix)) {
20059             for (start = 0; start < parts.length - 1; start++) {
20060                 for (i = parts.length; i > start; i--) {
20061                     prefixArray = parts.slice(start, i);
20062                     prefix = prefixArray.join(' ');
20063                     prefixLower = prefix.toLowerCase();
20064                     prefixLower = prefixLower.replace(/[,\.]/g, ''); // ignore commas and periods
20065 
20066                     if (prefixLower in this.info.auxillaries) {
20067                         parts.splice(start, i + 1 - start, prefixArray.concat(parts[i]));
20068                         i = start;
20069                     }
20070                 }
20071             }
20072         }
20073 
20074         return parts;
20075     },
20076 
20077     /**
20078      * Recursively join an array or string into a long string.
20079      * @protected
20080      */
20081     _joinArrayOrString: function _joinArrayOrString(part) {
20082         var i;
20083         if (typeof (part) === 'object') {
20084             for (i = 0; i < part.length; i++) {
20085                 part[i] = this._joinArrayOrString(part[i]);
20086             }
20087             var ret = "";
20088             part.forEach(function (segment) {
20089                 if (ret.length > 0 && !isPunct(segment.charAt(0))) {
20090                     ret += ' ';
20091                 }
20092                 ret += segment;
20093             });
20094 
20095             return ret;
20096         }
20097 
20098         return part;
20099     },
20100 
20101     /**
20102      * @protected
20103      */
20104     _joinNameArrays: function _joinNameArrays() {
20105         var prop;
20106         for (prop in this) {
20107 
20108             if (this[prop] !== undefined && typeof (this[prop]) === 'object' && this[prop] instanceof Array) {
20109 
20110                 this[prop] = this._joinArrayOrString(this[prop]);
20111             }
20112         }
20113     },
20114 
20115     /**
20116      * @protected
20117      */
20118     _parseAsianName: function (parts, language) {
20119         var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
20120         var tempFullName = parts.join('');
20121 
20122         if (familyNameArray && familyNameArray.length > 0) {
20123             this.familyName = familyNameArray.join('');
20124             this.givenName = parts.slice(this.familyName.length).join('');
20125             
20126             //Overide parsing rules if spaces are found in korean
20127             if (language === "ko" && tempFullName.search(/\s*[/\s]/) > -1 && !this.suffix) {
20128                 this._parseKoreanName(tempFullName);
20129             }
20130         } else if (this.locale.getLanguage() === "ja") {
20131             this._parseJapaneseName(parts);
20132         } else if (this.suffix || this.prefix) {
20133             this.familyName = parts.join('');
20134         } else {
20135             this.givenName = parts.join('');
20136         }
20137     },
20138 
20139     /**
20140      * @protected
20141      */
20142     _parseKoreanName: function (name) {
20143         var tempName = name;
20144 
20145         var spaceSplit = tempName.split(" ");
20146         var spceCount = spaceSplit.length;
20147         var fistSpaceIndex = tempName.indexOf(" ");
20148         var lastSpaceIndex = tempName.lastIndexOf(" ");
20149 
20150         if (spceCount === 2) {
20151             this.familyName = spaceSplit[0];
20152             this.givenName = tempName.slice(fistSpaceIndex, tempName.length);
20153         } else {
20154             this.familyName = spaceSplit[0];
20155             this.middleName = tempName.slice(fistSpaceIndex, lastSpaceIndex);
20156             this.givenName = tempName.slice(lastSpaceIndex, tempName.length);
20157         }
20158         
20159     },
20160 
20161     /**
20162      * @protected
20163      */
20164     _parseJapaneseName: function (parts) {
20165     	if (this.suffix && this.suffix.length > 1 && this.info.honorifics.indexOf(this.suffix)>-1) {
20166     		if (parts.length === 1) {
20167     			if (CType.withinRange(parts[0], "cjk")) {
20168     				this.familyName = parts[0];
20169     			} else {
20170     				this.givenName = parts[0];
20171     			}
20172     			return;
20173     		} else if (parts.length === 2) {
20174     			this.familyName = parts.slice(0,parts.length).join("")
20175     			return;
20176     		}
20177     	}
20178     	if (parts.length > 1) {
20179     		var fn = "";                                                                    
20180     		for (var i = 0; i < parts.length; i++) {
20181     			if (CType.withinRange(parts[i], "cjk")) {
20182     				fn += parts[i];
20183     			} else if (fn.length > 1 && CType.withinRange(parts[i], "hiragana")) {
20184     				this.familyName = fn;
20185     				this.givenName = parts.slice(i,parts.length).join("");
20186     				return;
20187     			} else {
20188     				break;
20189     			}
20190     		}
20191     	}
20192     	if (parts.length === 1) {
20193     		this.familyName = parts[0];
20194     	} else if (parts.length === 2) {
20195     		this.familyName = parts[0];
20196     		this.givenName = parts[1];
20197     	} else if (parts.length === 3) {
20198     		this.familyName = parts[0];
20199     		this.givenName = parts.slice(1,parts.length).join("");
20200     	} else if (parts.length > 3) {
20201     		this.familyName = parts.slice(0,2).join("")
20202     		this.givenName = parts.slice(2,parts.length).join("");
20203     	}      
20204     },
20205 
20206     /**
20207      * @protected
20208      */
20209     _parseSpanishName: function (parts) {
20210         var conjunctionIndex;
20211 
20212         if (parts.length === 1) {
20213             if (this.prefix || typeof (parts[0]) === 'object') {
20214                 this.familyName = parts[0];
20215             } else {
20216                 this.givenName = parts[0];
20217             }
20218         } else if (parts.length === 2) {
20219             // we do G F
20220             this.givenName = parts[0];
20221             this.familyName = parts[1];
20222         } else if (parts.length === 3) {
20223             conjunctionIndex = this._findLastConjunction(parts);
20224             // if there's an 'and' in the middle spot, put everything in the first name
20225             if (conjunctionIndex === 1) {
20226                 this.givenName = parts;
20227             } else {
20228                 // else, do G F F
20229                 this.givenName = parts[0];
20230                 this.familyName = parts.slice(1);
20231             }
20232         } else if (parts.length > 3) {
20233             //there are at least 4 parts to this name
20234 
20235             conjunctionIndex = this._findLastConjunction(parts);
20236             ////console.log("@@@@@@@@@@@@@@@@"+conjunctionIndex)
20237             if (conjunctionIndex > 0) {
20238                 // if there's a conjunction that's not the first token, put everything up to and 
20239                 // including the token after it into the first name, the last 2 tokens into
20240                 // the family name (if they exist) and everything else in to the middle name
20241                 // 0 1 2 3 4 5
20242                 // G A G
20243                 // G A G F
20244                 // G G A G
20245                 // G A G F F
20246                 // G G A G F
20247                 // G G G A G
20248                 // G A G M F F
20249                 // G G A G F F
20250                 // G G G A G F
20251                 // G G G G A G
20252                 this.givenName = parts.splice(0, conjunctionIndex + 2);
20253                 if (parts.length > 1) {
20254                     this.familyName = parts.splice(parts.length - 2, 2);
20255                     if (parts.length > 0) {
20256                         this.middleName = parts;
20257                     }
20258                 } else if (parts.length === 1) {
20259                     this.familyName = parts[0];
20260                 }
20261             } else {
20262                 this.givenName = parts.splice(0, 1);
20263                 this.familyName = parts.splice(parts.length - 2, 2);
20264                 this.middleName = parts;
20265             }
20266         }
20267     },
20268 
20269     /**
20270      * @protected
20271      */
20272     _parseIndonesianName: function (parts) {
20273         var conjunctionIndex;
20274 
20275         if (parts.length === 1) {
20276             //if (this.prefix || typeof(parts[0]) === 'object') {
20277             //this.familyName = parts[0];
20278             //} else {
20279             this.givenName = parts[0];
20280             //}
20281             //} else if (parts.length === 2) {
20282             // we do G F
20283             //this.givenName = parts[0];
20284             //this.familyName = parts[1];
20285         } else if (parts.length >= 2) {
20286             //there are at least 3 parts to this name
20287 
20288             conjunctionIndex = this._findLastConjunction(parts);
20289             if (conjunctionIndex > 0) {
20290                 // if there's a conjunction that's not the first token, put everything up to and 
20291                 // including the token after it into the first name, the last 2 tokens into
20292                 // the family name (if they exist) and everything else in to the middle name
20293                 // 0 1 2 3 4 5
20294                 // G A G
20295                 // G A G F
20296                 // G G A G
20297                 // G A G F F
20298                 // G G A G F
20299                 // G G G A G
20300                 // G A G M F F
20301                 // G G A G F F
20302                 // G G G A G F
20303                 // G G G G A G
20304                 this.givenName = parts.splice(0, conjunctionIndex + 2);
20305                 if (parts.length > 1) {
20306                     //this.familyName = parts.splice(parts.length-2, 2);
20307                     //if ( parts.length > 0 ) {
20308                     this.middleName = parts;
20309                 }
20310                 //} else if (parts.length === 1) {
20311                 //	this.familyName = parts[0];
20312                 //}
20313             } else {
20314                 this.givenName = parts.splice(0, 1);
20315                 //this.familyName = parts.splice(parts.length-2, 2);
20316                 this.middleName = parts;
20317             }
20318         }
20319     },
20320     
20321     /**
20322      * @protected
20323      */
20324     _parseGenericWesternName: function (parts) {
20325         /* Western names are parsed as follows, and rules are applied in this 
20326          * order:
20327          *
20328          * G
20329          * G F
20330          * G M F
20331          * G M M F
20332          * P F
20333          * P G F
20334          */
20335         var conjunctionIndex;
20336 
20337         if (parts.length === 1) {
20338             if (this.prefix || typeof (parts[0]) === 'object') {
20339                 // already has a prefix, so assume it goes with the family name like "Dr. Roberts" or
20340                 // it is a name with auxillaries, which is almost always a family name
20341                 this.familyName = parts[0];
20342             } else {
20343                 this.givenName = parts[0];
20344             }
20345         } else if (parts.length === 2) {
20346             // we do G F
20347             if (this.info.order == 'fgm') {
20348                 this.givenName = parts[1];
20349                 this.familyName = parts[0];
20350             } else if (this.info.order == "gmf" || typeof (this.info.order) == 'undefined') {
20351                 this.givenName = parts[0];
20352                 this.familyName = parts[1];
20353             }
20354         } else if (parts.length >= 3) {
20355             //find the first instance of 'and' in the name
20356             conjunctionIndex = this._findLastConjunction(parts);
20357 
20358             if (conjunctionIndex > 0) {
20359                 // if there's a conjunction that's not the first token, put everything up to and 
20360                 // including the token after it into the first name, the last token into
20361                 // the family name (if it exists) and everything else in to the middle name
20362                 // 0 1 2 3 4 5
20363                 // G A G M M F
20364                 // G G A G M F
20365                 // G G G A G F
20366                 // G G G G A G
20367                 //if(this.order == "gmf") {
20368                 this.givenName = parts.slice(0, conjunctionIndex + 2);
20369 
20370                 if (conjunctionIndex + 1 < parts.length - 1) {
20371                     this.familyName = parts.splice(parts.length - 1, 1);
20372                     ////console.log(this.familyName);
20373                     if (conjunctionIndex + 2 < parts.length - 1) {
20374                         this.middleName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
20375                     }
20376                 } else if (this.order == "fgm") {
20377                     this.familyName = parts.slice(0, conjunctionIndex + 2);
20378                     if (conjunctionIndex + 1 < parts.length - 1) {
20379                         this.middleName = parts.splice(parts.length - 1, 1);
20380                         if (conjunctionIndex + 2 < parts.length - 1) {
20381                             this.givenName = parts.slice(conjunctionIndex + 2, parts.length - conjunctionIndex - 3);
20382                         }
20383                     }
20384                 }
20385             } else {
20386                 this.givenName = parts[0];
20387 
20388                 this.middleName = parts.slice(1, parts.length - 1);
20389 
20390                 this.familyName = parts[parts.length - 1];
20391             }
20392         }
20393     },
20394     
20395      /**
20396      * parse patrinomic name from the russian names 
20397      * @protected
20398      * @param {Array.<string>} parts the current array of name parts
20399      * @return number  index of the part which contains patronymic name
20400      */
20401     _findPatronymicName: function(parts) {
20402     	var index, part;
20403     	for (index = 0; index < parts.length; index++) {
20404     		part = parts[index];
20405     		if (typeof (part) === 'string') {
20406     			part = part.toLowerCase();
20407 
20408     			var subLength = this.info.patronymicName.length;
20409     			while(subLength--) {
20410     				if(part.indexOf(this.info.patronymicName[subLength])!== -1 )
20411     					return index;
20412     			}
20413     		}
20414     	}
20415     	return -1;
20416     },
20417 
20418     /**
20419 	 * find if the given part is patronymic name
20420 	 * 
20421 	 * @protected
20422 	 * @param {string} part string from name parts @
20423 	 * @return number index of the part which contains familyName
20424 	 */
20425     _isPatronymicName: function(part) {
20426 	    var pName;
20427 	    if ( typeof (part) === 'string') {
20428 		    pName = part.toLowerCase();
20429 
20430 		    var subLength = this.info.patronymicName.length;
20431 		    while (subLength--) {
20432 			    if (pName.indexOf(this.info.patronymicName[subLength]) !== -1)
20433 				    return true;
20434 		    }
20435 	    }
20436 	    return false;
20437     },
20438 
20439     /**
20440 	 * find family name from the russian name
20441 	 * 
20442 	 * @protected
20443 	 * @param {Array.<string>} parts the current array of name parts
20444 	 * @return boolean true if patronymic, false otherwise
20445 	 */
20446     _findFamilyName: function(parts) {
20447 	    var index, part, substring;
20448 	    for (index = 0; index < parts.length; index++) {
20449 		    part = parts[index];
20450 
20451 		    if ( typeof (part) === 'string') {
20452 			    part = part.toLowerCase();
20453 			    var length = part.length - 1;
20454 
20455 			    if (this.info.familyName.indexOf(part) !== -1) {
20456 				    return index;
20457 			    } else if (part[length] === 'в' || part[length] === 'н' ||
20458 			        part[length] === 'й') {
20459 				    substring = part.slice(0, -1);
20460 				    if (this.info.familyName.indexOf(substring) !== -1) {
20461 					    return index;
20462 				    }
20463 			    } else if ((part[length - 1] === 'в' && part[length] === 'а') ||
20464 			        (part[length - 1] === 'н' && part[length] === 'а') ||
20465 			        (part[length - 1] === 'а' && part[length] === 'я')) {
20466 				    substring = part.slice(0, -2);
20467 				    if (this.info.familyName.indexOf(substring) !== -1) {
20468 					    return index;
20469 				    }
20470 			    }
20471 		    }
20472 	    }
20473 	    return -1;
20474     },
20475 
20476     /**
20477 	 * parse russian name
20478 	 * 
20479 	 * @protected
20480 	 * @param {Array.<string>} parts the current array of name parts
20481 	 * @return
20482 	 */
20483     _parseRussianName: function(parts) {
20484 	    var conjunctionIndex, familyIndex = -1;
20485 
20486 	    if (parts.length === 1) {
20487 		    if (this.prefix || typeof (parts[0]) === 'object') {
20488 			    // already has a prefix, so assume it goes with the family name
20489 				// like "Dr. Roberts" or
20490 			    // it is a name with auxillaries, which is almost always a
20491 				// family name
20492 			    this.familyName = parts[0];
20493 		    } else {
20494 			    this.givenName = parts[0];
20495 		    }
20496 	    } else if (parts.length === 2) {
20497 		    // we do G F
20498 		    if (this.info.order === 'fgm') {
20499 			    this.givenName = parts[1];
20500 			    this.familyName = parts[0];
20501 		    } else if (this.info.order === "gmf") {
20502 			    this.givenName = parts[0];
20503 			    this.familyName = parts[1];
20504 		    } else if ( typeof (this.info.order) === 'undefined') {
20505 			    if (this._isPatronymicName(parts[1]) === true) {
20506 				    this.middleName = parts[1];
20507 				    this.givenName = parts[0];
20508 			    } else if ((familyIndex = this._findFamilyName(parts)) !== -1) {
20509 				    if (familyIndex === 1) {
20510 					    this.givenName = parts[0];
20511 					    this.familyName = parts[1];
20512 				    } else {
20513 					    this.familyName = parts[0];
20514 					    this.givenName = parts[1];
20515 				    }
20516 
20517 			    } else {
20518 				    this.givenName = parts[0];
20519 				    this.familyName = parts[1];
20520 			    }
20521 
20522 		    }
20523 	    } else if (parts.length >= 3) {
20524 		    // find the first instance of 'and' in the name
20525 		    conjunctionIndex = this._findLastConjunction(parts);
20526 		    var patronymicNameIndex = this._findPatronymicName(parts);
20527 		    if (conjunctionIndex > 0) {
20528 			    // if there's a conjunction that's not the first token, put
20529 				// everything up to and
20530 			    // including the token after it into the first name, the last
20531 				// token into
20532 			    // the family name (if it exists) and everything else in to the
20533 				// middle name
20534 			    // 0 1 2 3 4 5
20535 			    // G A G M M F
20536 			    // G G A G M F
20537 			    // G G G A G F
20538 			    // G G G G A G
20539 			    // if(this.order == "gmf") {
20540 			    this.givenName = parts.slice(0, conjunctionIndex + 2);
20541 
20542 			    if (conjunctionIndex + 1 < parts.length - 1) {
20543 				    this.familyName = parts.splice(parts.length - 1, 1);
20544 				    // //console.log(this.familyName);
20545 				    if (conjunctionIndex + 2 < parts.length - 1) {
20546 					    this.middleName = parts.slice(conjunctionIndex + 2,
20547 					        parts.length - conjunctionIndex - 3);
20548 				    }
20549 			    } else if (this.order == "fgm") {
20550 				    this.familyName = parts.slice(0, conjunctionIndex + 2);
20551 				    if (conjunctionIndex + 1 < parts.length - 1) {
20552 					    this.middleName = parts.splice(parts.length - 1, 1);
20553 					    if (conjunctionIndex + 2 < parts.length - 1) {
20554 						    this.givenName = parts.slice(conjunctionIndex + 2,
20555 						        parts.length - conjunctionIndex - 3);
20556 					    }
20557 				    }
20558 			    }
20559 		    } else if (patronymicNameIndex !== -1) {
20560 			    this.middleName = parts[patronymicNameIndex];
20561 
20562 			    if (patronymicNameIndex === (parts.length - 1)) {
20563 				    this.familyName = parts[0];
20564 				    this.givenName = parts.slice(1, patronymicNameIndex);
20565 			    } else {
20566 				    this.givenName = parts.slice(0, patronymicNameIndex);
20567 
20568 				    this.familyName = parts[parts.length - 1];
20569 			    }
20570 		    } else {
20571 			    this.givenName = parts[0];
20572 
20573 			    this.middleName = parts.slice(1, parts.length - 1);
20574 
20575 			    this.familyName = parts[parts.length - 1];
20576 		    }
20577 	    }
20578     },
20579     
20580     
20581     /**
20582      * @protected
20583      */
20584     _parseWesternName: function (parts) {
20585 
20586         if (this.locale.getLanguage() === "es" || this.locale.getLanguage() === "pt") {
20587             // in spain and mexico and portugal, we parse names differently than in the rest of the world 
20588             // because of the double family names
20589             this._parseSpanishName(parts);
20590         } else if (this.locale.getLanguage() === "ru") {
20591             /*
20592              * In Russian, names can be given equally validly as given-family
20593              * or family-given. Use the value of the "order" property of the
20594              * constructor options to give the default when the order is ambiguous.
20595              */
20596             this._parseRussianName(parts);
20597         } else if (this.locale.getLanguage() === "id") {
20598             // in indonesia, we parse names differently than in the rest of the world 
20599             // because names don't have family names usually.
20600             this._parseIndonesianName(parts);
20601         } else {
20602         	this._parseGenericWesternName(parts);
20603         }
20604     },
20605 
20606     /**
20607      * When sorting names with auxiliary words (like "van der" or "de los"), determine
20608      * which is the "head word" and return a string that can be easily sorted by head
20609      * word. In English, names are always sorted by initial characters. In places like
20610      * the Netherlands or Germany, family names are sorted by the head word of a list
20611      * of names rather than the first element of that name.
20612      * @return {string|undefined} a string containing the family name[s] to be used for sorting
20613      * in the current locale, or undefined if there is no family name in this object
20614      */
20615     getSortFamilyName: function () {
20616         var name,
20617             auxillaries,
20618             auxString,
20619             parts,
20620             i;
20621 
20622         // no name to sort by
20623         if (!this.familyName) {
20624             return undefined;
20625         }
20626 
20627         // first break the name into parts
20628         if (this.info) {
20629             if (this.info.sortByHeadWord) {
20630                 if (typeof (this.familyName) === 'string') {
20631                     name = this.familyName.replace(/\s+/g, ' '); // compress multiple whitespaces
20632                     parts = name.trim().split(' ');
20633                 } else {
20634                     // already split
20635                     parts = /** @type Array */ this.familyName;
20636                 }
20637 
20638                 auxillaries = this._findPrefix(parts, this.info.auxillaries, false);
20639                 if (auxillaries && auxillaries.length > 0) {
20640                     if (typeof (this.familyName) === 'string') {
20641                         auxString = auxillaries.join(' ');
20642                         name = this.familyName.substring(auxString.length + 1) + ', ' + auxString;
20643                     } else {
20644                         name = parts.slice(auxillaries.length).join(' ') +
20645                             ', ' +
20646                             parts.slice(0, auxillaries.length).join(' ');
20647                     }
20648                 }
20649             } else if (this.info.knownFamilyNames && this.familyName) {
20650                 parts = this.familyName.split('');
20651                 var familyNameArray = this._findPrefix(parts, this.info.knownFamilyNames, true, this.info.noCompoundFamilyNames);
20652                 name = "";
20653                 for (i = 0; i < familyNameArray.length; i++) {
20654                     name += (this.info.knownFamilyNames[familyNameArray[i]] || "");
20655                 }
20656             }
20657         }
20658 
20659         return name || this.familyName;
20660     },
20661 
20662     getHeadFamilyName: function () {},
20663 
20664     /** 
20665      * @protected
20666      * Return a shallow copy of the current instance.
20667      */
20668     clone: function () {
20669         return new Name(this);
20670     }
20671 };
20672 
20673 
20674 /*< NameFmt.js */
20675 /*
20676  * NameFmt.js - Format person names for display
20677  * 
20678  * Copyright © 2013-2015, JEDLSoft
20679  *
20680  * Licensed under the Apache License, Version 2.0 (the "License");
20681  * you may not use this file except in compliance with the License.
20682  * You may obtain a copy of the License at
20683  *
20684  *     http://www.apache.org/licenses/LICENSE-2.0
20685  *
20686  * Unless required by applicable law or agreed to in writing, software
20687  * distributed under the License is distributed on an "AS IS" BASIS,
20688  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20689  *
20690  * See the License for the specific language governing permissions and
20691  * limitations under the License.
20692  */
20693 
20694 /* !depends 
20695 ilib.js
20696 Locale.js
20697 IString.js
20698 Name.js
20699 isPunct.js
20700 Utils.js
20701 */
20702 
20703 // !data name
20704 
20705 
20706 
20707 
20708 /**
20709  * @class
20710  * Creates a formatter that can format person name instances (Name) for display to
20711  * a user. The options may contain the following properties:
20712  * 
20713  * <ul>
20714  * <li><i>locale</i> - Use the conventions of the given locale to construct the name format. 
20715  * <li><i>style</i> - Format the name with the given style. The value of this property
20716  * should be one of the following strings: 
20717  *   <ul>
20718  *     <li><i>short</i> - Format a short name with just the given and family names.
20719  *     <li><i>medium</i> - Format a medium-length name with the given, middle, and family names.
20720  *     <li><i>long</i> - Format a long name with all names available in the given name object, including
20721  *     prefixes.
20722  *     <li><i>full</i> - Format a long name with all names available in the given name object, including
20723  *     prefixes and suffixes.
20724  *   </ul>
20725  * <li><i>components</i> - Format the name with the given components in the correct
20726  * order for those components. Components are encoded as a string of letters representing
20727  * the desired components:
20728  *   <ul>
20729  *     <li><i>p</i> - prefixes
20730  *     <li><i>g</i> - given name
20731  *     <li><i>m</i> - middle names
20732  *     <li><i>f</i> - family name
20733  *     <li><i>s</i> - suffixes
20734  *   </ul>
20735  * <p>
20736  * 
20737  * For example, the string "pf" would mean to only format any prefixes and family names 
20738  * together and leave out all the other parts of the name.<p>
20739  * 
20740  * The components can be listed in any order in the string. The <i>components</i> option 
20741  * overrides the <i>style</i> option if both are specified.
20742  *
20743  * <li>onLoad - a callback function to call when the locale info object is fully 
20744  * loaded. When the onLoad option is given, the localeinfo object will attempt to
20745  * load any missing locale data using the ilib loader callback.
20746  * When the constructor is done (even if the data is already preassembled), the 
20747  * onLoad function is called with the current instance as a parameter, so this
20748  * callback can be used with preassembled or dynamic loading or a mix of the two.
20749  * 
20750  * <li>sync - tell whether to load any missing locale data synchronously or 
20751  * asynchronously. If this option is given as "false", then the "onLoad"
20752  * callback must be given, as the instance returned from this constructor will
20753  * not be usable for a while. 
20754  *
20755  * <li><i>loadParams</i> - an object containing parameters to pass to the 
20756  * loader callback function when locale data is missing. The parameters are not
20757  * interpretted or modified in any way. They are simply passed along. The object 
20758  * may contain any property/value pairs as long as the calling code is in
20759  * agreement with the loader callback function as to what those parameters mean.
20760  * </ul>
20761  * 
20762  * Formatting names is a locale-dependent function, as the order of the components 
20763  * depends on the locale. The following explains some of the details:<p>
20764  * 
20765  * <ul>
20766  * <li>In Western countries, the given name comes first, followed by a space, followed 
20767  * by the family name. In Asian countries, the family name comes first, followed immediately
20768  * by the given name with no space. But, that format is only used with Asian names written
20769  * in ideographic characters. In Asian countries, especially ones where both an Asian and 
20770  * a Western language are used (Hong Kong, Singapore, etc.), the convention is often to 
20771  * follow the language of the name. That is, Asian names are written in Asian style, and 
20772  * Western names are written in Western style. This class follows that convention as
20773  * well. 
20774  * <li>In other Asian countries, Asian names
20775  * written in Latin script are written with Asian ordering. eg. "Xu Ping-an" instead
20776  * of the more Western order "Ping-an Xu", as the order is thought to go with the style
20777  * that is appropriate for the name rather than the style for the language being written.
20778  * <li>In some Spanish speaking countries, people often take both their maternal and
20779  * paternal last names as their own family name. When formatting a short or medium style
20780  * of that family name, only the paternal name is used. In the long style, all the names
20781  * are used. eg. "Juan Julio Raul Lopez Ortiz" took the name "Lopez" from his father and 
20782  * the name "Ortiz" from his mother. His family name would be "Lopez Ortiz". The formatted
20783  * short style of his name would be simply "Juan Lopez" which only uses his paternal
20784  * family name of "Lopez".
20785  * <li>In many Western languages, it is common to use auxillary words in family names. For
20786  * example, the family name of "Ludwig von Beethoven" in German is "von Beethoven", not 
20787  * "Beethoven". This class ensures that the family name is formatted correctly with 
20788  * all auxillary words.   
20789  * </ul>
20790  * 
20791  * 
20792  * @constructor
20793  * @param {Object} options A set of options that govern how the formatter will behave
20794  */
20795 var NameFmt = function(options) {
20796 	var sync = true;
20797 	
20798 	this.style = "short";
20799 	this.loadParams = {};
20800 	
20801 	if (options) {
20802 		if (options.locale) {
20803 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
20804 		}
20805 		
20806 		if (options.style) {
20807 			this.style = options.style;
20808 		}
20809 		
20810 		if (options.components) {
20811 			this.components = options.components;
20812 		}
20813 		
20814 		if (typeof(options.sync) !== 'undefined') {
20815 			sync = (options.sync == true);
20816 		}
20817 		
20818 		if (typeof(options.loadParams) !== 'undefined') {
20819 			this.loadParams = options.loadParams;
20820 		}
20821 	}
20822 	
20823 	// set up defaults in case we need them
20824 	this.defaultEuroTemplate = new IString("{prefix} {givenName} {middleName} {familyName}{suffix}");
20825 	this.defaultAsianTemplate = new IString("{prefix}{familyName}{givenName}{middleName}{suffix}");
20826 	this.useFirstFamilyName = false;
20827 
20828 	switch (this.style) {
20829 		default:
20830 		case "s":
20831 		case "short":
20832 			this.style = "short";
20833 			break;
20834 		case "m":
20835 		case "medium":
20836 			this.style = "medium";
20837 			break;
20838 		case "l":
20839 		case "long":
20840 			this.style = "long";
20841 			break;
20842 		case "f":
20843 		case "full":
20844 			this.style = "full";
20845 			break;
20846 	}
20847 
20848 	if (!Name.cache) {
20849 		Name.cache = {};
20850 	}
20851 
20852 	this.locale = this.locale || new Locale();
20853 	
20854 	isPunct._init(sync, this.loadParams, /** @type {function()|undefined} */ ilib.bind(this, function() {
20855 		Utils.loadData({
20856 			object: Name, 
20857 			locale: this.locale, 
20858 			name: "name.json", 
20859 			sync: sync, 
20860 			loadParams: this.loadParams, 
20861 			callback: ilib.bind(this, function (info) {
20862 				if (!info) {
20863 					info = Name.defaultInfo;
20864 					var spec = this.locale.getSpec().replace(/-/g, "_");
20865 					Name.cache[spec] = info;
20866 				}
20867 				this.info = info;
20868 				this._init();
20869 				if (options && typeof(options.onLoad) === 'function') {
20870 					options.onLoad(this);
20871 				}
20872 			})
20873 		});
20874 	}));
20875 };
20876 
20877 NameFmt.prototype = {
20878 	/**                          
20879 	 * @protected
20880 	 */
20881 	_init: function() {
20882 		if (this.components) {
20883 			var valids = {"p":1,"g":1,"m":1,"f":1,"s":1},
20884 				arr = this.components.split("");
20885 			this.comps = {};
20886 			for (var i = 0; i < arr.length; i++) {
20887 				if (valids[arr[i].toLowerCase()]) {
20888 					this.comps[arr[i].toLowerCase()] = true;
20889 				}
20890 			}
20891 		} else {
20892 			this.comps = this.info.components[this.style];
20893 		}
20894 
20895 		this.template = new IString(this.info.format);
20896 		
20897 		if (this.locale.language === "es" && (this.style !== "long" && this.style !== "full")) {
20898 			this.useFirstFamilyName = true;	// in spanish, they have 2 family names, the maternal and paternal
20899 		}
20900 
20901 		this.isAsianLocale = (this.info.nameStyle === "asian");
20902 	},
20903 
20904 	/**
20905 	 * adjoin auxillary words to their head words
20906 	 * @protected
20907 	 */
20908 	_adjoinAuxillaries: function (parts, namePrefix) {
20909 		var start, i, prefixArray, prefix, prefixLower;
20910 		
20911 		//console.info("_adjoinAuxillaries: finding and adjoining aux words in " + parts.join(' '));
20912 		
20913 		if ( this.info.auxillaries && (parts.length > 2 || namePrefix) ) {
20914 			for ( start = 0; start < parts.length-1; start++ ) {
20915 				for ( i = parts.length; i > start; i-- ) {
20916 					prefixArray = parts.slice(start, i);
20917 					prefix = prefixArray.join(' ');
20918 					prefixLower = prefix.toLowerCase();
20919 					prefixLower = prefixLower.replace(/[,\.]/g, '');  // ignore commas and periods
20920 					
20921 					//console.info("_adjoinAuxillaries: checking aux prefix: '" + prefixLower + "' which is " + start + " to " + i);
20922 					
20923 					if ( prefixLower in this.info.auxillaries ) {
20924 						//console.info("Found! Old parts list is " + JSON.stringify(parts));
20925 						parts.splice(start, i+1-start, prefixArray.concat(parts[i]));
20926 						//console.info("_adjoinAuxillaries: Found! New parts list is " + JSON.stringify(parts));
20927 						i = start;
20928 					}
20929 				}
20930 			}
20931 		}
20932 		
20933 		//console.info("_adjoinAuxillaries: done. Result is " + JSON.stringify(parts));
20934 
20935 		return parts;
20936 	},
20937 
20938 	/**
20939 	 * Return the locale for this formatter instance.
20940 	 * @return {Locale} the locale instance for this formatter
20941 	 */
20942 	getLocale: function () {
20943 		return this.locale;
20944 	},
20945 	
20946 	/**
20947 	 * Return the style of names returned by this formatter
20948 	 * @return {string} the style of names returned by this formatter
20949 	 */
20950 	getStyle: function () {
20951 		return this.style;
20952 	},
20953 	
20954 	/**
20955 	 * Return the list of components used to format names in this formatter
20956 	 * @return {string} the list of components
20957 	 */
20958 	getComponents: function () {
20959 		return this.components;
20960 	},
20961 	
20962 	/**
20963 	 * Format the name for display in the current locale with the options set up
20964 	 * in the constructor of this formatter instance.<p>
20965 	 * 
20966 	 * If the name does not contain all the parts required for the style, those parts
20967 	 * will be left blank.<p>
20968 	 * 
20969 	 * There are two basic styles of formatting: European, and Asian. If this formatter object
20970 	 * is set for European style, but an Asian name is passed to the format method, then this
20971 	 * method will format the Asian name with a generic Asian template. Similarly, if the
20972 	 * formatter is set for an Asian style, and a European name is passed to the format method,
20973 	 * the formatter will use a generic European template.<p>
20974 	 * 
20975 	 * This means it is always safe to format any name with a formatter for any locale. You should
20976 	 * always get something at least reasonable as output.<p>
20977 	 * 
20978 	 * @param {Name} name the name to format
20979 	 * @return {string|undefined} the name formatted according to the style of this formatter instance
20980 	 */
20981 	format: function(name) {
20982 		var formatted, temp, modified, isAsianName;
20983 		var currentLanguage = this.locale.getLanguage();
20984 		 
20985 		if (!name || typeof(name) !== 'object') {
20986 			return undefined;
20987 		}
20988 		
20989 		if ((typeof(name.isAsianName) === 'boolean' && !name.isAsianName) ||
20990 				Name._isEuroName([name.givenName, name.middleName, name.familyName].join(""), currentLanguage)) {
20991 			isAsianName = false;	// this is a euro name, even if the locale is asian
20992 			modified = name.clone();
20993 			
20994 			// handle the case where there is no space if there is punctuation in the suffix like ", Phd". 
20995 			// Otherwise, put a space in to transform "PhD" to " PhD"
20996 			/*
20997 			console.log("suffix is " + modified.suffix);
20998 			if ( modified.suffix ) {
20999 				console.log("first char is " + modified.suffix.charAt(0));
21000 				console.log("isPunct(modified.suffix.charAt(0)) is " + isPunct(modified.suffix.charAt(0)));
21001 			}
21002 			*/
21003 			if (modified.suffix && isPunct(modified.suffix.charAt(0)) === false) {
21004 				modified.suffix = ' ' + modified.suffix; 
21005 			}
21006 			
21007 			if (this.useFirstFamilyName && name.familyName) {
21008 				var familyNameParts = modified.familyName.trim().split(' ');
21009 				if (familyNameParts.length > 1) {
21010 					familyNameParts = this._adjoinAuxillaries(familyNameParts, name.prefix);
21011 				}	//in spain and mexico, we parse names differently than in the rest of the world
21012 	
21013 				modified.familyName = familyNameParts[0];
21014 			}
21015 		
21016 			modified._joinNameArrays();
21017 		} else {
21018 			isAsianName = true;
21019 			modified = name;
21020 			if (modified.suffix && currentLanguage === "ko" && this.info.honorifics.indexOf(name.suffix) == -1) {
21021 				modified.suffix = ' ' + modified.suffix; 
21022 			}
21023 		}
21024 		
21025 		if (!this.template || isAsianName !== this.isAsianLocale) {
21026 			temp = isAsianName ? this.defaultAsianTemplate : this.defaultEuroTemplate;
21027 		} else {
21028 			temp = this.template;
21029 		}
21030 		
21031 		var parts = {
21032 			prefix: this.comps["p"] && modified.prefix || "",
21033 			givenName: this.comps["g"] && modified.givenName || "",
21034 			middleName: this.comps["m"] && modified.middleName || "",
21035 			familyName: this.comps["f"] && modified.familyName || "",
21036 			suffix: this.comps["s"] && modified.suffix || ""
21037 		};
21038 		
21039 		formatted = temp.format(parts);
21040 		return formatted.replace(/\s+/g, ' ').trim();
21041 	}
21042 };
21043 
21044 
21045 /*< Address.js */
21046 /*
21047  * Address.js - Represent a mailing address
21048  * 
21049  * Copyright © 2013-2015, JEDLSoft
21050  *
21051  * Licensed under the Apache License, Version 2.0 (the "License");
21052  * you may not use this file except in compliance with the License.
21053  * You may obtain a copy of the License at
21054  *
21055  *     http://www.apache.org/licenses/LICENSE-2.0
21056  *
21057  * Unless required by applicable law or agreed to in writing, software
21058  * distributed under the License is distributed on an "AS IS" BASIS,
21059  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21060  *
21061  * See the License for the specific language governing permissions and
21062  * limitations under the License.
21063  */
21064 
21065 /*globals console RegExp */
21066 
21067 /* !depends 
21068 ilib.js
21069 Utils.js
21070 JSUtils.js
21071 Locale.js 
21072 isIdeo.js 
21073 isAscii.js
21074 isDigit.js
21075 IString.js
21076 */
21077 
21078 // !data address countries nativecountries ctrynames
21079 
21080 
21081 /**
21082  * @class
21083  * Create a new Address instance and parse a physical address.<p>
21084  * 
21085  * This function parses a physical address written in a free-form string. 
21086  * It returns an object with a number of properties from the list below 
21087  * that it may have extracted from that address.<p>
21088  * 
21089  * The following is a list of properties that the algorithm will return:<p>
21090  * 
21091  * <ul>
21092  * <li><i>streetAddress</i>: The street address, including house numbers and all.
21093  * <li><i>locality</i>: The locality of this address (usually a city or town). 
21094  * <li><i>region</i>: The region where the locality is located. In the US, this
21095  * corresponds to states. In other countries, this may be provinces,
21096  * cantons, prefectures, etc. In some smaller countries, there are no
21097  * such divisions.
21098  * <li><i>postalCode</i>: Country-specific code for expediting mail. In the US, 
21099  * this is the zip code.
21100  * <li><i>country</i>: The country of the address.
21101  * <li><i>countryCode</i>: The ISO 3166 2-letter region code for the destination
21102  * country in this address.
21103  * </ul> 
21104  * 
21105  * The above properties will not necessarily appear in the instance. For 
21106  * any individual property, if the free-form address does not contain 
21107  * that property or it cannot be parsed out, the it is left out.<p>
21108  * 
21109  * The options parameter may contain any of the following properties:
21110  * 
21111  * <ul>
21112  * <li><i>locale</i> - locale or localeSpec to use to parse the address. If not 
21113  * specified, this function will use the current ilib locale
21114  * 
21115  * <li><i>onLoad</i> - a callback function to call when the address info for the
21116  * locale is fully loaded and the address has been parsed. When the onLoad 
21117  * option is given, the address object 
21118  * will attempt to load any missing locale data using the ilib loader callback.
21119  * When the constructor is done (even if the data is already preassembled), the 
21120  * onLoad function is called with the current instance as a parameter, so this
21121  * callback can be used with preassembled or dynamic loading or a mix of the two. 
21122  * 
21123  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
21124  * asynchronously. If this option is given as "false", then the "onLoad"
21125  * callback must be given, as the instance returned from this constructor will
21126  * not be usable for a while. 
21127  *
21128  * <li><i>loadParams</i> - an object containing parameters to pass to the 
21129  * loader callback function when locale data is missing. The parameters are not
21130  * interpretted or modified in any way. They are simply passed along. The object 
21131  * may contain any property/value pairs as long as the calling code is in
21132  * agreement with the loader callback function as to what those parameters mean.
21133  * </ul>
21134  * 
21135  * When an address cannot be parsed properly, the entire address will be placed
21136  * into the streetAddress property.<p>
21137  * 
21138  * When the freeformAddress is another Address, this will act like a copy
21139  * constructor.<p>
21140  * 
21141  * 
21142  * @constructor
21143  * @param {string|Address} freeformAddress free-form address to parse, or a
21144  * javascript object containing the fields
21145  * @param {Object} options options to the parser
21146  */
21147 var Address = function (freeformAddress, options) {
21148 	var address;
21149 
21150 	if (!freeformAddress) {
21151 		return undefined;
21152 	}
21153 
21154 	this.sync = true;
21155 	this.loadParams = {};
21156 	
21157 	if (options) {
21158 		if (options.locale) {
21159 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
21160 		}
21161 		
21162 		if (typeof(options.sync) !== 'undefined') {
21163 			this.sync = (options.sync == true);
21164 		}
21165 		
21166 		if (options.loadParams) {
21167 			this.loadParams = options.loadParams;
21168 		}
21169 	}
21170 
21171 	this.locale = this.locale || new Locale();
21172 	// initialize from an already parsed object
21173 	if (typeof(freeformAddress) === 'object') {
21174 		/**
21175 		 * The street address, including house numbers and all.
21176 		 * @expose
21177 		 * @type {string|undefined} 
21178 		 */
21179 		this.streetAddress = freeformAddress.streetAddress;
21180 		/**
21181 		 * The locality of this address (usually a city or town).
21182 		 * @expose
21183 		 * @type {string|undefined} 
21184 		 */
21185 		this.locality = freeformAddress.locality;
21186 		/**
21187 		 * The region (province, canton, prefecture, state, etc.) where the address is located.
21188 		 * @expose
21189 		 * @type {string|undefined} 
21190 		 */
21191 		this.region = freeformAddress.region;
21192 		/**
21193 		 * Country-specific code for expediting mail. In the US, this is the zip code.
21194 		 * @expose
21195 		 * @type {string|undefined} 
21196 		 */
21197 		this.postalCode = freeformAddress.postalCode;
21198 		/**
21199 		 * Optional city-specific code for a particular post office, used to expidite
21200 		 * delivery.
21201 		 * @expose
21202 		 * @type {string|undefined} 
21203 		 */
21204 		this.postOffice = freeformAddress.postOffice;
21205 		/**
21206 		 * The country of the address.
21207 		 * @expose
21208 		 * @type {string|undefined}
21209 		 */
21210 		this.country = freeformAddress.country;
21211 		if (freeformAddress.countryCode) {
21212 			/**
21213 			 * The 2 or 3 letter ISO 3166 region code for the destination country in this address.
21214 			 * @expose
21215 			 * @type {string} 
21216 			 * 
21217 			 */
21218 			this.countryCode = freeformAddress.countryCode;
21219 		}
21220 		if (freeformAddress.format) {
21221 			/**
21222 			 * private
21223 			 * @type {string}
21224 			 */
21225 			this.format = freeformAddress.format;
21226 		}
21227 		return this;
21228 	}
21229 
21230 	address = freeformAddress.replace(/[ \t\r]+/g, " ").trim();
21231 	address = address.replace(/[\s\n]+$/, "");
21232 	address = address.replace(/^[\s\n]+/, "");
21233 	//console.log("\n\n-------------\nAddress is '" + address + "'");
21234 	
21235 	this.lines = address.split(/[,,\n]/g);
21236 	this.removeEmptyLines(this.lines);
21237 	
21238 	isAscii._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
21239 		isIdeo._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
21240 			isDigit._init(this.sync, this.loadParams, /** @type {function(*)|undefined} */ ilib.bind(this, function() {
21241 				if (typeof(ilib.data.nativecountries) === 'undefined') {
21242 					Utils.loadData({
21243 						object: Address,
21244 						name: "nativecountries.json", // countries in their own language 
21245 						locale: "-", // only need to load the root file 
21246 						nonlocale: true,
21247 						sync: this.sync, 
21248 						loadParams: this.loadParams, 
21249 						callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(nativecountries) {
21250 							ilib.data.nativecountries = nativecountries;
21251 							this._loadCountries(options && options.onLoad);
21252 						})
21253 					});
21254 				} else {
21255 					this._loadCountries(options && options.onLoad);
21256 				}
21257 			}));
21258 		}));
21259 	}));
21260 };
21261 
21262 /** @protected */
21263 Address.prototype = {
21264 	/**
21265 	 * @private
21266 	 */
21267 	_loadCountries: function(onLoad) {
21268 		if (typeof(ilib.data.countries) === 'undefined') {
21269 			Utils.loadData({
21270 				object: Address,
21271 				name: "countries.json", // countries in English
21272 				locale: "-", // only need to load the root file
21273 				nonlocale: true,
21274 				sync: this.sync, 
21275 				loadParams: this.loadParams, 
21276 				callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(countries) {
21277 					ilib.data.countries = countries;
21278 					this._loadCtrynames(onLoad);
21279 				})
21280 			});
21281 		} else {
21282 			this._loadCtrynames(onLoad);
21283 		}
21284 	},
21285 
21286 	/**
21287 	 * @private
21288 	 */
21289 	_loadCtrynames: function(onLoad) {
21290 		Utils.loadData({
21291 			name: "ctrynames.json", 
21292 			object: Address, 
21293 			locale: this.locale,
21294 			sync: this.sync, 
21295 			loadParams: this.loadParams, 
21296 			callback: /** @type function(Object=):undefined */ ilib.bind(this, /** @type function() */ function(ctrynames) {
21297 				this._determineDest(ctrynames, onLoad);
21298 			})
21299 		});
21300 	},
21301 	
21302 	/**
21303 	 * @private
21304 	 * @param {Object?} ctrynames
21305 	 */
21306 	_findDest: function (ctrynames) {
21307 		var match;
21308 		
21309 		for (var countryName in ctrynames) {
21310 			if (countryName && countryName !== "generated") {
21311 				// find the longest match in the current table
21312 				// ctrynames contains the country names mapped to region code
21313 				// for efficiency, only test for things longer than the current match
21314 				if (!match || match.text.length < countryName.length) {
21315 					var temp = this._findCountry(countryName);
21316 					if (temp) {
21317 						match = temp;
21318 						this.country = match.text;
21319 						this.countryCode = ctrynames[countryName];
21320 					}
21321 				}
21322 			}
21323 		}
21324 		return match;
21325 	},
21326 	
21327 	/**
21328 	 * @private
21329 	 * @param {Object?} localizedCountries
21330 	 * @param {function(Address):undefined} callback
21331 	 */
21332 	_determineDest: function (localizedCountries, callback) {
21333 		var match;
21334 		
21335 		/*
21336 		 * First, find the name of the destination country, as that determines how to parse
21337 		 * the rest of the address. For any address, there are three possible ways 
21338 		 * that the name of the country could be written:
21339 		 * 1. In the current language
21340 		 * 2. In its own native language
21341 		 * 3. In English
21342 		 * We'll try all three.
21343 		 */
21344 		var tables = [];
21345 		if (localizedCountries) {
21346 			tables.push(localizedCountries);
21347 		}
21348 		tables.push(ilib.data.nativecountries);
21349 		tables.push(ilib.data.countries);
21350 		
21351 		for (var i = 0; i < tables.length; i++) {
21352 			match = this._findDest(tables[i]);
21353 			
21354 			if (match) {
21355 				this.lines[match.line] = this.lines[match.line].substring(0, match.start) + this.lines[match.line].substring(match.start + match.text.length);
21356 
21357 				this._init(callback);
21358 				return;
21359 			}
21360 		}
21361 		
21362 		// no country, so try parsing it as if we were in the same country
21363 		this.country = undefined;
21364 		this.countryCode = this.locale.getRegion();
21365 		this._init(callback);
21366 	},
21367 
21368 	/**
21369 	 * @private
21370 	 * @param {function(Address):undefined} callback
21371 	 */
21372 	_init: function(callback) {
21373 		Utils.loadData({
21374 			object: Address, 
21375 			locale: new Locale(this.countryCode), 
21376 			name: "address.json", 
21377 			sync: this.sync, 
21378 			loadParams: this.loadParams,
21379 			callback: /** @type function(Object=):undefined */ ilib.bind(this, function(info) {
21380 				if (!info || JSUtils.isEmpty(info)) {
21381 					// load the "unknown" locale instead
21382 					Utils.loadData({
21383 						object: Address, 
21384 						locale: new Locale("XX"), 
21385 						name: "address.json", 
21386 						sync: this.sync, 
21387 						loadParams: this.loadParams,
21388 						callback: /** @type function(Object=):undefined */ ilib.bind(this, function(info) {
21389 							this.info = info;
21390 							this._parseAddress();
21391 							if (typeof(callback) === 'function') {
21392 								callback(this);
21393 							}	
21394 						})
21395 					});
21396 				} else {
21397 					this.info = info;
21398 					this._parseAddress();
21399 					if (typeof(callback) === 'function') {
21400 						callback(this);
21401 					}
21402 				}
21403 			})
21404 		});
21405 	},
21406 
21407 	/**
21408 	 * @private
21409 	 */
21410 	_parseAddress: function() {
21411 		// clean it up first
21412 		var i, 
21413 			asianChars = 0, 
21414 			latinChars = 0,
21415 			startAt,
21416 			infoFields,
21417 			field,
21418 			pattern,
21419 			matchFunction,
21420 			match,
21421 			fieldNumber;
21422 		
21423 		// for locales that support both latin and asian character addresses, 
21424 		// decide if we are parsing an asian or latin script address
21425 		if (this.info && this.info.multiformat) {
21426 			for (var j = 0; j < this.lines.length; j++) {
21427 				var line = new IString(this.lines[j]);
21428 				var it = line.charIterator();
21429 				while (it.hasNext()) {
21430 					var c = it.next();
21431 					if (isIdeo(c) || CType.withinRange(c, "Hangul")) {
21432 						asianChars++;
21433 					} else if (isAscii(c) && !isDigit(c)) {
21434 						latinChars++;
21435 					}
21436 				}
21437 			}
21438 			
21439 			this.format = (asianChars >= latinChars) ? "asian" : "latin";
21440 			startAt = this.info.startAt[this.format];
21441 			infoFields = this.info.fields[this.format];
21442 			// //console.log("multiformat locale: format is now " + this.format);
21443 		} else {
21444 			startAt = (this.info && this.info.startAt) || "end";
21445 			infoFields = this.info.fields;
21446 		}
21447 		this.compare = (startAt === "end") ? this.endsWith : this.startsWith;
21448 		
21449 		//console.log("this.lines is: " + JSON.stringify(this.lines));
21450 		
21451 		for (i = 0; i < infoFields.length && this.lines.length > 0; i++) {
21452 			/** @type {{name:string, line:string, pattern:(string|Array.<string>), matchGroup:number}} */
21453 			field = infoFields[i];
21454 			this.removeEmptyLines(this.lines);
21455 			//console.log("Searching for field " + field.name);
21456 			if (field.pattern) {
21457 				if (typeof(field.pattern) === 'string') {
21458 					pattern = new RegExp(field.pattern, "img");
21459 					matchFunction = this.matchRegExp;
21460 				} else {
21461 					pattern = field.pattern;
21462 					matchFunction = this.matchPattern;
21463 				}
21464 					
21465 				switch (field.line) {
21466 				case 'startAtFirst':
21467 					for (fieldNumber = 0; fieldNumber < this.lines.length; fieldNumber++) {
21468 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21469 						if (match) {
21470 							break;
21471 						}
21472 					}
21473 					break;
21474 				case 'startAtLast':
21475 					for (fieldNumber = this.lines.length-1; fieldNumber >= 0; fieldNumber--) {
21476 						match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21477 						if (match) {
21478 							break;
21479 						}
21480 					}
21481 					break;
21482 				case 'first':
21483 					fieldNumber = 0;
21484 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21485 					break;
21486 				case 'last':
21487 				default:
21488 					fieldNumber = this.lines.length - 1;
21489 					match = matchFunction(this, this.lines[fieldNumber], pattern, field.matchGroup, startAt);
21490 					break;
21491 				}
21492 				if (match) {
21493 					// //console.log("found match for " + field.name + ": " + JSON.stringify(match));
21494 					// //console.log("remaining line is " + match.line);
21495 					this.lines[fieldNumber] = match.line;
21496 					this[field.name] = match.match;
21497 				}
21498 			} else {
21499 				// if nothing is given, default to taking the whole field
21500 				this[field.name] = this.lines.splice(fieldNumber,1)[0].trim();
21501 				//console.log("typeof(this[field.name]) is " + typeof(this[field.name]) + " and value is " + JSON.stringify(this[field.name]));
21502 			}
21503 		}
21504 			
21505 		// all the left overs go in the street address field
21506 		this.removeEmptyLines(this.lines);
21507 		if (this.lines.length > 0) {
21508 			//console.log("this.lines is " + JSON.stringify(this.lines) + " and splicing to get streetAddress");
21509 			// Korea uses spaces between words, despite being an "asian" locale
21510 			var joinString = (this.info.joinString && this.info.joinString[this.format]) || ((this.format && this.format === "asian") ? "" : ", ");
21511 			this.streetAddress = this.lines.join(joinString).trim();
21512 		}
21513 		
21514 		this.lines = undefined;
21515 		//console.log("final result is " + JSON.stringify(this));
21516 	},
21517 	
21518 	/**
21519 	 * @protected
21520 	 * Find the named country either at the end or the beginning of the address.
21521 	 */
21522 	_findCountry: function(name) {
21523 		var start = -1, match, line = 0;
21524 		
21525 		if (this.lines.length > 0) {
21526 			start = this.startsWith(this.lines[line], name);
21527 			if (start === -1) {
21528 				line = this.lines.length-1;
21529 				start = this.endsWith(this.lines[line], name);
21530 			}
21531 			if (start !== -1) {
21532 				match = {
21533 					text: this.lines[line].substring(start, start + name.length),
21534 					line: line,
21535 					start: start
21536 				};
21537 			}
21538 		}
21539 		
21540 		return match;
21541 	},
21542 	
21543 	endsWith: function (subject, query) {
21544 		var start = subject.length-query.length,
21545 			i,
21546 			pat;
21547 		//console.log("endsWith: checking " + query + " against " + subject);
21548 		for (i = 0; i < query.length; i++) {
21549 			// TODO: use case mapper instead of toLowerCase()
21550 			if (subject.charAt(start+i).toLowerCase() !== query.charAt(i).toLowerCase()) {
21551 				return -1;
21552 			}
21553 		}
21554 		if (start > 0) {
21555 			pat = /\s/;
21556 			if (!pat.test(subject.charAt(start-1))) {
21557 				// make sure if we are not at the beginning of the string, that the match is 
21558 				// not the end of some other word
21559 				return -1;
21560 			}
21561 		}
21562 		return start;
21563 	},
21564 	
21565 	startsWith: function (subject, query) {
21566 		var i;
21567 		// //console.log("startsWith: checking " + query + " against " + subject);
21568 		for (i = 0; i < query.length; i++) {
21569 			// TODO: use case mapper instead of toLowerCase()
21570 			if (subject.charAt(i).toLowerCase() !== query.charAt(i).toLowerCase()) {
21571 				return -1;
21572 			}
21573 		}
21574 		return 0;
21575 	},
21576 	
21577 	removeEmptyLines: function (arr) {
21578 		var i = 0;
21579 		
21580 		while (i < arr.length) {
21581 			if (arr[i]) {
21582 				arr[i] = arr[i].trim();
21583 				if (arr[i].length === 0) {
21584 					arr.splice(i,1);
21585 				} else {
21586 					i++;
21587 				}
21588 			} else {
21589 				arr.splice(i,1);
21590 			}
21591 		}
21592 	},
21593 	
21594 	matchRegExp: function(address, line, expression, matchGroup, startAt) {
21595 		var lastMatch,
21596 			match,
21597 			ret = {},
21598 			last;
21599 		
21600 		//console.log("searching for regexp " + expression.source + " in line " + line);
21601 		
21602 		match = expression.exec(line);
21603 		if (startAt === 'end') {
21604 			while (match !== null && match.length > 0) {
21605 				//console.log("found matches " + JSON.stringify(match));
21606 				lastMatch = match;
21607 				match = expression.exec(line);
21608 			}
21609 			match = lastMatch;
21610 		}
21611 		
21612 		if (match && match !== null) {
21613 			//console.log("found matches " + JSON.stringify(match));
21614 			matchGroup = matchGroup || 0;
21615 			if (match[matchGroup] !== undefined) {
21616 				ret.match = match[matchGroup].trim();
21617 				ret.match = ret.match.replace(/^\-|\-+$/, '');
21618 				ret.match = ret.match.replace(/\s+$/, '');
21619 				last = (startAt === 'end') ? line.lastIndexOf(match[matchGroup]) : line.indexOf(match[matchGroup]); 
21620 				//console.log("last is " + last);
21621 				ret.line = line.slice(0,last);
21622 				if (address.format !== "asian") {
21623 					ret.line += " ";
21624 				}
21625 				ret.line += line.slice(last+match[matchGroup].length);
21626 				ret.line = ret.line.trim();
21627 				//console.log("found match " + ret.match + " from matchgroup " + matchGroup + " and rest of line is " + ret.line);
21628 				return ret;
21629 			}
21630 		//} else {
21631 			//console.log("no match");
21632 		}
21633 		
21634 		return undefined;
21635 	},
21636 	
21637 	matchPattern: function(address, line, pattern, matchGroup) {
21638 		var start,
21639 			j,
21640 			ret = {};
21641 		
21642 		//console.log("searching in line " + line);
21643 		
21644 		// search an array of possible fixed strings
21645 		//console.log("Using fixed set of strings.");
21646 		for (j = 0; j < pattern.length; j++) {
21647 			start = address.compare(line, pattern[j]); 
21648 			if (start !== -1) {
21649                             ret.match = line.substring(start, start+pattern[j].length);
21650                             if (start !== 0) {
21651                                 ret.line = line.substring(0,start).trim();
21652                             } else {
21653                                 ret.line = line.substring(pattern[j].length).trim();
21654                             }
21655 				//console.log("found match " + ret.match + " and rest of line is " + ret.line);
21656                             return ret;
21657 			}
21658 		}
21659 		
21660 		return undefined;
21661 	}
21662 };
21663 
21664 
21665 
21666 /*< AddressFmt.js */
21667 /*
21668  * AddressFmt.js - Format an address
21669  * 
21670  * Copyright © 2013-2015, JEDLSoft
21671  *
21672  * Licensed under the Apache License, Version 2.0 (the "License");
21673  * you may not use this file except in compliance with the License.
21674  * You may obtain a copy of the License at
21675  *
21676  *     http://www.apache.org/licenses/LICENSE-2.0
21677  *
21678  * Unless required by applicable law or agreed to in writing, software
21679  * distributed under the License is distributed on an "AS IS" BASIS,
21680  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21681  *
21682  * See the License for the specific language governing permissions and
21683  * limitations under the License.
21684  */
21685 
21686 /* !depends 
21687 ilib.js 
21688 Locale.js
21689 Address.js
21690 IString.js
21691 Utils.js
21692 JSUtils.js
21693 */
21694 
21695 // !data address
21696 
21697 
21698 
21699 /**
21700  * @class
21701  * Create a new formatter object to format physical addresses in a particular way.
21702  *
21703  * The options object may contain the following properties, both of which are optional:
21704  *
21705  * <ul>
21706  * <li><i>locale</i> - the locale to use to format this address. If not specified, it uses the default locale
21707  * 
21708  * <li><i>style</i> - the style of this address. The default style for each country usually includes all valid 
21709  * fields for that country.
21710  * 
21711  * <li><i>onLoad</i> - a callback function to call when the address info for the
21712  * locale is fully loaded and the address has been parsed. When the onLoad 
21713  * option is given, the address formatter object 
21714  * will attempt to load any missing locale data using the ilib loader callback.
21715  * When the constructor is done (even if the data is already preassembled), the 
21716  * onLoad function is called with the current instance as a parameter, so this
21717  * callback can be used with preassembled or dynamic loading or a mix of the two. 
21718  * 
21719  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
21720  * asynchronously. If this option is given as "false", then the "onLoad"
21721  * callback must be given, as the instance returned from this constructor will
21722  * not be usable for a while. 
21723  *
21724  * <li><i>loadParams</i> - an object containing parameters to pass to the 
21725  * loader callback function when locale data is missing. The parameters are not
21726  * interpretted or modified in any way. They are simply passed along. The object 
21727  * may contain any property/value pairs as long as the calling code is in
21728  * agreement with the loader callback function as to what those parameters mean.
21729  * </ul>
21730  * 
21731  * 
21732  * @constructor
21733  * @param {Object} options options that configure how this formatter should work
21734  * Returns a formatter instance that can format multiple addresses.
21735  */
21736 var AddressFmt = function(options) {
21737 	this.sync = true;
21738 	this.styleName = 'default';
21739 	this.loadParams = {};
21740 	this.locale = new Locale();
21741 	
21742 	if (options) {
21743 		if (options.locale) {
21744 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
21745 		}
21746 		
21747 		if (typeof(options.sync) !== 'undefined') {
21748 			this.sync = (options.sync == true);
21749 		}
21750 		
21751 		if (options.style) {
21752 			this.styleName = options.style;
21753 		}
21754 		
21755 		if (options.loadParams) {
21756 			this.loadParams = options.loadParams;
21757 		}
21758 	}
21759 	
21760 	// console.log("Creating formatter for region: " + this.locale.region);
21761 	Utils.loadData({
21762 		name: "address.json",
21763 		object: AddressFmt, 
21764 		locale: this.locale,
21765 		sync: this.sync, 
21766 		loadParams: this.loadParams, 
21767 		callback: /** @type function(Object?):undefined */ ilib.bind(this, function(info) {
21768 			if (!info || JSUtils.isEmpty(info)) {
21769 				// load the "unknown" locale instead
21770 				Utils.loadData({
21771 					name: "address.json",
21772 					object: AddressFmt, 
21773 					locale: new Locale("XX"),
21774 					sync: this.sync, 
21775 					loadParams: this.loadParams, 
21776 					callback: /** @type function(Object?):undefined */ ilib.bind(this, function(info) {
21777 						this.info = info;
21778 						this._init();
21779 						if (options && typeof(options.onLoad) === 'function') {
21780 							options.onLoad(this);
21781 						}
21782 					})
21783 				});
21784 			} else {
21785 				this.info = info;
21786 				this._init();
21787 				if (options && typeof(options.onLoad) === 'function') {
21788 					options.onLoad(this);
21789 				}
21790 			}
21791 		})
21792 	});
21793 };
21794 
21795 /**
21796  * @private
21797  */
21798 AddressFmt.prototype._init = function () {
21799 	this.style = this.info && this.info.formats && this.info.formats[this.styleName];
21800 	
21801 	// use generic default -- should not happen, but just in case...
21802 	this.style = this.style || (this.info && this.info.formats["default"]) || "{streetAddress}\n{locality} {region} {postalCode}\n{country}";
21803 };
21804 
21805 /**
21806  * This function formats a physical address (Address instance) for display. 
21807  * Whitespace is trimmed from the beginning and end of final resulting string, and 
21808  * multiple consecutive whitespace characters in the middle of the string are 
21809  * compressed down to 1 space character.
21810  * 
21811  * If the Address instance is for a locale that is different than the locale for this
21812  * formatter, then a hybrid address is produced. The country name is located in the
21813  * correct spot for the current formatter's locale, but the rest of the fields are
21814  * formatted according to the default style of the locale of the actual address.
21815  * 
21816  * Example: a mailing address in China, but formatted for the US might produce the words
21817  * "People's Republic of China" in English at the last line of the address, and the 
21818  * Chinese-style address will appear in the first line of the address. In the US, the
21819  * country is on the last line, but in China the country is usually on the first line.
21820  *
21821  * @param {Address} address Address to format
21822  * @eturns {string} Returns a string containing the formatted address
21823  */
21824 AddressFmt.prototype.format = function (address) {
21825 	var ret, template, other, format;
21826 	
21827 	if (!address) {
21828 		return "";
21829 	}
21830 	// console.log("formatting address: " + JSON.stringify(address));
21831 	if (address.countryCode && 
21832 			address.countryCode !== this.locale.region && 
21833 			Locale._isRegionCode(this.locale.region) && 
21834 			this.locale.region !== "XX") {
21835 		// we are formatting an address that is sent from this country to another country,
21836 		// so only the country should be in this locale, and the rest should be in the other
21837 		// locale
21838 		// console.log("formatting for another locale. Loading in its settings: " + address.countryCode);
21839 		other = new AddressFmt({
21840 			locale: new Locale(address.countryCode), 
21841 			style: this.styleName
21842 		});
21843 		return other.format(address);
21844 	}
21845 	
21846 	if (typeof(this.style) === 'object') {
21847 		format = this.style[address.format || "latin"];
21848 	} else {
21849 		format = this.style;
21850 	}
21851 	
21852 	// console.log("Using format: " + format);
21853 	// make sure we have a blank string for any missing parts so that
21854 	// those template parts get blanked out
21855 	var params = {
21856 		country: address.country || "",
21857 		region: address.region || "",
21858 		locality: address.locality || "",
21859 		streetAddress: address.streetAddress || "",
21860 		postalCode: address.postalCode || "",
21861 		postOffice: address.postOffice || ""
21862 	};
21863 	template = new IString(format);
21864 	ret = template.format(params);
21865 	ret = ret.replace(/[ \t]+/g, ' ');
21866 	ret = ret.replace("\n ", "\n");
21867 	ret = ret.replace(" \n", "\n");
21868 	return ret.replace(/\n+/g, '\n').trim();
21869 };
21870 
21871 
21872 
21873 /*< GlyphString.js */
21874 /*
21875  * GlyphString.js - ilib string subclass that allows you to access 
21876  * whole glyphs at a time
21877  * 
21878  * Copyright © 2015, JEDLSoft
21879  *
21880  * Licensed under the Apache License, Version 2.0 (the "License");
21881  * you may not use this file except in compliance with the License.
21882  * You may obtain a copy of the License at
21883  *
21884  *     http://www.apache.org/licenses/LICENSE-2.0
21885  *
21886  * Unless required by applicable law or agreed to in writing, software
21887  * distributed under the License is distributed on an "AS IS" BASIS,
21888  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21889  *
21890  * See the License for the specific language governing permissions and
21891  * limitations under the License.
21892  */
21893 
21894 // !depends IString.js CType.js Utils.js JSUtils.js
21895 // !data norm ctype_m
21896 
21897 
21898 
21899 /**
21900  * @class
21901  * Create a new glyph string instance. This string inherits from 
21902  * the IString class, and adds methods that allow you to access
21903  * whole glyphs at a time. <p>
21904  * 
21905  * In Unicode, various accented characters can be created by using
21906  * a base character and one or more combining characters following
21907  * it. These appear on the screen to the user as a single glyph.
21908  * For example, the Latin character "a" (U+0061) followed by the
21909  * combining diaresis character "¨" (U+0308) combine together to
21910  * form the "a with diaresis" glyph "ä", which looks like a single
21911  * character on the screen.<p>
21912  * 
21913  * The big problem with combining characters for web developers is
21914  * that many CSS engines do not ellipsize text between glyphs. They
21915  * only deal with single Unicode characters. So if a particular space 
21916  * only allows for 4 characters, the CSS engine will truncate a
21917  * string at 4 Unicode characters and then add the ellipsis (...)
21918  * character. What if the fourth Unicode character is the "a" and
21919  * the fifth one is the diaresis? Then a string like "xxxäxxx" that
21920  * is ellipsized at 4 characters will appear as "xxxa..." on the 
21921  * screen instead of "xxxä...".<p>
21922  * 
21923  * In the Latin script as it is commonly used, it is not so common
21924  * to form accented characters using combining accents, so the above
21925  * example is mostly for illustrative purposes. It is not unheard of
21926  * however. The situation is much, much worse in scripts such as Thai and 
21927  * Devanagari that normally make very heavy use of combining characters.
21928  * These scripts do so because Unicode does not include pre-composed 
21929  * versions of the accented characters like it does for Latin, so 
21930  * combining accents are the only way to create these accented and 
21931  * combined versions of the characters.<p>
21932  * 
21933  * The solution to thise problem is not to use the the CSS property 
21934  * "text-overflow: ellipsis" in your web site, ever. Instead, use
21935  * a glyph string to truncate text between glyphs instead of between
21936  * characters.<p>
21937  * 
21938  * Glyph strings are also useful for truncation, hyphenation, and 
21939  * line wrapping, as all of these should be done between glyphs instead
21940  * of between characters.<p>
21941  * 
21942  * The options parameter is optional, and may contain any combination
21943  * of the following properties:<p>
21944  * 
21945  * <ul>
21946  * <li><i>onLoad</i> - a callback function to call when the locale data are
21947  * fully loaded. When the onLoad option is given, this object will attempt to
21948  * load any missing locale data using the ilib loader callback.
21949  * When the constructor is done (even if the data is already preassembled), the 
21950  * onLoad function is called with the current instance as a parameter, so this
21951  * callback can be used with preassembled or dynamic loading or a mix of the two.
21952  * 
21953  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
21954  * asynchronously. If this option is given as "false", then the "onLoad"
21955  * callback must be given, as the instance returned from this constructor will
21956  * not be usable for a while.
21957  *  
21958  * <li><i>loadParams</i> - an object containing parameters to pass to the 
21959  * loader callback function when locale data is missing. The parameters are not
21960  * interpretted or modified in any way. They are simply passed along. The object 
21961  * may contain any property/value pairs as long as the calling code is in
21962  * agreement with the loader callback function as to what those parameters mean.
21963  * </ul>
21964  * 
21965  * @constructor
21966  * @extends IString
21967  * @param {string|IString=} str initialize this instance with this string 
21968  * @param {Object=} options options governing the way this instance works
21969  */
21970 var GlyphString = function (str, options) {
21971 	if (options && options.noinstance) {
21972 		return;
21973 	}
21974 	
21975 	IString.call(this, str);
21976 	
21977 	var sync = true;
21978 	var loadParams = {};
21979 	if (options) {
21980 		if (typeof(options.sync) === 'boolean') {
21981 			sync = options.sync;
21982 		}
21983 		if (options.loadParams) {
21984 			loadParams = options.loadParams;
21985 		}
21986 	}
21987 	
21988 	CType._load("ctype_m", sync, loadParams, function() {
21989 		if (!ilib.data.norm || JSUtils.isEmpty(ilib.data.norm.ccc)) {
21990 			Utils.loadData({
21991 				object: GlyphString, 
21992 				locale: "-", 
21993 				name: "normdata.json",
21994 				nonlocale: true,
21995 				sync: sync, 
21996 				loadParams: loadParams, 
21997 				callback: ilib.bind(this, function (norm) {
21998 					ilib.extend(ilib.data.norm, norm);
21999 					if (options && typeof(options.onLoad) === 'function') {
22000 						options.onLoad(this);
22001 					}
22002 				})
22003 			});
22004 		} else {
22005 			if (options && typeof(options.onLoad) === 'function') {
22006 				options.onLoad(this);
22007 			}
22008 		}
22009 	});
22010 };
22011 
22012 GlyphString.prototype = new IString(undefined);
22013 GlyphString.prototype.parent = IString;
22014 GlyphString.prototype.constructor = GlyphString;
22015 
22016 /**
22017  * Return true if the given character is a leading Jamo (Choseong) character.
22018  * 
22019  * @private
22020  * @static
22021  * @param {number} n code point to check
22022  * @return {boolean} true if the character is a leading Jamo character, 
22023  * false otherwise
22024  */
22025 GlyphString._isJamoL = function (n) {
22026 	return (n >= 0x1100 && n <= 0x1112);
22027 };
22028 
22029 /**
22030  * Return true if the given character is a vowel Jamo (Jungseong) character.
22031  * 
22032  * @private
22033  * @static
22034  * @param {number} n code point to check
22035  * @return {boolean} true if the character is a vowel Jamo character, 
22036  * false otherwise
22037  */
22038 GlyphString._isJamoV = function (n) {
22039 	return (n >= 0x1161 && n <= 0x1175);
22040 };
22041 
22042 /**
22043  * Return true if the given character is a trailing Jamo (Jongseong) character.
22044  * 
22045  * @private
22046  * @static
22047  * @param {number} n code point to check
22048  * @return {boolean} true if the character is a trailing Jamo character, 
22049  * false otherwise
22050  */
22051 GlyphString._isJamoT = function (n) {
22052 	return (n >= 0x11A8 && n <= 0x11C2);
22053 };
22054 
22055 /**
22056  * Return true if the given character is a precomposed Hangul character.
22057  * 
22058  * @private
22059  * @static
22060  * @param {number} n code point to check
22061  * @return {boolean} true if the character is a precomposed Hangul character, 
22062  * false otherwise
22063  */
22064 GlyphString._isHangul = function (n) {
22065 	return (n >= 0xAC00 && n <= 0xD7A3);
22066 };
22067 
22068 /**
22069  * Algorithmically compose an L and a V combining Jamo characters into
22070  * a precomposed Korean syllabic Hangul character. Both should already
22071  * be in the proper ranges for L and V characters. 
22072  * 
22073  * @private
22074  * @static
22075  * @param {number} lead the code point of the lead Jamo character to compose
22076  * @param {number} trail the code point of the trailing Jamo character to compose
22077  * @return {string} the composed Hangul character
22078  */
22079 GlyphString._composeJamoLV = function (lead, trail) {
22080 	var lindex = lead - 0x1100;
22081 	var vindex = trail - 0x1161;
22082 	return IString.fromCodePoint(0xAC00 + (lindex * 21 + vindex) * 28);
22083 };
22084 
22085 /**
22086  * Algorithmically compose a Hangul LV and a combining Jamo T character 
22087  * into a precomposed Korean syllabic Hangul character. 
22088  * 
22089  * @private
22090  * @static
22091  * @param {number} lead the code point of the lead Hangul character to compose
22092  * @param {number} trail the code point of the trailing Jamo T character to compose
22093  * @return {string} the composed Hangul character
22094  */
22095 GlyphString._composeJamoLVT = function (lead, trail) {
22096 	return IString.fromCodePoint(lead + (trail - 0x11A7));
22097 };
22098 
22099 /**
22100  * Compose one character out of a leading character and a 
22101  * trailing character. If the characters are Korean Jamo, they
22102  * will be composed algorithmically. If they are any other
22103  * characters, they will be looked up in the nfc tables.
22104  * 
22105  * @private
22106  * @static
22107  * @param {string} lead leading character to compose
22108  * @param {string} trail the trailing character to compose
22109  * @return {string|null} the fully composed character, or undefined if
22110  * there is no composition for those two characters
22111  */
22112 GlyphString._compose = function (lead, trail) {
22113 	var first = lead.charCodeAt(0);
22114 	var last = trail.charCodeAt(0);
22115 	if (GlyphString._isHangul(first) && GlyphString._isJamoT(last)) {
22116 		return GlyphString._composeJamoLVT(first, last);
22117 	} else if (GlyphString._isJamoL(first) && GlyphString._isJamoV(last)) {
22118 		return GlyphString._composeJamoLV(first, last);
22119 	}
22120 
22121 	var c = lead + trail;
22122 	return (ilib.data.norm.nfc && ilib.data.norm.nfc[c]);
22123 };
22124 
22125 /**
22126  * Return an iterator that will step through all of the characters
22127  * in the string one at a time, taking care to step through decomposed 
22128  * characters and through surrogate pairs in the UTF-16 encoding 
22129  * as single characters. <p>
22130  * 
22131  * The GlyphString class will return decomposed Unicode characters
22132  * as a single unit that a user might see on the screen as a single
22133  * glyph. If the 
22134  * next character in the iteration is a base character and it is 
22135  * followed by combining characters, the base and all its following 
22136  * combining characters are returned as a single unit.<p>
22137  * 
22138  * The standard Javascript String's charAt() method only
22139  * returns information about a particular 16-bit character in the 
22140  * UTF-16 encoding scheme.
22141  * If the index is pointing to a low- or high-surrogate character,
22142  * it will return that surrogate character rather 
22143  * than the surrogate pair which represents a character 
22144  * in the supplementary planes.<p>
22145  * 
22146  * The iterator instance returned has two methods, hasNext() which
22147  * returns true if the iterator has more characters to iterate through,
22148  * and next() which returns the next character.<p>
22149  * 
22150  * @override
22151  * @return {Object} an iterator 
22152  * that iterates through all the characters in the string
22153  */
22154 GlyphString.prototype.charIterator = function() {
22155 	var it = IString.prototype.charIterator.call(this);
22156 	
22157 	/**
22158 	 * @constructor
22159 	 */
22160 	function _chiterator (istring) {
22161 		this.index = 0;
22162 		this.spacingCombining = false;
22163 		this.hasNext = function () {
22164 			return !!this.nextChar || it.hasNext();
22165 		};
22166 		this.next = function () {
22167 			var ch = this.nextChar || it.next(),
22168 				prevCcc = ilib.data.norm.ccc[ch],
22169 				nextCcc,
22170 				composed = ch;
22171 			
22172 			this.nextChar = undefined;
22173 			this.spacingCombining = false;
22174 			
22175 			if (ilib.data.norm.ccc && 
22176 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ilib.data.norm.ccc[ch] === 0)) {
22177 				// found a starter... find all the non-starters until the next starter. Must include
22178 				// the next starter because under some odd circumstances, two starters sometimes recompose 
22179 				// together to form another character
22180 				var notdone = true;
22181 				while (it.hasNext() && notdone) {
22182 					this.nextChar = it.next();
22183 					nextCcc = ilib.data.norm.ccc[this.nextChar];
22184 					var codePoint = IString.toCodePoint(this.nextChar, 0);
22185 					// Mn characters are Marks that are non-spacing. These do not take more room than an accent, so they should be 
22186 					// considered part of the on-screen glyph, even if they are non-combining. Mc are marks that are spacing
22187 					// and combining, which means they are part of the glyph, but they cause the glyph to use up more space than
22188 					// just the base character alone.
22189 					var isMn = CType._inRange(codePoint, "Mn", ilib.data.ctype_m);
22190 					var isMc = CType._inRange(codePoint, "Mc", ilib.data.ctype_m);
22191 					if (isMn || isMc || (typeof(nextCcc) !== 'undefined' && nextCcc !== 0)) {
22192 						if (isMc) {
22193 							this.spacingCombining = true;
22194 						}
22195 						ch += this.nextChar;
22196 						this.nextChar = undefined;
22197 					} else {
22198 						// found the next starter. See if this can be composed with the previous starter
22199 						var testChar = GlyphString._compose(composed, this.nextChar);
22200 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
22201 							// not blocked and there is a mapping 
22202 							composed = testChar;
22203 							ch += this.nextChar;
22204 							this.nextChar = undefined;
22205 						} else {
22206 							// finished iterating, leave this.nextChar for the next next() call 
22207 							notdone = false;
22208 						}
22209 					}
22210 					prevCcc = nextCcc;
22211 				}
22212 			}
22213 			return ch;
22214 		};
22215 		// Returns true if the last character returned by the "next" method included
22216 		// spacing combining characters. If it does, then the character was wider than
22217 		// just the base character alone, and the truncation code will not add it.
22218 		this.wasSpacingCombining = function() {
22219 			return this.spacingCombining;
22220 		};
22221 	};
22222 	return new _chiterator(this);
22223 };
22224 
22225 /**
22226  * Truncate the current string at the given number of whole glyphs and return
22227  * the resulting string.
22228  * 
22229  * @param {number} length the number of whole glyphs to keep in the string
22230  * @return {string} a string truncated to the requested number of glyphs
22231  */
22232 GlyphString.prototype.truncate = function(length) {
22233 	var it = this.charIterator();
22234 	var tr = "";
22235 	for (var i = 0; i < length-1 && it.hasNext(); i++) {
22236 		tr += it.next();
22237 	}
22238 	
22239 	/*
22240 	 * handle the last character separately. If it contains spacing combining
22241 	 * accents, then we must assume that it uses up more horizontal space on
22242 	 * the screen than just the base character by itself, and therefore this
22243 	 * method will not truncate enough characters to fit in the given length.
22244 	 * In this case, we have to chop off not only the combining characters, 
22245 	 * but also the base character as well because the base without the
22246 	 * combining accents is considered a different character.
22247 	 */
22248 	if (i < length && it.hasNext()) {
22249 		var c = it.next();
22250 		if (!it.wasSpacingCombining()) {
22251 			tr += c;
22252 		}
22253 	}
22254 	return tr;
22255 };
22256 
22257 /**
22258  * Truncate the current string at the given number of glyphs and add an ellipsis
22259  * to indicate that is more to the string. The ellipsis forms the last character
22260  * in the string, so the string is actually truncated at length-1 glyphs.
22261  * 
22262  * @param {number} length the number of whole glyphs to keep in the string 
22263  * including the ellipsis
22264  * @return {string} a string truncated to the requested number of glyphs
22265  * with an ellipsis
22266  */
22267 GlyphString.prototype.ellipsize = function(length) {
22268 	return this.truncate(length > 0 ? length-1 : 0) + "…";
22269 };
22270 
22271 
22272 
22273 /*< NormString.js */
22274 /*
22275  * NormString.js - ilib normalized string subclass definition
22276  * 
22277  * Copyright © 2013-2015, JEDLSoft
22278  *
22279  * Licensed under the Apache License, Version 2.0 (the "License");
22280  * you may not use this file except in compliance with the License.
22281  * You may obtain a copy of the License at
22282  *
22283  *     http://www.apache.org/licenses/LICENSE-2.0
22284  *
22285  * Unless required by applicable law or agreed to in writing, software
22286  * distributed under the License is distributed on an "AS IS" BASIS,
22287  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22288  *
22289  * See the License for the specific language governing permissions and
22290  * limitations under the License.
22291  */
22292 
22293 // !depends IString.js GlyphString.js Utils.js
22294 
22295 
22296 
22297 /**
22298  * @class
22299  * Create a new normalized string instance. This string inherits from 
22300  * the GlyphString class, and adds the normalize method. It can be
22301  * used anywhere that a normal Javascript string is used. <p>
22302  * 
22303  * 
22304  * @constructor
22305  * @extends GlyphString
22306  * @param {string|IString=} str initialize this instance with this string 
22307  */
22308 var NormString = function (str) {
22309 	GlyphString.call(this, str);
22310 };
22311 
22312 NormString.prototype = new GlyphString("", {noinstance:true});
22313 NormString.prototype.parent = GlyphString;
22314 NormString.prototype.constructor = NormString;
22315 
22316 /**
22317  * Initialize the normalized string routines statically. This
22318  * is intended to be called in a dynamic-load version of ilib
22319  * to load the data need to normalize strings before any instances
22320  * of NormString are created.<p>
22321  * 
22322  * The options parameter may contain any of the following properties:
22323  * 
22324  * <ul>
22325  * <li><i>form</i> - {string} the normalization form to load
22326  * <li><i>script</i> - {string} load the normalization for this script. If the 
22327  * script is given as "all" then the normalization data for all scripts
22328  * is loaded at the same time
22329  * <li><i>sync</i> - {boolean} whether to load the files synchronously or not
22330  * <li><i>loadParams</i> - {Object} parameters to the loader function
22331  * <li><i>onLoad</i> - {function()} a function to call when the 
22332  * files are done being loaded
22333  * </ul>
22334  * 
22335  * @param {Object} options an object containing properties that govern 
22336  * how to initialize the data
22337  */
22338 NormString.init = function(options) {
22339 	if (!ilib._load || (typeof(ilib._load) !== 'function' && typeof(ilib._load.loadFiles) !== 'function')) {
22340 		// can't do anything
22341 		return;
22342 	}
22343 	var form = "nfkc";
22344 	var script = "all";
22345 	var sync = true;
22346 	var onLoad = undefined;
22347 	var loadParams = undefined;
22348 	if (options) {
22349 		form = options.form || "nfkc";
22350 		script = options.script || "all";
22351 		sync = typeof(options.sync) !== 'undefined' ? options.sync : true;
22352 		onLoad = typeof(options.onLoad) === 'function' ? options.onLoad : undefined;
22353 		if (options.loadParams) {
22354 			loadParams = options.loadParams;
22355 		}
22356 	}
22357 	var formDependencies = {
22358 		"nfd": ["nfd"],
22359 		"nfc": ["nfd"],
22360 		"nfkd": ["nfkd", "nfd"],
22361 		"nfkc": ["nfkd", "nfd"]
22362 	};
22363 	var files = ["normdata.json"];
22364 	var forms = formDependencies[form];
22365 	for (var f in forms) {
22366 		files.push(forms[f] + "/" + script + ".json");
22367 	}
22368 	
22369 	if (JSUtils.isEmpty(ilib.data.norm.ccc) || JSUtils.isEmpty(ilib.data.norm.nfd) || JSUtils.isEmpty(ilib.data.norm.nfkd)) {
22370 		//console.log("loading files " + JSON.stringify(files));
22371 		Utils._callLoadData(files, sync, loadParams, function(arr) {
22372 			ilib.extend(ilib.data.norm, arr[0]);
22373 			for (var i = 1; i < arr.length; i++) {
22374 				if (typeof(arr[i]) !== 'undefined') {
22375 					ilib.extend(ilib.data.norm[forms[i-1]], arr[i]);
22376 				}
22377 			}
22378 			
22379 			if (onLoad) {
22380 				onLoad(arr);
22381 			}
22382 		});
22383 	}
22384 };
22385 
22386 /**
22387  * Algorithmically decompose a precomposed Korean syllabic Hangul 
22388  * character into its individual combining Jamo characters. The given 
22389  * character must be in the range of Hangul characters U+AC00 to U+D7A3.
22390  * 
22391  * @private
22392  * @static
22393  * @param {number} cp code point of a Korean Hangul character to decompose
22394  * @return {string} the decomposed string of Jamo characters
22395  */
22396 NormString._decomposeHangul = function (cp) {
22397 	var sindex = cp - 0xAC00;
22398 	var result = String.fromCharCode(0x1100 + sindex / 588) + 
22399 			String.fromCharCode(0x1161 + (sindex % 588) / 28);
22400 	var t = sindex % 28;
22401 	if (t !== 0) {
22402 		result += String.fromCharCode(0x11A7 + t);
22403 	}
22404 	return result;
22405 };
22406 
22407 /**
22408  * Expand one character according to the given canonical and 
22409  * compatibility mappings.
22410  *
22411  * @private
22412  * @static
22413  * @param {string} ch character to map
22414  * @param {Object} canon the canonical mappings to apply
22415  * @param {Object=} compat the compatibility mappings to apply, or undefined
22416  * if only the canonical mappings are needed
22417  * @return {string} the mapped character
22418  */
22419 NormString._expand = function (ch, canon, compat) {
22420 	var i, 
22421 		expansion = "",
22422 		n = ch.charCodeAt(0);
22423 	if (GlyphString._isHangul(n)) {
22424 		expansion = NormString._decomposeHangul(n);
22425 	} else {
22426 		var result = canon[ch];
22427 		if (!result && compat) {
22428 			result = compat[ch];
22429 		}
22430 		if (result && result !== ch) {
22431 			for (i = 0; i < result.length; i++) {
22432 				expansion += NormString._expand(result[i], canon, compat);
22433 			}
22434 		} else {
22435 			expansion = ch;
22436 		}
22437 	}
22438 	return expansion;
22439 };
22440 
22441 /**
22442  * Perform the Unicode Normalization Algorithm upon the string and return 
22443  * the resulting new string. The current string is not modified.
22444  * 
22445  * <h2>Forms</h2>
22446  * 
22447  * The forms of possible normalizations are defined by the <a 
22448  * href="http://www.unicode.org/reports/tr15/">Unicode Standard
22449  * Annex (UAX) 15</a>. The form parameter is a string that may have one 
22450  * of the following values:
22451  * 
22452  * <ul>
22453  * <li>nfd - Canonical decomposition. This decomposes characters into
22454  * their exactly equivalent forms. For example, "ü" would decompose
22455  * into a "u" followed by the combining diaeresis character. 
22456  * <li>nfc - Canonical decomposition followed by canonical composition.
22457  * This decomposes and then recomposes character into their shortest
22458  * exactly equivalent forms by recomposing as many combining characters
22459  * as possible. For example, "ü" followed by a combining 
22460  * macron character would decompose into a "u" followed by the combining 
22461  * macron characters the combining diaeresis character, and then be recomposed into
22462  * the u with macron and diaeresis "ṻ" character. The reason that
22463  * the "nfc" form decomposes and then recomposes is that combining characters
22464  * have a specific order under the Unicode Normalization Algorithm, and
22465  * partly composed characters such as the "ü" followed by combining
22466  * marks may change the order of the combining marks when decomposed and
22467  * recomposed.
22468  * <li>nfkd - Compatibility decomposition. This decomposes characters
22469  * into compatible forms that may not be exactly equivalent semantically,
22470  * as well as performing canonical decomposition as well.
22471  * For example, the "œ" ligature character decomposes to the two
22472  * characters "oe" because they are compatible even though they are not 
22473  * exactly the same semantically. 
22474  * <li>nfkc - Compatibility decomposition followed by canonical composition.
22475  * This decomposes characters into compatible forms, then recomposes
22476  * characters using the canonical composition. That is, it breaks down
22477  * characters into the compatible forms, and then recombines all combining
22478  * marks it can with their base characters. For example, the character
22479  * "ǽ" would be normalized to "aé" by first decomposing
22480  * the character into "a" followed by "e" followed by the combining acute accent
22481  * combining mark, and then recomposed to an "a" followed by the "e"
22482  * with acute accent.
22483  * </ul>
22484  * 
22485  * <h2>Operation</h2>
22486  * 
22487  * Two strings a and b can be said to be canonically equivalent if 
22488  * normalize(a) = normalize(b)
22489  * under the nfc normalization form. Two strings can be said to be compatible if
22490  * normalize(a) = normalize(b) under the nfkc normalization form.<p>
22491  * 
22492  * The canonical normalization is often used to see if strings are 
22493  * equivalent to each other, and thus is useful when implementing parsing 
22494  * algorithms or exact matching algorithms. It can also be used to ensure
22495  * that any string output produces a predictable sequence of characters.<p>
22496  * 
22497  * Compatibility normalization 
22498  * does not always preserve the semantic meaning of all the characters, 
22499  * although this is sometimes the behaviour that you are after. It is useful, 
22500  * for example, when doing searches of user-input against text in documents 
22501  * where the matches are supposed to "fuzzy". In this case, both the query
22502  * string and the document string would be mapped to their compatibility 
22503  * normalized forms, and then compared.<p>
22504  * 
22505  * Compatibility normalization also does not guarantee round-trip conversion
22506  * to and from legacy character sets as the normalization is "lossy". It is 
22507  * akin to doing a lower- or upper-case conversion on text -- after casing,
22508  * you cannot tell what case each character is in the original string. It is 
22509  * good for matching and searching, but it rarely good for output because some 
22510  * distinctions or meanings in the original text have been lost.<p>
22511  * 
22512  * Note that W3C normalization for HTML also escapes and unescapes
22513  * HTML character entities such as "&uuml;" for u with diaeresis. This
22514  * method does not do such escaping or unescaping. If normalization is required
22515  * for HTML strings with entities, unescaping should be performed on the string 
22516  * prior to calling this method.<p>
22517  * 
22518  * <h2>Data</h2>
22519  * 
22520  * Normalization requires a fair amount of mapping data, much of which you may 
22521  * not need for the characters expected in your texts. It is possible to assemble
22522  * a copy of ilib that saves space by only including normalization data for 
22523  * those scripts that you expect to encounter in your data.<p>
22524  * 
22525  * The normalization data is organized by normalization form and within there
22526  * by script. To include the normalization data for a particular script with
22527  * a particular normalization form, use the directive:
22528  * 
22529  * <pre><code>
22530  * !depends <form>/<script>.js
22531  * </code></pre>
22532  * 
22533  * Where <form> is the normalization form ("nfd", "nfc", "nfkd", or "nfkc"), and
22534  * <script> is the ISO 15924 code for the script you would like to
22535  * support. Example: to load in the NFC data for Cyrillic, you would use:
22536  * 
22537  * <pre><code>
22538  * !depends nfc/Cyrl.js
22539  * </code></pre>
22540  * 
22541  * Note that because certain normalization forms include others in their algorithm, 
22542  * their data also depends on the data for the other forms. For example, if you 
22543  * include the "nfc" data for a script, you will automatically get the "nfd" data 
22544  * for that same script as well because the NFC algorithm does NFD normalization 
22545  * first. Here are the dependencies:<p>
22546  * 
22547  * <ul>
22548  * <li>NFD -> no dependencies
22549  * <li>NFC -> NFD
22550  * <li>NFKD -> NFD
22551  * <li>NFKC -> NFKD, NFD, NFC
22552  * </ul>
22553  * 
22554  * A special value for the script dependency is "all" which will cause the data for 
22555  * all scripts
22556  * to be loaded for that normalization form. This would be useful if you know that
22557  * you are going to normalize a lot of multilingual text or cannot predict which scripts
22558  * will appear in the input. Because the NFKC form depends on all others, you can 
22559  * get all of the data for all forms automatically by depending on "nfkc/all.js".
22560  * Note that the normalization data for practically all script automatically depend
22561  * on data for the Common script (code "Zyyy") which contains all of the characters
22562  * that are commonly used in many different scripts. Examples of characters in the
22563  * Common script are the ASCII punctuation characters, or the ASCII Arabic 
22564  * numerals "0" through "9".<p>
22565  * 
22566  * By default, none of the data for normalization is automatically 
22567  * included in the preassembled iliball.js file. 
22568  * If you would like to normalize strings, you must assemble
22569  * your own copy of ilib and explicitly include the normalization data
22570  * for those scripts as per the instructions above. This normalization method will 
22571  * produce output, even without the normalization data. However, the output will be 
22572  * simply the same thing as its input for all scripts 
22573  * except Korean Hangul and Jamo, which are decomposed and recomposed 
22574  * algorithmically and therefore do not rely on data.<p>
22575  * 
22576  * If characters are encountered for which there are no normalization data, they
22577  * will be passed through to the output string unmodified.
22578  * 
22579  * @param {string} form The normalization form requested
22580  * @return {IString} a new instance of an IString that has been normalized
22581  * according to the requested form. The current instance is not modified.
22582  */
22583 NormString.prototype.normalize = function (form) {
22584 	var i;
22585 	
22586 	if (typeof(form) !== 'string' || this.str.length === 0) {
22587 		return new IString(this.str);
22588 	}
22589 	
22590 	var nfc = false,
22591 		nfkd = false;
22592 	
22593 	switch (form) {
22594 	default:
22595 		break;
22596 		
22597 	case "nfc":
22598 		nfc = true;
22599 		break;
22600 		
22601 	case "nfkd":
22602 		nfkd = true;
22603 		break;
22604 		
22605 	case "nfkc":
22606 		nfkd = true;
22607 		nfc = true;
22608 		break;
22609 	}
22610 
22611 	// decompose
22612 	var decomp = "";
22613 	
22614 	if (nfkd) {
22615 		var ch, it = IString.prototype.charIterator.call(this);
22616 		while (it.hasNext()) {
22617 			ch = it.next();
22618 			decomp += NormString._expand(ch, ilib.data.norm.nfd, ilib.data.norm.nfkd);
22619 		}
22620 	} else {
22621 		var ch, it = IString.prototype.charIterator.call(this);
22622 		while (it.hasNext()) {
22623 			ch = it.next();
22624 			decomp += NormString._expand(ch, ilib.data.norm.nfd);
22625 		}
22626 	}
22627 
22628 	// now put the combining marks in a fixed order by 
22629 	// sorting on the combining class
22630 	function compareByCCC(left, right) {
22631 		return ilib.data.norm.ccc[left] - ilib.data.norm.ccc[right]; 
22632 	}
22633 	
22634 	function ccc(c) {
22635 		return ilib.data.norm.ccc[c] || 0;
22636 	}
22637 
22638 	function sortChars(arr, comp) {
22639 		// qt/qml's Javascript engine re-arranges entries that are equal to
22640 		// each other. Technically, that is a correct behaviour, but it is
22641 		// not desirable. All the other engines leave equivalent entries
22642 		// where they are. This bubblesort emulates what the other engines
22643 		// do. Fortunately, the arrays we are sorting are a max of 5 or 6
22644 		// entries, so performance is not a big deal here.
22645 		if (ilib._getPlatform() === "qt") {
22646 			var tmp;
22647 			for (var i = arr.length-1; i > 0; i--) {
22648 				for (var j = 0; j < i; j++) {
22649 					if (comp(arr[j], arr[j+1]) > 0) {
22650 						tmp = arr[j];
22651 						arr[j] = arr[j+1];
22652 						arr[j+1] = tmp;
22653 					}
22654 				}
22655 			}
22656 			return arr;
22657 		} else {
22658 			return arr.sort(comp);
22659 		}
22660 	}
22661 		
22662 	var dstr = new IString(decomp);
22663 	var it = dstr.charIterator();
22664 	var cpArray = [];
22665 
22666 	// easier to deal with as an array of chars
22667 	while (it.hasNext()) {
22668 		cpArray.push(it.next());
22669 	}
22670 	
22671 	i = 0;
22672 	while (i < cpArray.length) {
22673 		if (typeof(ilib.data.norm.ccc[cpArray[i]]) !== 'undefined' && ccc(cpArray[i]) !== 0) {
22674 			// found a non-starter... rearrange all the non-starters until the next starter
22675 			var end = i+1;
22676 			while (end < cpArray.length &&
22677 					typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
22678 					ccc(cpArray[end]) !== 0) {
22679 				end++;
22680 			}
22681 			
22682 			// simple sort of the non-starter chars
22683 			if (end - i > 1) {
22684 				cpArray = cpArray.slice(0,i).concat(sortChars(cpArray.slice(i, end), compareByCCC), cpArray.slice(end));
22685 			}
22686 		}
22687 		i++;
22688 	}
22689 	
22690 	if (nfc) {
22691 		i = 0;
22692 		while (i < cpArray.length) {
22693 			if (typeof(ilib.data.norm.ccc[cpArray[i]]) === 'undefined' || ilib.data.norm.ccc[cpArray[i]] === 0) {
22694 				// found a starter... find all the non-starters until the next starter. Must include
22695 				// the next starter because under some odd circumstances, two starters sometimes recompose 
22696 				// together to form another character
22697 				var end = i+1;
22698 				var notdone = true;
22699 				while (end < cpArray.length && notdone) {
22700 					if (typeof(ilib.data.norm.ccc[cpArray[end]]) !== 'undefined' && 
22701 						ilib.data.norm.ccc[cpArray[end]] !== 0) {
22702 						if (ccc(cpArray[end-1]) < ccc(cpArray[end])) { 
22703 							// not blocked 
22704 							var testChar = GlyphString._compose(cpArray[i], cpArray[end]);
22705 							if (typeof(testChar) !== 'undefined') {
22706 								cpArray[i] = testChar;
22707 								
22708 								// delete the combining char
22709 								cpArray.splice(end,1);	
22710 								
22711 								// restart the iteration, just in case there is more to recompose with the new char
22712 								end = i;
22713 							}
22714 						}
22715 						end++;
22716 					} else {
22717 						// found the next starter. See if this can be composed with the previous starter
22718 						var testChar = GlyphString._compose(cpArray[i], cpArray[end]);
22719 						if (ccc(cpArray[end-1]) === 0 && typeof(testChar) !== 'undefined') { 
22720 							// not blocked and there is a mapping 
22721 							cpArray[i] = testChar;
22722 							
22723 							// delete the combining char
22724 							cpArray.splice(end,1);
22725 							
22726 							// restart the iteration, just in case there is more to recompose with the new char
22727 							end = i+1;
22728 						} else {
22729 							// finished iterating 
22730 							notdone = false;
22731 						}
22732 					}
22733 				}
22734 			}
22735 			i++;
22736 		}
22737 	}
22738 	
22739 	return new IString(cpArray.length > 0 ? cpArray.join("") : "");
22740 };
22741 	
22742 /**
22743  * @override
22744  * Return an iterator that will step through all of the characters
22745  * in the string one at a time, taking care to step through decomposed 
22746  * characters and through surrogate pairs in UTF-16 encoding 
22747  * properly. <p>
22748  * 
22749  * The NormString class will return decomposed Unicode characters
22750  * as a single unit that a user might see on the screen. If the 
22751  * next character in the iteration is a base character and it is 
22752  * followed by combining characters, the base and all its following 
22753  * combining characters are returned as a single unit.<p>
22754  * 
22755  * The standard Javascript String's charAt() method only
22756  * returns information about a particular 16-bit character in the 
22757  * UTF-16 encoding scheme.
22758  * If the index is pointing to a low- or high-surrogate character,
22759  * it will return that surrogate character rather 
22760  * than the surrogate pair which represents a character 
22761  * in the supplementary planes.<p>
22762  * 
22763  * The iterator instance returned has two methods, hasNext() which
22764  * returns true if the iterator has more characters to iterate through,
22765  * and next() which returns the next character.<p>
22766  * 
22767  * @return {Object} an iterator 
22768  * that iterates through all the characters in the string
22769  */
22770 NormString.prototype.charIterator = function() {
22771 	var it = IString.prototype.charIterator.call(this);
22772 	
22773 	/**
22774 	 * @constructor
22775 	 */
22776 	function _chiterator (istring) {
22777 		/**
22778 		 * @private
22779 		 */
22780 		var ccc = function(c) {
22781 			return ilib.data.norm.ccc[c] || 0;
22782 		};
22783 
22784 		this.index = 0;
22785 		this.hasNext = function () {
22786 			return !!this.nextChar || it.hasNext();
22787 		};
22788 		this.next = function () {
22789 			var ch = this.nextChar || it.next(),
22790 				prevCcc = ccc(ch),
22791 				nextCcc,
22792 				composed = ch;
22793 			
22794 			this.nextChar = undefined;
22795 			
22796 			if (ilib.data.norm.ccc && 
22797 					(typeof(ilib.data.norm.ccc[ch]) === 'undefined' || ccc(ch) === 0)) {
22798 				// found a starter... find all the non-starters until the next starter. Must include
22799 				// the next starter because under some odd circumstances, two starters sometimes recompose 
22800 				// together to form another character
22801 				var notdone = true;
22802 				while (it.hasNext() && notdone) {
22803 					this.nextChar = it.next();
22804 					nextCcc = ccc(this.nextChar);
22805 					if (typeof(ilib.data.norm.ccc[this.nextChar]) !== 'undefined' && nextCcc !== 0) {
22806 						ch += this.nextChar;
22807 						this.nextChar = undefined;
22808 					} else {
22809 						// found the next starter. See if this can be composed with the previous starter
22810 						var testChar = GlyphString._compose(composed, this.nextChar);
22811 						if (prevCcc === 0 && typeof(testChar) !== 'undefined') { 
22812 							// not blocked and there is a mapping 
22813 							composed = testChar;
22814 							ch += this.nextChar;
22815 							this.nextChar = undefined;
22816 						} else {
22817 							// finished iterating, leave this.nextChar for the next next() call 
22818 							notdone = false;
22819 						}
22820 					}
22821 					prevCcc = nextCcc;
22822 				}
22823 			}
22824 			return ch;
22825 		};
22826 	};
22827 	return new _chiterator(this);
22828 };
22829 
22830 
22831 /*< CodePointSource.js */
22832 /*
22833  * CodePointSource.js - Source of code points from a string
22834  * 
22835  * Copyright © 2013-2015, JEDLSoft
22836  *
22837  * Licensed under the Apache License, Version 2.0 (the "License");
22838  * you may not use this file except in compliance with the License.
22839  * You may obtain a copy of the License at
22840  *
22841  *     http://www.apache.org/licenses/LICENSE-2.0
22842  *
22843  * Unless required by applicable law or agreed to in writing, software
22844  * distributed under the License is distributed on an "AS IS" BASIS,
22845  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22846  *
22847  * See the License for the specific language governing permissions and
22848  * limitations under the License.
22849  */
22850 
22851 // !depends isPunct.js NormString.js
22852 
22853 
22854 /**
22855  * @class
22856  * Represents a buffered source of code points. The input string is first
22857  * normalized so that combining characters come out in a standardized order.
22858  * If the "ignorePunctuation" flag is turned on, then punctuation 
22859  * characters are skipped.
22860  * 
22861  * @constructor
22862  * @private
22863  * @param {NormString|string} str a string to get code points from
22864  * @param {boolean} ignorePunctuation whether or not to ignore punctuation
22865  * characters
22866  */
22867 var CodePointSource = function(str, ignorePunctuation) {
22868 	this.chars = [];
22869 	// first convert the string to a normalized sequence of characters
22870 	var s = (typeof(str) === "string") ? new NormString(str) : str;
22871 	this.it = s.charIterator();
22872 	this.ignorePunctuation = typeof(ignorePunctuation) === "boolean" && ignorePunctuation;
22873 };
22874 
22875 /**
22876  * Return the first num code points in the source without advancing the
22877  * source pointer. If there are not enough code points left in the
22878  * string to satisfy the request, this method will return undefined. 
22879  * 
22880  * @param {number} num the number of characters to peek ahead
22881  * @return {string|undefined} a string formed out of up to num code points from
22882  * the start of the string, or undefined if there are not enough character left
22883  * in the source to complete the request
22884  */
22885 CodePointSource.prototype.peek = function(num) {
22886 	if (num < 1) {
22887 		return undefined;
22888 	}
22889 	if (this.chars.length < num && this.it.hasNext()) {
22890 		for (var i = 0; this.chars.length < 4 && this.it.hasNext(); i++) {
22891 			var c = this.it.next();
22892 			if (c && !this.ignorePunctuation || !isPunct(c)) {
22893 				this.chars.push(c);
22894 			}
22895 		}
22896 	}
22897 	if (this.chars.length < num) {
22898 		return undefined;
22899 	}
22900 	return this.chars.slice(0, num).join("");
22901 };
22902 /**
22903  * Advance the source pointer by the given number of code points.
22904  * @param {number} num number of code points to advance
22905  */
22906 CodePointSource.prototype.consume = function(num) {
22907 	if (num > 0) {
22908 		this.peek(num); // for the iterator to go forward if needed
22909 		if (num < this.chars.length) {
22910 			this.chars = this.chars.slice(num);
22911 		} else {
22912 			this.chars = [];
22913 		}
22914 	}
22915 };
22916 
22917 
22918 
22919 /*< ElementIterator.js */
22920 /*
22921  * ElementIterator.js - Iterate through a list of collation elements
22922  * 
22923  * Copyright © 2013-2015, JEDLSoft
22924  *
22925  * Licensed under the Apache License, Version 2.0 (the "License");
22926  * you may not use this file except in compliance with the License.
22927  * You may obtain a copy of the License at
22928  *
22929  *     http://www.apache.org/licenses/LICENSE-2.0
22930  *
22931  * Unless required by applicable law or agreed to in writing, software
22932  * distributed under the License is distributed on an "AS IS" BASIS,
22933  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22934  *
22935  * See the License for the specific language governing permissions and
22936  * limitations under the License.
22937  */
22938 
22939 /**
22940  * @class
22941  * An iterator through a sequence of collation elements. This
22942  * iterator takes a source of code points, converts them into
22943  * collation elements, and allows the caller to get single
22944  * elements at a time.
22945  * 
22946  * @constructor
22947  * @private
22948  * @param {CodePointSource} source source of code points to 
22949  * convert to collation elements
22950  * @param {Object} map mapping from sequences of code points to
22951  * collation elements
22952  * @param {number} keysize size in bits of the collation elements
22953  */
22954 var ElementIterator = function (source, map, keysize) {
22955 	this.elements = [];
22956 	this.source = source;
22957 	this.map = map;
22958 	this.keysize = keysize;
22959 };
22960 
22961 /**
22962  * @private
22963  */
22964 ElementIterator.prototype._fillBuffer = function () {
22965 	var str = undefined;
22966 	
22967 	// peek ahead by up to 4 characters, which may combine
22968 	// into 1 or more collation elements
22969 	for (var i = 4; i > 0; i--) {
22970 		str = this.source.peek(i);
22971 		if (str && this.map[str]) {
22972 			this.elements = this.elements.concat(this.map[str]);
22973 			this.source.consume(i);
22974 			return;
22975 		}
22976 	}
22977 	
22978 	if (str) {
22979 		// no mappings for the first code point, so just use its
22980 		// Unicode code point as a proxy for its sort order. Shift
22981 		// it by the key size so that everything unknown sorts
22982 		// after things that have mappings
22983 		this.elements.push(str.charCodeAt(0) << this.keysize);
22984 		this.source.consume(1);
22985 	} else {
22986 		// end of the string
22987 		return undefined;
22988 	}
22989 };
22990 
22991 /**
22992  * Return true if there are more collation elements left to
22993  * iterate through.
22994  * @returns {boolean} true if there are more elements left to
22995  * iterate through, and false otherwise
22996  */
22997 ElementIterator.prototype.hasNext = function () {
22998 	if (this.elements.length < 1) {
22999 		this._fillBuffer();
23000 	}
23001 	return !!this.elements.length;
23002 };
23003 
23004 /**
23005  * Return the next collation element. If more than one collation 
23006  * element is generated from a sequence of code points 
23007  * (ie. an "expansion"), then this class will buffer the
23008  * other elements and return them on subsequent calls to 
23009  * this method.
23010  * 
23011  * @returns {number|undefined} the next collation element or
23012  * undefined for no more collation elements
23013  */
23014 ElementIterator.prototype.next = function () {
23015 	if (this.elements.length < 1) {
23016 		this._fillBuffer();
23017 	}
23018 	var ret = this.elements[0];
23019 	this.elements = this.elements.slice(1);
23020 	return ret;
23021 };
23022 
23023 
23024 
23025 /*< Collator.js */
23026 /*
23027  * Collator.js - Collation routines
23028  * 
23029  * Copyright © 2013-2015, JEDLSoft
23030  *
23031  * Licensed under the Apache License, Version 2.0 (the "License");
23032  * you may not use this file except in compliance with the License.
23033  * You may obtain a copy of the License at
23034  *
23035  *     http://www.apache.org/licenses/LICENSE-2.0
23036  *
23037  * Unless required by applicable law or agreed to in writing, software
23038  * distributed under the License is distributed on an "AS IS" BASIS,
23039  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23040  *
23041  * See the License for the specific language governing permissions and
23042  * limitations under the License.
23043  */
23044 
23045 /* !depends 
23046 Locale.js 
23047 ilib.js 
23048 INumber.js 
23049 isPunct.js 
23050 NormString.js 
23051 MathUtils.js 
23052 Utils.js 
23053 LocaleInfo.js 
23054 CodePointSource.js
23055 ElementIterator.js
23056 */
23057 
23058 // !data collation
23059 
23060 
23061 /**
23062  * @class
23063  * A class that implements a locale-sensitive comparator function 
23064  * for use with sorting function. The comparator function
23065  * assumes that the strings it is comparing contain Unicode characters
23066  * encoded in UTF-16.<p>
23067  * 
23068  * Collations usually depend only on the language, because most collation orders 
23069  * are shared between locales that speak the same language. There are, however, a
23070  * number of instances where a locale collates differently than other locales
23071  * that share the same language. There are also a number of instances where a
23072  * locale collates differently based on the script used. This object can handle
23073  * these cases automatically if a full locale is specified in the options rather
23074  * than just a language code.<p>
23075  * 
23076  * <h2>Options</h2>
23077  * 
23078  * The options parameter can contain any of the following properties:
23079  * 
23080  * <ul>
23081  * <li><i>locale</i> - String|Locale. The locale which the comparator function 
23082  * will collate with. Default: the current iLib locale.
23083  * 
23084  * <li><i>sensitivity</i> - String. Sensitivity or strength of collator. This is one of 
23085  * "primary", "base", "secondary", "accent", "tertiary", "case", "quaternary", or 
23086  * "variant". Default: "primary"
23087  *   <ol>
23088  *   <li>base or primary - Only the primary distinctions between characters are significant.
23089  *   Another way of saying that is that the collator will be case-, accent-, and 
23090  *   variation-insensitive, and only distinguish between the base characters
23091  *   <li>case or secondary - Both the primary and secondary distinctions between characters
23092  *   are significant. That is, the collator will be accent- and variation-insensitive
23093  *   and will distinguish between base characters and character case.
23094  *   <li>accent or tertiary - The primary, secondary, and tertiary distinctions between
23095  *   characters are all significant. That is, the collator will be 
23096  *   variation-insensitive, but accent-, case-, and base-character-sensitive. 
23097  *   <li>variant or quaternary - All distinctions between characters are significant. That is,
23098  *   the algorithm is base character-, case-, accent-, and variation-sensitive.
23099  *   </ol>
23100  *   
23101  * <li><i>upperFirst</i> - boolean. When collating case-sensitively in a script that
23102  * has the concept of case, put upper-case
23103  * characters first, otherwise lower-case will come first. Warning: some browsers do
23104  * not implement this feature or at least do not implement it properly, so if you are 
23105  * using the native collator with this option, you may get different results in different
23106  * browsers. To guarantee the same results, set useNative to false to use the ilib 
23107  * collator implementation. This of course will be somewhat slower, but more 
23108  * predictable. Default: true
23109  * 
23110  * <li><i>reverse</i> - boolean. Return the list sorted in reverse order. When the
23111  * upperFirst option is also set to true, upper-case characters would then come at 
23112  * the end of the list. Default: false.
23113  * 
23114  * <li><i>scriptOrder</i> - string. When collating strings in multiple scripts,
23115  * this property specifies what order those scripts should be sorted. The default
23116  * Unicode Collation Algorithm (UCA) already has a default order for scripts, but
23117  * this can be tailored via this property. The value of this option is a 
23118  * space-separated list of ISO 15924 scripts codes. If a code is specified in this
23119  * property, its default data must be included using the JS assembly tool. If the
23120  * data is not included, the ordering for the script will be ignored. Default:
23121  * the default order defined by the UCA. 
23122  * 
23123  * <li><i>style</i> - The value of the style parameter is dependent on the locale.
23124  * For some locales, there are different styles of collating strings depending
23125  * on what kind of strings are being collated or what the preference of the user 
23126  * is. For example, in German, there is a phonebook order and a dictionary ordering
23127  * that sort the same array of strings slightly differently.
23128  * The static method {@link Collator#getAvailableStyles} will return a list of styles that ilib
23129  * currently knows about for any given locale. If the value of the style option is 
23130  * not recognized for a locale, it will be ignored. Default style is "standard".<p>
23131  * 
23132  * <li><i>usage</i> - Whether this collator will be used for searching or sorting.
23133  * Valid values are simply the strings "sort" or "search". When used for sorting,
23134  * it is good idea if a collator produces a stable sort. That is, the order of the 
23135  * sorted array of strings should not depend on the order of the strings in the
23136  * input array. As such, when a collator is supposed to act case insensitively, 
23137  * it nonetheless still distinguishes between case after all other criteria
23138  * are satisfied so that strings that are distinguished only by case do not sort
23139  * randomly. For searching, we would like to match two strings that different only 
23140  * by case, so the collator must return equals in that situation instead of 
23141  * further distinguishing by case. Default is "sort".
23142  * 
23143  * <li><i>numeric</i> - Treat the left and right strings as if they started with
23144  * numbers and sort them numerically rather than lexically.
23145  * 
23146  * <li><i>ignorePunctuation</i> - Skip punctuation characters when comparing the
23147  * strings.
23148  *  
23149  * <li>onLoad - a callback function to call when the collator object is fully 
23150  * loaded. When the onLoad option is given, the collator object will attempt to
23151  * load any missing locale data using the ilib loader callback.
23152  * When the constructor is done (even if the data is already preassembled), the 
23153  * onLoad function is called with the current instance as a parameter, so this
23154  * callback can be used with preassembled or dynamic loading or a mix of the two.
23155  * 
23156  * <li>sync - tell whether to load any missing locale data synchronously or 
23157  * asynchronously. If this option is given as "false", then the "onLoad"
23158  * callback must be given, as the instance returned from this constructor will
23159  * not be usable for a while. 
23160  *
23161  * <li><i>loadParams</i> - an object containing parameters to pass to the 
23162  * loader callback function when locale data is missing. The parameters are not
23163  * interpretted or modified in any way. They are simply passed along. The object 
23164  * may contain any property/value pairs as long as the calling code is in
23165  * agreement with the loader callback function as to what those parameters mean.
23166  * 
23167  * <li><i>useNative</i> - when this option is true, use the native Intl object
23168  * provided by the Javascript engine, if it exists, to implement this class. If
23169  * it doesn't exist, or if this parameter is false, then this class uses a pure 
23170  * Javascript implementation, which is slower and uses a lot more memory, but 
23171  * works everywhere that ilib works. Default is "true".
23172  * </ul>
23173  * 
23174  * <h2>Operation</h2>
23175  * 
23176  * The Collator constructor returns a collator object tailored with the above 
23177  * options. The object contains an internal compare() method which compares two 
23178  * strings according to those options. This can be used directly to compare
23179  * two strings, but is not useful for passing to the javascript sort function
23180  * because then it will not have its collation data available. Instead, use the 
23181  * getComparator() method to retrieve a function that is bound to the collator
23182  * object. (You could also bind it yourself using ilib.bind()). The bound function 
23183  * can be used with the standard Javascript array sorting algorithm, or as a 
23184  * comparator with your own sorting algorithm.<p>
23185  * 
23186  * Example using the standard Javascript array sorting call with the bound
23187  * function:<p>
23188  * 
23189  * <code>
23190  * <pre>
23191  * var arr = ["ö", "oe", "ü", "o", "a", "ae", "u", "ß", "ä"];
23192  * var collator = new Collator({locale: 'de-DE', style: "dictionary"});
23193  * arr.sort(collator.getComparator());
23194  * console.log(JSON.stringify(arr));
23195  * </pre>
23196  * </code>
23197  * <p>
23198  * 
23199  * Would give the output:<p>
23200  * 
23201  * <code>
23202  * <pre>
23203  * ["a", "ae", "ä", "o", "oe", "ö", "ß", "u", "ü"]
23204  * </pre>
23205  * </code>
23206  * 
23207  * When sorting an array of Javascript objects according to one of the 
23208  * string properties of the objects, wrap the collator's compare function 
23209  * in your own comparator function that knows the structure of the objects
23210  * being sorted:<p>
23211  * 
23212  * <code>
23213  * <pre>
23214  * var collator = new Collator({locale: 'de-DE'});
23215  * var myComparator = function (collator) {
23216  *   var comparator = collator.getComparator();
23217  *   // left and right are your own objects
23218  *   return function (left, right) {
23219  *   	return comparator(left.x.y.textProperty, right.x.y.textProperty);
23220  *   };
23221  * };
23222  * arr.sort(myComparator(collator));
23223  * </pre>
23224  * </code>
23225  * <p>
23226  * 
23227  * <h2>Sort Keys</h2>
23228  * 
23229  * The collator class also has a method to retrieve the sort key for a
23230  * string. The sort key is an array of values that represent how each  
23231  * character in the string should be collated according to the characteristics
23232  * of the collation algorithm and the given options. Thus, sort keys can be 
23233  * compared directly value-for-value with other sort keys that were generated 
23234  * by the same collator, and the resulting ordering is guaranteed to be the 
23235  * same as if the original strings were compared by the collator.
23236  * Sort keys generated by different collators are not guaranteed to give
23237  * any reasonable results when compared together unless the two collators 
23238  * were constructed with 
23239  * exactly the same options and therefore end up representing the exact same 
23240  * collation sequence.<p>
23241  * 
23242  * A good rule of thumb is that you would use a sort key if you had 10 or more
23243  * items to sort or if your array might be resorted arbitrarily. For example, if your 
23244  * user interface was displaying a table with 100 rows in it, and each row had
23245  * 4 sortable text columns which could be sorted in acending or descending order,
23246  * the recommended practice would be to generate a sort key for each of the 4
23247  * sortable fields in each row and store that in the Javascript representation of the
23248  * table data. Then, when the user clicks on a column header to resort the
23249  * table according to that column, the resorting would be relatively quick 
23250  * because it would only be comparing arrays of values, and not recalculating 
23251  * the collation values for each character in each string for every comparison.<p>
23252  * 
23253  * For tables that are large, it is usually a better idea to do the sorting
23254  * on the server side, especially if the table is the result of a database
23255  * query. In this case, the table is usually a view of the cursor of a large
23256  * results set, and only a few entries are sent to the front end at a time.
23257  * In order to sort the set efficiently, it should be done on the database
23258  * level instead.
23259  * 
23260  * <h2>Data</h2>
23261  * 
23262  * Doing correct collation entails a huge amount of mapping data, much of which is
23263  * not necessary when collating in one language with one script, which is the most
23264  * common case. Thus, ilib implements a number of ways to include the data you
23265  * need or leave out the data you don't need using the JS assembly tool:
23266  * 
23267  * <ol>
23268  * <li>Full multilingual data - if you are sorting multilingual data and need to collate 
23269  * text written in multiple scripts, you can use the directive "!data collation/ducet" to 
23270  * load in the full collation data.  This allows the collator to perform the entire 
23271  * Unicode Collation Algorithm (UCA) based on the Default Unicode Collation Element 
23272  * Table (DUCET). The data is very large, on the order of multiple megabytes, but 
23273  * sometimes it is necessary.
23274  * <li>A few scripts - if you are sorting text written in only a few scripts, you may 
23275  * want to include only the data for those scripts. Each ISO 15924 script code has its
23276  * own data available in a separate file, so you can use the data directive to include
23277  * only the data for the scripts you need. For example, use  
23278  * "!data collation/Latn" to retrieve the collation information for the Latin script.
23279  * Because the "ducet" table mentioned in the previous point is a superset of the 
23280  * tables for all other scripts, you do not need to include explicitly the data for 
23281  * any particular script when using "ducet". That is, you either include "ducet" or 
23282  * you include a specific list of scripts.
23283  * <li>Only one script - if you are sorting text written only in one script, you can
23284  * either include the data directly as in the previous point, or you can rely on the 
23285  * locale to include the correct data for you. In this case, you can use the directive
23286  * "!data collate" to load in the locale's collation data for its most common script.
23287  * </ol>
23288  *   
23289  * With any of the above ways of including the data, the collator will only perform the
23290  * correct language-sensitive sorting for the given locale. All other scripts will be
23291  * sorted in the default manner according to the UCA. For example, if you include the
23292  * "ducet" data and pass in "de-DE" (German for Germany) as the locale spec, then
23293  * only the Latin script (the default script for German) will be sorted according to
23294  * German rules. All other scripts in the DUCET, such as Japanese or Arabic, will use 
23295  * the default UCA collation rules.<p>
23296  * 
23297  * If this collator encounters a character for which it has no collation data, it will
23298  * sort those characters by pure Unicode value after all characters for which it does have
23299  * collation data. For example, if you only loaded in the German collation data (ie. the
23300  * data for the Latin script tailored to German) to sort a list of person names, but that
23301  * list happens to include the names of a few Japanese people written in Japanese 
23302  * characters, the Japanese names will sort at the end of the list after all German names,
23303  * and will sort according to the Unicode values of the characters.
23304  * 
23305  * @constructor
23306  * @param {Object} options options governing how the resulting comparator 
23307  * function will operate
23308  */
23309 var Collator = function(options) {
23310 	var sync = true,
23311 		loadParams = undefined,
23312 		useNative = true;
23313 
23314 	// defaults
23315 	/** 
23316 	 * @private
23317 	 * @type {Locale} 
23318 	 */
23319 	this.locale = new Locale(ilib.getLocale());
23320 	
23321 	/** @private */
23322 	this.caseFirst = "upper";
23323 	/** @private */
23324 	this.sensitivity = "variant";
23325 	/** @private */
23326 	this.level = 4;
23327 	/** @private */
23328 	this.usage = "sort";
23329 	/** @private */
23330 	this.reverse = false;
23331 	/** @private */
23332 	this.numeric = false;
23333 	/** @private */
23334 	this.style = "default";
23335 	/** @private */
23336 	this.ignorePunctuation = false;
23337 	
23338 	if (options) {
23339 		if (options.locale) {
23340 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
23341 		}
23342 		if (options.sensitivity) {
23343 			switch (options.sensitivity) {
23344 				case 'primary':
23345 				case 'base':
23346 					this.sensitivity = "base";
23347 					this.level = 1;
23348 					break;
23349 				case 'secondary':
23350 				case 'accent':
23351 					this.sensitivity = "accent";
23352 					this.level = 2;
23353 					break;
23354 				case 'tertiary':
23355 				case 'case':
23356 					this.sensitivity = "case";
23357 					this.level = 3;
23358 					break;
23359 				case 'quaternary':
23360 				case 'variant':
23361 					this.sensitivity = "variant";
23362 					this.level = 4;
23363 					break;
23364 			}
23365 		}
23366 		if (typeof(options.upperFirst) !== 'undefined') {
23367 			this.caseFirst = options.upperFirst ? "upper" : "lower"; 
23368 		}
23369 		
23370 		if (typeof(options.ignorePunctuation) !== 'undefined') {
23371 			this.ignorePunctuation = options.ignorePunctuation;
23372 		}
23373 		if (typeof(options.sync) !== 'undefined') {
23374 			sync = (options.sync == true);
23375 		}
23376 		
23377 		loadParams = options.loadParams;
23378 		if (typeof(options.useNative) !== 'undefined') {
23379 			useNative = options.useNative;
23380 		}
23381 		
23382 		if (options.usage === "sort" || options.usage === "search") {
23383 			this.usage = options.usage;
23384 		}
23385 		
23386 		if (typeof(options.reverse) === 'boolean') {
23387 			this.reverse = options.reverse;
23388 		}
23389 
23390 		if (typeof(options.numeric) === 'boolean') {
23391 			this.numeric = options.numeric;
23392 		}
23393 		
23394 		if (typeof(options.style) === 'string') {
23395 			this.style = options.style;
23396 		}
23397 	}
23398 
23399 	if (this.usage === "sort") {
23400 		// produces a stable sort
23401 		this.level = 4;
23402 	}
23403 
23404 	if (useNative && typeof(Intl) !== 'undefined' && Intl) {
23405 		// this engine is modern and supports the new Intl object!
23406 		//console.log("implemented natively");
23407 		/** 
23408 		 * @private
23409 		 * @type {{compare:function(string,string)}} 
23410 		 */
23411 		this.collator = new Intl.Collator(this.locale.getSpec(), this);
23412 		
23413 		if (options && typeof(options.onLoad) === 'function') {
23414 			options.onLoad(this);
23415 		}
23416 	} else {
23417 		//console.log("implemented in pure JS");
23418 		if (!Collator.cache) {
23419 			Collator.cache = {};
23420 		}
23421 
23422 		// else implement in pure Javascript
23423 		Utils.loadData({
23424 			object: Collator, 
23425 			locale: this.locale, 
23426 			name: "collation.json",
23427 			sync: sync,
23428 			loadParams: loadParams, 
23429 			callback: ilib.bind(this, function (collation) {
23430 				if (!collation) {
23431 					collation = ilib.data.collation;
23432 					var spec = this.locale.getSpec().replace(/-/g, '_');
23433 					Collator.cache[spec] = collation;
23434 				}
23435 				this._init(collation);
23436 				new LocaleInfo(this.locale, {
23437 					sync: sync,
23438 					loadParams: loadParams,
23439 					onLoad: ilib.bind(this, function(li) {
23440 						this.li = li;
23441 						if (this.ignorePunctuation) {
23442 			    			isPunct._init(sync, loadParams, ilib.bind(this, function() {
23443 								if (options && typeof(options.onLoad) === 'function') {
23444 									options.onLoad(this);
23445 								}
23446 			    			}));
23447 		    			} else {
23448 							if (options && typeof(options.onLoad) === 'function') {
23449 								options.onLoad(this);
23450 							}
23451 		    			}
23452 		    		})
23453 				});
23454 			})
23455 		});
23456 	}
23457 };
23458 
23459 Collator.prototype = {
23460 	/**
23461 	 * @private
23462 	 * Bit pack an array of values into a single number
23463 	 * @param {number|null|Array.<number>} arr array of values to bit pack
23464 	 * @param {number} offset offset for the start of this map
23465 	 */
23466 	_pack: function (arr, offset) {
23467 		var value = 0;
23468 		if (arr) {
23469 			if (typeof(arr) === 'number') {
23470 				arr = [ arr ];
23471 			}
23472 			for (var i = 0; i < this.level; i++) {
23473 				var thisLevel = (typeof(arr[i]) !== "undefined" ? arr[i] : 0);
23474 				if (i === 0) {
23475 					thisLevel += offset;
23476 				}
23477 				if (i > 0) {
23478 					value <<= this.collation.bits[i];	
23479 				}
23480 				if (i === 2 && this.caseFirst === "lower") {
23481 					// sort the lower case first instead of upper
23482 					value = value | (1 - thisLevel);
23483 				} else {
23484 					value = value | thisLevel;
23485 				}
23486 			}
23487 		}
23488 		return value;
23489 	},
23490 	
23491 	/**
23492 	 * @private
23493 	 * Return the rule packed into an array of collation elements.
23494 	 * @param {Array.<number|null|Array.<number>>} rule
23495 	 * @param {number} offset
23496 	 * @return {Array.<number>} a bit-packed array of numbers
23497 	 */
23498 	_packRule: function(rule, offset) {
23499 		if (ilib.isArray(rule[0])) {
23500 			var ret = [];
23501 			for (var i = 0; i < rule.length; i++) {
23502 				ret.push(this._pack(rule[i], offset));
23503 			}
23504 			return ret;
23505 		} else {
23506 			return [ this._pack(rule, offset) ];
23507 		}
23508 	},
23509     
23510 	/**
23511 	 * @private
23512 	 */
23513 	_addChars: function (str, offset) {
23514 		var gs = new GlyphString(str);
23515 		var it = gs.charIterator();
23516 		var c;
23517 		
23518 		while (it.hasNext()) {
23519 			c = it.next();
23520 			if (c === "'") {
23521 				// escape a sequence of chars as one collation element
23522 				c = "";
23523 				var x = "";
23524 				while (it.hasNext() && x !== "'") {
23525 					c += x;
23526 					x = it.next();
23527 				}
23528 			}
23529 			this.lastMap++;
23530 			this.map[c] = this._packRule([this.lastMap], offset);
23531 		}
23532 	},
23533 	
23534 	/**
23535 	 * @private
23536 	 */
23537 	_addRules: function(rules, start) {
23538 		var p;
23539     	for (var r in rules.map) {
23540     		if (r) {
23541     			this.map[r] = this._packRule(rules.map[r], start);
23542     			p = typeof(rules.map[r][0]) === 'number' ? rules.map[r][0] : rules.map[r][0][0]; 
23543     			this.lastMap = Math.max(p + start, this.lastMap);
23544     		}
23545     	}
23546     	
23547     	if (typeof(rules.ranges) !== 'undefined') {
23548     		// for each range, everything in the range goes in primary sequence from the start
23549     		for (var i = 0; i < rules.ranges.length; i++) {
23550     			var range = rules.ranges[i];
23551     			
23552     			this.lastMap = range.start;
23553     			if (typeof(range.chars) === "string") {
23554     				this._addChars(range.chars, start);
23555     			} else {
23556     				for (var k = 0; k < range.chars.length; k++) {
23557     					this._addChars(range.chars[k], start);
23558     				}
23559     			}
23560     		}
23561     	}
23562 	},
23563 	
23564 	/**
23565      * @private
23566      */
23567     _init: function(rules) {
23568     	var rule = this.style;
23569     	while (typeof(rule) === 'string') {
23570     		rule = rules[rule];
23571     	}
23572     	if (!rule) {
23573     		rule = "default";
23574         	while (typeof(rule) === 'string') {
23575         		rule = rules[rule];
23576         	}
23577     	}
23578     	if (!rule) {
23579     		this.map = {};
23580     		return;
23581     	}
23582     	
23583     	/** 
23584     	 * @private
23585     	 * @type {{scripts:Array.<string>,bits:Array.<number>,maxes:Array.<number>,bases:Array.<number>,map:Object.<string,Array.<number|null|Array.<number>>>}}
23586     	 */
23587     	this.collation = rule;
23588     	this.map = {};
23589     	this.lastMap = -1;
23590     	this.keysize = this.collation.keysize[this.level-1];
23591     	
23592     	if (typeof(this.collation.inherit) !== 'undefined') {
23593     		for (var i = 0; i < this.collation.inherit.length; i++) {
23594     			var col = this.collation.inherit[i];
23595     			rule = typeof(col) === 'object' ? col.name : col;
23596     			if (rules[rule]) {
23597     				this._addRules(rules[rule], col.start || this.lastMap+1);
23598     			}
23599     		}
23600     	}
23601     	this._addRules(this.collation, this.lastMap+1);
23602     },
23603     
23604     /**
23605      * @private
23606      */
23607     _basicCompare: function(left, right) {
23608 		var l = (left instanceof NormString) ? left : new NormString(left),
23609 			r = (right instanceof NormString) ? right : new NormString(right),
23610 			lchar, 
23611 			rchar,
23612 			lelements,
23613 			relements;
23614 		
23615 		if (this.numeric) {
23616 			var lvalue = new INumber(left, {locale: this.locale});
23617 			var rvalue = new INumber(right, {locale: this.locale});
23618 			if (!isNaN(lvalue.valueOf()) && !isNaN(rvalue.valueOf())) {
23619 				var diff = lvalue.valueOf() - rvalue.valueOf();
23620 				if (diff) {
23621 					return diff;
23622 				} else {
23623 					// skip the numeric part and compare the rest lexically
23624 					l = new NormString(left.substring(lvalue.parsed.length));
23625 					r = new NormString(right.substring(rvalue.parsed.length));
23626 				}
23627 			}
23628 			// else if they aren't both numbers, then let the code below take care of the lexical comparison instead
23629 		}
23630 			
23631 		lelements = new ElementIterator(new CodePointSource(l, this.ignorePunctuation), this.map, this.keysize);
23632 		relements = new ElementIterator(new CodePointSource(r, this.ignorePunctuation), this.map, this.keysize);
23633 		
23634 		while (lelements.hasNext() && relements.hasNext()) {
23635 			var diff = lelements.next() - relements.next();
23636 			if (diff) {
23637 				return diff;
23638 			}
23639 		}
23640 		if (!lelements.hasNext() && !relements.hasNext()) {
23641 			return 0;
23642 		} else if (lelements.hasNext()) {
23643 			return 1;
23644 		} else {
23645 			return -1;
23646 		}
23647     },
23648     
23649 	/**
23650 	 * Compare two strings together according to the rules of this 
23651 	 * collator instance. Do not use this function directly with 
23652 	 * Array.sort, as it will not have its collation data available
23653 	 * and therefore will not function properly. Use the function
23654 	 * returned by getComparator() instead.
23655 	 * 
23656 	 * @param {string} left the left string to compare
23657 	 * @param {string} right the right string to compare
23658 	 * @return {number} a negative number if left comes before right, a
23659 	 * positive number if right comes before left, and zero if left and 
23660 	 * right are equivalent according to this collator
23661 	 */
23662 	compare: function (left, right) {
23663 		// last resort: use the "C" locale
23664 		if (this.collator) {
23665 			// implemented by the core engine
23666 			return this.collator.compare(left, right);
23667 		}
23668 
23669 		var ret = this._basicCompare(left, right);
23670 		return this.reverse ? -ret : ret;
23671 	},
23672 	
23673 	/**
23674 	 * Return a comparator function that can compare two strings together
23675 	 * according to the rules of this collator instance. The function 
23676 	 * returns a negative number if the left 
23677 	 * string comes before right, a positive number if the right string comes 
23678 	 * before the left, and zero if left and right are equivalent. If the
23679 	 * reverse property was given as true to the collator constructor, this 
23680 	 * function will
23681 	 * switch the sign of those values to cause sorting to happen in the
23682 	 * reverse order.
23683 	 * 
23684 	 * @return {function(...)|undefined} a comparator function that 
23685 	 * can compare two strings together according to the rules of this 
23686 	 * collator instance
23687 	 */
23688 	getComparator: function() {
23689 		// bind the function to this instance so that we have the collation
23690 		// rules available to do the work
23691 		if (this.collator) {
23692 			// implemented by the core engine
23693 			return this.collator.compare;
23694 		}
23695 		
23696 		return /** @type function(string,string):number */ ilib.bind(this, this.compare);
23697 	},
23698 	
23699 	/**
23700 	 * Return a sort key string for the given string. The sort key
23701 	 * string is a list of values that represent each character 
23702 	 * in the original string. The sort key
23703 	 * values for any particular character consists of 3 numbers that
23704 	 * encode the primary, secondary, and tertiary characteristics
23705 	 * of that character. The values of each characteristic are 
23706 	 * modified according to the strength of this collator instance 
23707 	 * to give the correct collation order. The idea is that this
23708 	 * sort key string is directly comparable byte-for-byte to 
23709 	 * other sort key strings generated by this collator without
23710 	 * any further knowledge of the collation rules for the locale.
23711 	 * More formally, if a < b according to the rules of this collation, 
23712 	 * then it is guaranteed that sortkey(a) < sortkey(b) when compared
23713 	 * byte-for-byte. The sort key string can therefore be used
23714 	 * without the collator to sort an array of strings efficiently
23715 	 * because the work of determining the applicability of various
23716 	 * collation rules is done once up-front when generating 
23717 	 * the sort key.<p>
23718 	 * 
23719 	 * The sort key string can be treated as a regular, albeit somewhat
23720 	 * odd-looking, string. That is, it can be pass to regular 
23721 	 * Javascript functions without problems.  
23722 	 * 
23723 	 * @param {string} str the original string to generate the sort key for
23724 	 * @return {string} a sort key string for the given string
23725 	 */
23726 	sortKey: function (str) {
23727 		if (!str) {
23728 			return "";
23729 		}
23730 		
23731 		if (this.collator) {
23732 			// native, no sort keys available
23733 			return str;
23734 		}
23735 		
23736 		function pad(str, limit) {
23737 			return "0000000000000000".substring(0, limit - str.length) + str;
23738 		}
23739 		
23740 		if (this.numeric) {
23741 			var v = new INumber(str, {locale: this.locale});
23742 			var s = isNaN(v.valueOf()) ? "" : v.valueOf().toString(16);
23743 			return pad(s, 16);	
23744 		} else {
23745 			var n = (typeof(str) === "string") ? new NormString(str) : str,
23746 				ret = "",
23747 				lelements = new ElementIterator(new CodePointSource(n, this.ignorePunctuation), this.map, this.keysize),
23748 				element;
23749 			
23750 			while (lelements.hasNext()) {
23751 				element = lelements.next();
23752 				if (this.reverse) {
23753 					// for reverse, take the bitwise inverse
23754 					element = (1 << this.keysize) - element;
23755 				}
23756 				ret += pad(element.toString(16), this.keysize/4);	
23757 			}
23758 		}
23759 		return ret;
23760 	}
23761 };
23762 
23763 /**
23764  * Retrieve the list of collation style names that are available for the 
23765  * given locale. This list varies depending on the locale, and depending
23766  * on whether or not the data for that locale was assembled into this copy
23767  * of ilib.
23768  * 
23769  * @param {Locale|string=} locale The locale for which the available
23770  * styles are being sought
23771  * @return Array.<string> an array of style names that are available for
23772  * the given locale
23773  */
23774 Collator.getAvailableStyles = function (locale) {
23775 	return [ "standard" ];
23776 };
23777 
23778 /**
23779  * Retrieve the list of ISO 15924 script codes that are available in this
23780  * copy of ilib. This list varies depending on whether or not the data for 
23781  * various scripts was assembled into this copy of ilib. If the "ducet"
23782  * data is assembled into this copy of ilib, this method will report the
23783  * entire list of scripts as being available. If a collator instance is
23784  * instantiated with a script code that is not on the list returned by this
23785  * function, it will be ignored and text in that script will be sorted by
23786  * numeric Unicode values of the characters.
23787  * 
23788  * @return Array.<string> an array of ISO 15924 script codes that are 
23789  * available
23790  */
23791 Collator.getAvailableScripts = function () {
23792 	return [ "Latn" ];
23793 };
23794 
23795 
23796 
23797 /*< nfd/all.js */
23798 /*
23799  * all.js - include file for normalization data for a particular script
23800  * 
23801  * Copyright © 2013, JEDLSoft
23802  *
23803  * Licensed under the Apache License, Version 2.0 (the "License");
23804  * you may not use this file except in compliance with the License.
23805  * You may obtain a copy of the License at
23806  *
23807  *     http://www.apache.org/licenses/LICENSE-2.0
23808  *
23809  * Unless required by applicable law or agreed to in writing, software
23810  * distributed under the License is distributed on an "AS IS" BASIS,
23811  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23812  *
23813  * See the License for the specific language governing permissions and
23814  * limitations under the License.
23815  */
23816 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
23817 // !data normdata nfd/all
23818 ilib.extend(ilib.data.norm, ilib.data.normdata);
23819 ilib.extend(ilib.data.norm.nfd, ilib.data.nfd_all);
23820 ilib.data.normdata = undefined;
23821 ilib.data.nfd_all = undefined;
23822 /*< nfkd/all.js */
23823 /*
23824  * all.js - include file for normalization data for a particular script
23825  * 
23826  * Copyright © 2013, JEDLSoft
23827  *
23828  * Licensed under the Apache License, Version 2.0 (the "License");
23829  * you may not use this file except in compliance with the License.
23830  * You may obtain a copy of the License at
23831  *
23832  *     http://www.apache.org/licenses/LICENSE-2.0
23833  *
23834  * Unless required by applicable law or agreed to in writing, software
23835  * distributed under the License is distributed on an "AS IS" BASIS,
23836  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23837  *
23838  * See the License for the specific language governing permissions and
23839  * limitations under the License.
23840  */
23841 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
23842 // !depends nfd/all.js
23843 // !data normdata nfkd/all
23844 ilib.extend(ilib.data.norm, ilib.data.normdata);
23845 ilib.extend(ilib.data.norm.nfkd, ilib.data.nfkd_all);
23846 ilib.data.normdata = undefined;
23847 ilib.data.nfkd_all = undefined;
23848 /*< nfkc/all.js */
23849 /*
23850  * all.js - include file for normalization data for a particular script
23851  * 
23852  * Copyright © 2013, JEDLSoft
23853  *
23854  * Licensed under the Apache License, Version 2.0 (the "License");
23855  * you may not use this file except in compliance with the License.
23856  * You may obtain a copy of the License at
23857  *
23858  *     http://www.apache.org/licenses/LICENSE-2.0
23859  *
23860  * Unless required by applicable law or agreed to in writing, software
23861  * distributed under the License is distributed on an "AS IS" BASIS,
23862  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23863  *
23864  * See the License for the specific language governing permissions and
23865  * limitations under the License.
23866  */
23867 /* WARNING: THIS IS A FILE GENERATED BY gennorm.js. DO NOT EDIT BY HAND. */
23868 // !depends nfd/all.js nfkd/all.js
23869 // !data norm
23870 ilib.extend(ilib.data.norm, ilib.data.normdata);
23871 ilib.data.normdata = undefined;
23872 
23873 /*< LocaleMatcher.js */
23874 /*
23875  * LocaleMatcher.js - Locale matcher definition
23876  * 
23877  * Copyright © 2013-2015, JEDLSoft
23878  *
23879  * Licensed under the Apache License, Version 2.0 (the "License");
23880  * you may not use this file except in compliance with the License.
23881  * You may obtain a copy of the License at
23882  *
23883  *     http://www.apache.org/licenses/LICENSE-2.0
23884  *
23885  * Unless required by applicable law or agreed to in writing, software
23886  * distributed under the License is distributed on an "AS IS" BASIS,
23887  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23888  *
23889  * See the License for the specific language governing permissions and
23890  * limitations under the License.
23891  */
23892 
23893 // !depends ilib.js Locale.js Utils.js
23894 // !data likelylocales
23895 
23896 
23897 /**
23898  * @class
23899  * Create a new locale matcher instance. This is used
23900  * to see which locales can be matched with each other in
23901  * various ways.<p>
23902  * 
23903  * The options object may contain any of the following properties:
23904  * 
23905  * <ul>
23906  * <li><i>locale</i> - the locale to match
23907  * 
23908  * <li><i>onLoad</i> - a callback function to call when the locale matcher object is fully 
23909  * loaded. When the onLoad option is given, the locale matcher object will attempt to
23910  * load any missing locale data using the ilib loader callback.
23911  * When the constructor is done (even if the data is already preassembled), the 
23912  * onLoad function is called with the current instance as a parameter, so this
23913  * callback can be used with preassembled or dynamic loading or a mix of the two.
23914  * 
23915  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
23916  * asynchronously. If this option is given as "false", then the "onLoad"
23917  * callback must be given, as the instance returned from this constructor will
23918  * not be usable for a while. 
23919  *
23920  * <li><i>loadParams</i> - an object containing parameters to pass to the 
23921  * loader callback function when locale data is missing. The parameters are not
23922  * interpretted or modified in any way. They are simply passed along. The object 
23923  * may contain any property/value pairs as long as the calling code is in
23924  * agreement with the loader callback function as to what those parameters mean.
23925  * </ul>
23926  * 
23927  * 
23928  * @constructor
23929  * @param {Object} options parameters to initialize this matcher 
23930  */
23931 var LocaleMatcher = function(options) {
23932 	var sync = true,
23933 	    loadParams = undefined;
23934 	
23935 	this.locale = new Locale();
23936 	
23937 	if (options) {
23938 		if (typeof(options.locale) !== 'undefined') {
23939 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
23940 		}
23941 		
23942 		if (typeof(options.sync) !== 'undefined') {
23943 			sync = (options.sync == true);
23944 		}
23945 		
23946 		if (typeof(options.loadParams) !== 'undefined') {
23947 			loadParams = options.loadParams;
23948 		}
23949 	}
23950 
23951 	if (!LocaleMatcher.cache) {
23952 		LocaleMatcher.cache = {};
23953 	}
23954 
23955 	if (typeof(ilib.data.likelylocales) === 'undefined') {
23956 		Utils.loadData({
23957 			object: LocaleMatcher, 
23958 			locale: "-", 
23959 			name: "likelylocales.json", 
23960 			sync: sync, 
23961 			loadParams: loadParams, 
23962 			callback: ilib.bind(this, function (info) {
23963 				if (!info) {
23964 					info = {};
23965 					var spec = this.locale.getSpec().replace(/-/g, "_");
23966 					LocaleMatcher.cache[spec] = info;
23967 				}
23968 				/** @type {Object.<string,string>} */
23969 				this.info = info;
23970 				if (options && typeof(options.onLoad) === 'function') {
23971 					options.onLoad(this);
23972 				}
23973 			})
23974 		});
23975 	} else {
23976 		this.info = /** @type {Object.<string,string>} */ ilib.data.likelylocales;
23977 	}
23978 };
23979 
23980 
23981 LocaleMatcher.prototype = {
23982 	/**
23983 	 * Return the locale used to construct this instance. 
23984 	 * @return {Locale|undefined} the locale for this matcher
23985 	 */
23986 	getLocale: function() {
23987 		return this.locale;
23988 	},
23989 	
23990 	/**
23991 	 * Return an Locale instance that is fully specified based on partial information
23992 	 * given to the constructor of this locale matcher instance. For example, if the locale
23993 	 * spec given to this locale matcher instance is simply "ru" (for the Russian language), 
23994 	 * then it will fill in the missing region and script tags and return a locale with 
23995 	 * the specifier "ru-Cyrl-RU". (ie. Russian language, Cyrillic, Russian Federation).
23996 	 * Any one or two of the language, script, or region parts may be left unspecified,
23997 	 * and the other one or two parts will be filled in automatically. If this
23998 	 * class has no information about the given locale, then the locale of this
23999 	 * locale matcher instance is returned unchanged.
24000 	 * 
24001 	 * @returns {Locale} the most likely completion of the partial locale given
24002 	 * to the constructor of this locale matcher instance
24003 	 */
24004 	getLikelyLocale: function () {
24005 		if (typeof(this.info[this.locale.getSpec()]) === 'undefined') {
24006 			return this.locale;
24007 		}
24008 		
24009 		return new Locale(this.info[this.locale.getSpec()]);
24010 	}
24011 };
24012 
24013 
24014 /*< CaseMapper.js */
24015 /*
24016  * caseMapper.js - define upper- and lower-case mapper
24017  * 
24018  * Copyright © 2014-2015, JEDLSoft
24019  *
24020  * Licensed under the Apache License, Version 2.0 (the "License");
24021  * you may not use this file except in compliance with the License.
24022  * You may obtain a copy of the License at
24023  *
24024  *     http://www.apache.org/licenses/LICENSE-2.0
24025  *
24026  * Unless required by applicable law or agreed to in writing, software
24027  * distributed under the License is distributed on an "AS IS" BASIS,
24028  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24029  *
24030  * See the License for the specific language governing permissions and
24031  * limitations under the License.
24032  */
24033 
24034 // !depends Locale.js IString.js
24035 
24036 
24037 
24038 /**
24039  * @class
24040  * Create a new string mapper instance that maps strings to upper or
24041  * lower case. This mapping will work for any string as characters 
24042  * that have no case will be returned unchanged.<p>
24043  * 
24044  * The options may contain any of the following properties:
24045  * 
24046  * <ul>
24047  * <li><i>locale</i> - locale to use when loading the mapper. Some maps are 
24048  * locale-dependent, and this locale selects the right one. Default if this is
24049  * not specified is the current locale.
24050  * 
24051  * <li><i>direction</i> - "toupper" for upper-casing, or "tolower" for lower-casing.
24052  * Default if not specified is "toupper".
24053  * </ul>
24054  * 
24055  * 
24056  * @constructor
24057  * @param {Object=} options options to initialize this mapper 
24058  */
24059 var CaseMapper = function (options) {
24060 	this.up = true;
24061 	this.locale = new Locale();
24062 	
24063 	if (options) {
24064 		if (typeof(options.locale) !== 'undefined') {
24065 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
24066 		}
24067 		
24068 		this.up = (!options.direction || options.direction === "toupper");
24069 	}
24070 
24071 	this.mapData = this.up ? {
24072 		"ß": "SS",		// German
24073 		'ΐ': 'Ι',		// Greek
24074 		'ά': 'Α',
24075 		'έ': 'Ε',
24076 		'ή': 'Η',
24077 		'ί': 'Ι',
24078 		'ΰ': 'Υ',
24079 		'ϊ': 'Ι',
24080 		'ϋ': 'Υ',
24081 		'ό': 'Ο',
24082 		'ύ': 'Υ',
24083 		'ώ': 'Ω',
24084 		'Ӏ': 'Ӏ',		// Russian and slavic languages
24085 		'ӏ': 'Ӏ'
24086 	} : {
24087 		'Ӏ': 'Ӏ'		// Russian and slavic languages
24088 	};
24089 
24090 	switch (this.locale.getLanguage()) {
24091 		case "az":
24092 		case "tr":
24093 		case "crh":
24094 		case "kk":
24095 		case "krc":
24096 		case "tt":
24097 			var lower = "iı";
24098 			var upper = "İI";
24099 			this._setUpMap(lower, upper);
24100 			break;
24101 		case "fr":
24102 			if (this.up && this.locale.getRegion() !== "CA") {
24103 				this._setUpMap("àáâãäçèéêëìíîïñòóôöùúûü", "AAAAACEEEEIIIINOOOOUUUU");
24104 			}
24105 			break;
24106 	}
24107 	
24108 	if (ilib._getBrowser() === "ie") {
24109 		// IE is missing these mappings for some reason
24110 		if (this.up) {
24111 			this.mapData['ς'] = 'Σ';
24112 		}
24113 		this._setUpMap("ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⳁⳉⳋ", "ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⳀⳈⳊ"); // Coptic
24114 		// Georgian Nuskhuri <-> Asomtavruli
24115 		this._setUpMap("ⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥ", "ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ");	
24116 	}
24117 };
24118 
24119 CaseMapper.prototype = {
24120 	/** 
24121 	 * @private 
24122 	 */
24123 	_charMapper: function(string) {
24124 		if (!string) {
24125 			return string;
24126 		}
24127 		var input = (typeof(string) === 'string') ? new IString(string) : string.toString();
24128 		var ret = "";
24129 		var it = input.charIterator();
24130 		var c;
24131 		
24132 		while (it.hasNext()) {
24133 			c = it.next();
24134 			if (!this.up && c === 'Σ') {
24135 				if (it.hasNext()) {
24136 					c = it.next();
24137 					var code = c.charCodeAt(0);
24138 					// if the next char is not a greek letter, this is the end of the word so use the
24139 					// final form of sigma. Otherwise, use the mid-word form.
24140 					ret += ((code < 0x0388 && code !== 0x0386) || code > 0x03CE) ? 'ς' : 'σ';
24141 					ret += c.toLowerCase();
24142 				} else {
24143 					// no next char means this is the end of the word, so use the final form of sigma
24144 					ret += 'ς';
24145 				}
24146 			} else {
24147 				if (this.mapData[c]) {
24148 					ret += this.mapData[c];
24149 				} else {
24150 					ret += this.up ? c.toUpperCase() : c.toLowerCase();
24151 				}
24152 			}
24153 		}
24154 		
24155 		return ret;
24156 	},
24157 
24158 	/** @private */
24159 	_setUpMap: function(lower, upper) {
24160 		var from, to;
24161 		if (this.up) {
24162 			from = lower;
24163 			to = upper;
24164 		} else {
24165 			from = upper;
24166 			to = lower;
24167 		}
24168 		for (var i = 0; i < upper.length; i++) {
24169 			this.mapData[from[i]] = to[i];
24170 		}
24171 	},
24172 
24173 	/**
24174 	 * Return the locale that this mapper was constructed with. 
24175 	 * @returns {Locale} the locale that this mapper was constructed with
24176 	 */
24177 	getLocale: function () {
24178 		return this.locale;
24179 	},
24180 		
24181 	/**
24182 	 * Map a string to lower case in a locale-sensitive manner.
24183 	 * 
24184 	 * @param {string|undefined} string
24185 	 * @return {string|undefined}
24186 	 */
24187 	map: function (string) {
24188 		return this._charMapper(string);
24189 	}
24190 };
24191 
24192 
24193 /*< NumberingPlan.js */
24194 /*
24195  * NumPlan.js - Represent a phone numbering plan.
24196  * 
24197  * Copyright © 2014-2015, JEDLSoft
24198  *
24199  * Licensed under the Apache License, Version 2.0 (the "License");
24200  * you may not use this file except in compliance with the License.
24201  * You may obtain a copy of the License at
24202  *
24203  *     http://www.apache.org/licenses/LICENSE-2.0
24204  *
24205  * Unless required by applicable law or agreed to in writing, software
24206  * distributed under the License is distributed on an "AS IS" BASIS,
24207  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24208  *
24209  * See the License for the specific language governing permissions and
24210  * limitations under the License.
24211  */
24212 
24213 /*
24214 !depends 
24215 ilib.js 
24216 Locale.js 
24217 Utils.js
24218 JSUtils.js
24219 */
24220 
24221 // !data numplan
24222 
24223 
24224 /**
24225  * @class
24226  * Create a numbering plan information instance for a particular country's plan.<p>
24227  * 
24228  * The options may contain any of the following properties:
24229  * 
24230  * <ul>
24231  * <li><i>locale</i> - locale for which the numbering plan is sought. This locale
24232  * will be mapped to the actual numbering plan, which may be shared amongst a
24233  * number of countries.
24234  *
24235  * <li>onLoad - a callback function to call when the date format object is fully 
24236  * loaded. When the onLoad option is given, the DateFmt object will attempt to
24237  * load any missing locale data using the ilib loader callback.
24238  * When the constructor is done (even if the data is already preassembled), the 
24239  * onLoad function is called with the current instance as a parameter, so this
24240  * callback can be used with preassembled or dynamic loading or a mix of the two.
24241  * 
24242  * <li>sync - tell whether to load any missing locale data synchronously or 
24243  * asynchronously. If this option is given as "false", then the "onLoad"
24244  * callback must be given, as the instance returned from this constructor will
24245  * not be usable for a while.
24246  *  
24247  * <li><i>loadParams</i> - an object containing parameters to pass to the 
24248  * loader callback function when locale data is missing. The parameters are not
24249  * interpretted or modified in any way. They are simply passed along. The object 
24250  * may contain any property/value pairs as long as the calling code is in
24251  * agreement with the loader callback function as to what those parameters mean.
24252  * </ul>
24253  * 
24254  * @private
24255  * @constructor
24256  * @param {Object} options options governing the way this plan is loaded
24257  */
24258 var NumberingPlan = function (options) {
24259 	var sync = true,
24260 	    loadParams = {};
24261 	
24262 	this.locale = new Locale();
24263 
24264 	if (options) {
24265 		if (options.locale) {
24266 			this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
24267 		}
24268 		
24269 		if (typeof(options.sync) !== 'undefined') {
24270 			sync = (options.sync == true);
24271 		}
24272 		
24273 		if (options.loadParams) {
24274 			loadParams = options.loadParams;
24275 		}
24276 	}	
24277 
24278 	Utils.loadData({
24279 		name: "numplan.json",
24280 		object: NumberingPlan,
24281 		locale: this.locale,
24282 		sync: sync, 
24283 		loadParams: loadParams, 
24284 		callback: ilib.bind(this, function (npdata) {
24285 			if (!npdata) {
24286 				npdata = {
24287 					"region": "XX",
24288 					"skipTrunk": false,
24289 					"trunkCode": "0",
24290 					"iddCode": "00",
24291 					"dialingPlan": "closed",
24292 					"commonFormatChars": " ()-./",
24293 					"fieldLengths": {
24294 						"areaCode": 0,
24295 						"cic": 0,
24296 						"mobilePrefix": 0,
24297 						"serviceCode": 0
24298 					}
24299 				};
24300 			}
24301 
24302 			/** 
24303 			 * @type {{
24304 			 *   region:string,
24305 			 *   skipTrunk:boolean,
24306 			 *   trunkCode:string,
24307 			 *   iddCode:string,
24308 			 *   dialingPlan:string,
24309 			 *   commonFormatChars:string,
24310 			 *   fieldLengths:Object.<string,number>,
24311 			 *   contextFree:boolean,
24312 			 *   findExtensions:boolean,
24313 			 *   trunkRequired:boolean,
24314 			 *   extendedAreaCodes:boolean
24315 			 * }}
24316 			 */
24317 			this.npdata = npdata;
24318 			if (options && typeof(options.onLoad) === 'function') {
24319 				options.onLoad(this);
24320 			}
24321 		})
24322 	});
24323 };
24324 
24325 NumberingPlan.prototype = {
24326 	/**
24327 	 * Return the name of this plan. This may be different than the 
24328 	 * name of the region because sometimes multiple countries share 
24329 	 * the same plan.
24330 	 * @return {string} the name of the plan
24331 	 */
24332 	getName: function() {
24333 		return this.npdata.region;
24334 	},
24335 
24336 	/**
24337 	 * Return the trunk code of the current plan as a string.
24338 	 * @return {string|undefined} the trunk code of the plan or
24339 	 * undefined if there is no trunk code in this plan
24340 	 */
24341 	getTrunkCode: function() {
24342 		return this.npdata.trunkCode;
24343 	},
24344 	
24345 	/**
24346 	 * Return the international direct dialing code of this plan.
24347 	 * @return {string} the IDD code of this plan
24348 	 */
24349 	getIDDCode: function() {
24350 		return this.npdata.iddCode;	
24351 	},
24352 	
24353 	/**
24354 	 * Return the plan style for this plan. The plan style may be
24355 	 * one of:
24356 	 * 
24357 	 * <ul>
24358 	 * <li>"open" - area codes may be left off if the caller is 
24359 	 * dialing to another number within the same area code
24360 	 * <li>"closed" - the area code must always be specified, even
24361 	 * if calling another number within the same area code
24362 	 * </ul>
24363 	 * 
24364 	 * @return {string} the plan style, "open" or "closed"
24365 	 */
24366 	getPlanStyle: function() {	
24367 		return this.npdata.dialingPlan;
24368 	},
24369 	/** [Need Comment]
24370 	 * Return a contextFree
24371 	 *
24372 	 * @return {boolean}
24373 	 */
24374 	getContextFree: function() {
24375 		return this.npdata.contextFree;
24376 	},
24377 	/** [Need Comment]
24378 	 * Return a findExtensions
24379 	 * 
24380 	 * @return {boolean}
24381 	 */
24382 	getFindExtensions: function() {
24383 		return this.npdata.findExtensions;
24384 	},
24385 	/** [Need Comment]
24386 	 * Return a skipTrunk
24387 	 * 
24388 	 * @return {boolean}
24389 	 */
24390 	getSkipTrunk: function() {
24391 		return this.npdata.skipTrunk;
24392 	},
24393 	/** [Need Comment]
24394 	 * Return a skipTrunk
24395 	 * 
24396 	 * @return {boolean}
24397 	 */
24398 	getTrunkRequired: function() {
24399 		return this.npdata.trunkRequired;
24400 	},
24401 	/**
24402 	 * Return true if this plan uses extended area codes.
24403 	 * @return {boolean} true if the plan uses extended area codes
24404 	 */
24405 	getExtendedAreaCode: function() {
24406 		return this.npdata.extendedAreaCodes;
24407 	},
24408 	/**
24409 	 * Return a string containing all of the common format characters
24410 	 * used to format numbers.
24411 	 * @return {string} the common format characters fused in this locale
24412 	 */
24413 	getCommonFormatChars: function() {
24414 		return this.npdata.commonFormatChars;
24415 	},
24416 	
24417 	/**
24418 	 * Return the length of the field with the given name. If the length
24419 	 * is returned as 0, this means it is variable length.
24420 	 * 
24421 	 * @param {string} field name of the field for which the length is 
24422 	 * being sought
24423 	 * @return {number} if positive, this gives the length of the given 
24424 	 * field. If zero, the field is variable length. If negative, the
24425 	 * field is not known.
24426 	 */
24427 	getFieldLength: function (field) {
24428 		var dataField = this.npdata.fieldLengths;
24429 		
24430 		return dataField[field];
24431 	}
24432 };
24433 
24434 
24435 /*< PhoneLocale.js */
24436 /*
24437  * phoneloc.js - Represent a phone locale object.
24438  * 
24439  * Copyright © 2014-2015, JEDLSoft
24440  *
24441  * Licensed under the Apache License, Version 2.0 (the "License");
24442  * you may not use this file except in compliance with the License.
24443  * You may obtain a copy of the License at
24444  *
24445  *     http://www.apache.org/licenses/LICENSE-2.0
24446  *
24447  * Unless required by applicable law or agreed to in writing, software
24448  * distributed under the License is distributed on an "AS IS" BASIS,
24449  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24450  *
24451  * See the License for the specific language governing permissions and
24452  * limitations under the License.
24453  */
24454 
24455 /*
24456 !depends 
24457 ilib.js 
24458 Locale.js
24459 Utils.js
24460 */
24461 
24462 // !data phoneloc
24463 
24464 
24465 /**
24466  * @class
24467  * Extension of the locale class that has extra methods to map various numbers
24468  * related to phone number parsing.
24469  *
24470  * @param {Object} options Options that govern how this phone locale works
24471  * 
24472  * @private
24473  * @constructor
24474  * @extends Locale
24475  */
24476 var PhoneLocale = function(options) {
24477 	var region,
24478 		mcc,
24479 		cc,
24480 		sync = true,
24481 		loadParams = {},
24482 		locale;
24483 	
24484 	locale = (options && options.locale) || ilib.getLocale();
24485 
24486 	this.parent.call(this, locale);
24487 	
24488 	region = this.region;
24489 	
24490 	if (options) {
24491 		if (typeof(options.mcc) !== 'undefined') {
24492 			mcc = options.mcc;
24493 		}
24494 		
24495 		if (typeof(options.countryCode) !== 'undefined') {
24496 			cc = options.countryCode;
24497 		}
24498 
24499 		if (typeof(options.sync) !== 'undefined') {
24500 			sync = (options.sync == true);
24501 		}
24502 		
24503 		if (options.loadParams) {
24504 			loadParams = options.loadParams;
24505 		}
24506 	}
24507 
24508 	Utils.loadData({
24509 		name: "phoneloc.json",
24510 		object: PhoneLocale,
24511 		nonlocale: true,
24512 		sync: sync, 
24513 		loadParams: loadParams, 
24514 		callback: ilib.bind(this, function (data) {
24515 			/** @type {{mcc2reg:Object.<string,string>,cc2reg:Object.<string,string>,reg2cc:Object.<string,string>,area2reg:Object.<string,string>}} */
24516 			this.mappings = data;
24517 			
24518 			if (typeof(mcc) !== 'undefined') {
24519 				region = this.mappings.mcc2reg[mcc];	
24520 			}
24521 
24522 			if (typeof(cc) !== 'undefined') {
24523 				region = this.mappings.cc2reg[cc];
24524 			}
24525 
24526 			if (!region) {
24527 				region = "XX";
24528 			}
24529 
24530 			this.region = this._normPhoneReg(region);
24531 			this._genSpec();
24532 
24533 			if (options && typeof(options.onLoad) === 'function') {
24534 				options.onLoad(this);
24535 			}									
24536 		})
24537 	});
24538 };
24539 
24540 PhoneLocale.prototype = new Locale();
24541 PhoneLocale.prototype.parent = Locale;
24542 PhoneLocale.prototype.constructor = PhoneLocale;
24543 
24544 /**
24545  * Map a mobile carrier code to a region code.
24546  *
24547  * @static
24548  * @package
24549  * @param {string|undefined} mcc the MCC to map
24550  * @return {string|undefined} the region code
24551  */
24552 
24553 PhoneLocale.prototype._mapMCCtoRegion = function(mcc) {
24554 	if (!mcc) {
24555 		return undefined;
24556 	}
24557 	return this.mappings.mcc2reg && this.mappings.mcc2reg[mcc] || "XX";
24558 };
24559 
24560 /**
24561  * Map a country code to a region code.
24562  *
24563  * @static
24564  * @package
24565  * @param {string|undefined} cc the country code to map
24566  * @return {string|undefined} the region code
24567  */
24568 PhoneLocale.prototype._mapCCtoRegion = function(cc) {
24569 	if (!cc) {
24570 		return undefined;
24571 	}
24572 	return this.mappings.cc2reg && this.mappings.cc2reg[cc] || "XX";
24573 };
24574 
24575 /**
24576  * Map a region code to a country code.
24577  *
24578  * @static
24579  * @package
24580  * @param {string|undefined} region the region code to map
24581  * @return {string|undefined} the country code
24582  */
24583 PhoneLocale.prototype._mapRegiontoCC = function(region) {
24584 	if (!region) {
24585 		return undefined;
24586 	}
24587 	return this.mappings.reg2cc && this.mappings.reg2cc[region] || "0";
24588 };
24589 
24590 /**
24591  * Map a country code to a region code.
24592  *
24593  * @static
24594  * @package
24595  * @param {string|undefined} cc the country code to map
24596  * @param {string|undefined} area the area code within the country code's numbering plan
24597  * @return {string|undefined} the region code
24598  */
24599 PhoneLocale.prototype._mapAreatoRegion = function(cc, area) {
24600 	if (!cc) {
24601 		return undefined;
24602 	}
24603 	if (cc in this.mappings.area2reg) {
24604 		return this.mappings.area2reg[cc][area] || this.mappings.area2reg[cc]["default"];
24605 	} else {
24606 		return this.mappings.cc2reg[cc];
24607 	}
24608 };
24609 
24610 /**
24611  * Return the region that controls the dialing plan in the given
24612  * region. (ie. the "normalized phone region".)
24613  * 
24614  * @static
24615  * @package
24616  * @param {string} region the region code to normalize
24617  * @return {string} the normalized region code
24618  */
24619 PhoneLocale.prototype._normPhoneReg = function(region) {
24620 	var norm;
24621 	
24622 	// Map all NANP regions to the right region, so that they get parsed using the 
24623 	// correct state table
24624 	switch (region) {
24625 		case "US": // usa
24626 		case "CA": // canada
24627 		case "AG": // antigua and barbuda
24628 		case "BS": // bahamas
24629 		case "BB": // barbados
24630 		case "DM": // dominica
24631 		case "DO": // dominican republic
24632 		case "GD": // grenada
24633 		case "JM": // jamaica
24634 		case "KN": // st. kitts and nevis
24635 		case "LC": // st. lucia
24636 		case "VC": // st. vincent and the grenadines
24637 		case "TT": // trinidad and tobago
24638 		case "AI": // anguilla
24639 		case "BM": // bermuda
24640 		case "VG": // british virgin islands
24641 		case "KY": // cayman islands
24642 		case "MS": // montserrat
24643 		case "TC": // turks and caicos
24644 		case "AS": // American Samoa 
24645 		case "VI": // Virgin Islands, U.S.
24646 		case "PR": // Puerto Rico
24647 		case "MP": // Northern Mariana Islands
24648 		case "T:": // East Timor
24649 		case "GU": // Guam
24650 			norm = "US";
24651 			break;
24652 		
24653 		// these all use the Italian dialling plan
24654 		case "IT": // italy
24655 		case "SM": // san marino
24656 		case "VA": // vatican city
24657 			norm = "IT";
24658 			break;
24659 		
24660 		// all the French dependencies are on the French dialling plan
24661 		case "FR": // france
24662 		case "GF": // french guiana
24663 		case "MQ": // martinique
24664 		case "GP": // guadeloupe, 
24665 		case "BL": // saint barthélemy
24666 		case "MF": // saint martin
24667 		case "RE": // réunion, mayotte
24668 			norm = "FR";
24669 			break;
24670 		default:
24671 			norm = region;
24672 			break;
24673 	}	
24674 	return norm;
24675 };
24676 
24677 
24678 /*< PhoneHandlerFactory.js */
24679 /*
24680  * handler.js - Handle phone number parse states
24681  * 
24682  * Copyright © 2014-2015, JEDLSoft
24683  *
24684  * Licensed under the Apache License, Version 2.0 (the "License");
24685  * you may not use this file except in compliance with the License.
24686  * You may obtain a copy of the License at
24687  *
24688  *     http://www.apache.org/licenses/LICENSE-2.0
24689  *
24690  * Unless required by applicable law or agreed to in writing, software
24691  * distributed under the License is distributed on an "AS IS" BASIS,
24692  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24693  *
24694  * See the License for the specific language governing permissions and
24695  * limitations under the License.
24696  */
24697 
24698 
24699 /**
24700  * @class
24701  * @private
24702  * @constructor
24703  */
24704 var PhoneHandler = function () {
24705 	return this;
24706 };
24707 
24708 PhoneHandler.prototype = {
24709 	/**
24710 	 * @private
24711 	 * @param {string} number phone number
24712 	 * @param {Object} fields the fields that have been extracted so far
24713 	 * @param {Object} regionSettings settings used to parse the rest of the number
24714 	 */
24715 	processSubscriberNumber: function(number, fields, regionSettings) {
24716 		var last;
24717 		
24718 		last = number.search(/[xwtp,;]/i);	// last digit of the local number
24719 
24720 		if (last > -1) {
24721 			if (last > 0) {
24722 				fields.subscriberNumber = number.substring(0, last);
24723 			}
24724 			// strip x's which are there to indicate a break between the local subscriber number and the extension, but
24725 			// are not themselves a dialable character
24726 			fields.extension = number.substring(last).replace('x', '');
24727 		} else {
24728 			if (number.length) {
24729 				fields.subscriberNumber = number;
24730 			}
24731 		}
24732 		
24733 		if (regionSettings.plan.getFieldLength('maxLocalLength') &&
24734 				fields.subscriberNumber &&
24735 				fields.subscriberNumber.length > regionSettings.plan.getFieldLength('maxLocalLength')) {
24736 			fields.invalid = true;
24737 		}
24738 	},
24739 	/**
24740 	 * @private
24741 	 * @param {string} fieldName 
24742 	 * @param {number} length length of phone number
24743 	 * @param {string} number phone number
24744 	 * @param {number} currentChar currentChar to be parsed
24745 	 * @param {Object} fields the fields that have been extracted so far
24746 	 * @param {Object} regionSettings settings used to parse the rest of the number
24747 	 * @param {boolean} noExtractTrunk 
24748 	 */
24749 	processFieldWithSubscriberNumber: function(fieldName, length, number, currentChar, fields, regionSettings, noExtractTrunk) {
24750 		var ret, end;
24751 		
24752 		if (length !== undefined && length > 0) {
24753 			// fixed length
24754 			end = length;
24755 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
24756 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
24757 			}
24758 		} else {
24759 			// variable length
24760 			// the setting is the negative of the length to add, so subtract to make it positive
24761 			end = currentChar + 1 - length;
24762 		}
24763 		
24764 		if (fields[fieldName] !== undefined) {
24765 			// we have a spurious recognition, because this number already contains that field! So, just put
24766 			// everything into the subscriberNumber as the default
24767 			this.processSubscriberNumber(number, fields, regionSettings);
24768 		} else {
24769 			fields[fieldName] = number.substring(0, end);
24770 			if (number.length > end) {
24771 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
24772 			}
24773 		}
24774 		
24775 		ret = {
24776 			number: ""
24777 		};
24778 
24779 		return ret;
24780 	},
24781 	/**
24782 	 * @private
24783 	 * @param {string} fieldName 
24784 	 * @param {number} length length of phone number
24785 	 * @param {string} number phone number
24786 	 * @param {number} currentChar currentChar to be parsed
24787 	 * @param {Object} fields the fields that have been extracted so far
24788 	 * @param {Object} regionSettings settings used to parse the rest of the number
24789 	 */
24790 	processField: function(fieldName, length, number, currentChar, fields, regionSettings) {
24791 		var ret = {}, end;
24792 		
24793 		if (length !== undefined && length > 0) {
24794 			// fixed length
24795 			end = length;
24796 			if (regionSettings.plan.getTrunkCode() === "0" && number.charAt(0) === "0") {
24797 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
24798 			}
24799 		} else {
24800 			// variable length
24801 			// the setting is the negative of the length to add, so subtract to make it positive
24802 			end = currentChar + 1 - length;
24803 		}
24804 		
24805 		if (fields[fieldName] !== undefined) {
24806 			// we have a spurious recognition, because this number already contains that field! So, just put
24807 			// everything into the subscriberNumber as the default
24808 			this.processSubscriberNumber(number, fields, regionSettings);
24809 			ret.number = "";
24810 		} else {
24811 			fields[fieldName] = number.substring(0, end);			
24812 			ret.number = (number.length > end) ? number.substring(end) : "";
24813 		}
24814 		
24815 		return ret;
24816 	},
24817 	/**
24818 	 * @private
24819 	 * @param {string} number phone number
24820 	 * @param {number} currentChar currentChar to be parsed
24821 	 * @param {Object} fields the fields that have been extracted so far
24822 	 * @param {Object} regionSettings settings used to parse the rest of the number
24823 	 */
24824 	trunk: function(number, currentChar, fields, regionSettings) {
24825 		var ret, trunkLength;
24826 		
24827 		if (fields.trunkAccess !== undefined) {
24828 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
24829 			this.processSubscriberNumber(number, fields, regionSettings);
24830 			number = "";
24831 		} else {
24832 			trunkLength = regionSettings.plan.getTrunkCode().length;
24833 			fields.trunkAccess = number.substring(0, trunkLength);
24834 			number = (number.length > trunkLength) ? number.substring(trunkLength) : "";
24835 		}
24836 		
24837 		ret = {
24838 			number: number
24839 		};
24840 		
24841 		return ret;
24842 	},
24843 	/**
24844 	 * @private
24845 	 * @param {string} number phone number
24846 	 * @param {number} currentChar currentChar to be parsed
24847 	 * @param {Object} fields the fields that have been extracted so far
24848 	 * @param {Object} regionSettings settings used to parse the rest of the number
24849 	 */
24850 	plus: function(number, currentChar, fields, regionSettings) {
24851 		var ret = {};
24852 		
24853 		if (fields.iddPrefix !== undefined) {
24854 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
24855 			this.processSubscriberNumber(number, fields, regionSettings);
24856 			ret.number = "";
24857 		} else {
24858 			// found the idd prefix, so save it and cause the function to parse the next part
24859 			// of the number with the idd table
24860 			fields.iddPrefix = number.substring(0, 1);
24861 	
24862 			ret = {
24863 				number: number.substring(1),
24864 				table: 'idd'    // shared subtable that parses the country code
24865 			};
24866 		}		
24867 		return ret;
24868 	},
24869 	/**
24870 	 * @private
24871 	 * @param {string} number phone number
24872 	 * @param {number} currentChar currentChar to be parsed
24873 	 * @param {Object} fields the fields that have been extracted so far
24874 	 * @param {Object} regionSettings settings used to parse the rest of the number
24875 	 */
24876 	idd: function(number, currentChar, fields, regionSettings) {
24877 		var ret = {};
24878 		
24879 		if (fields.iddPrefix !== undefined) {
24880 			// What? We already have one? Okay, put the rest of this in the subscriber number as the default behaviour then.
24881 			this.processSubscriberNumber(number, fields, regionSettings);
24882 			ret.number = "";
24883 		} else {
24884 			// found the idd prefix, so save it and cause the function to parse the next part
24885 			// of the number with the idd table
24886 			fields.iddPrefix = number.substring(0, currentChar+1);
24887 	
24888 			ret = {
24889 				number: number.substring(currentChar+1),
24890 				table: 'idd'    // shared subtable that parses the country code
24891 			};
24892 		}
24893 		
24894 		return ret;
24895 	},
24896 	/**
24897 	 * @private
24898 	 * @param {string} number phone number
24899 	 * @param {number} currentChar currentChar to be parsed
24900 	 * @param {Object} fields the fields that have been extracted so far
24901 	 * @param {Object} regionSettings settings used to parse the rest of the number
24902 	 */	
24903 	country: function(number, currentChar, fields, regionSettings) {
24904 		var ret, cc;
24905 		
24906 		// found the country code of an IDD number, so save it and cause the function to 
24907 		// parse the rest of the number with the regular table for this locale
24908 		fields.countryCode = number.substring(0, currentChar+1);
24909 		cc = fields.countryCode.replace(/[wWpPtT\+#\*]/g, ''); // fix for NOV-108200
24910 		// console.log("Found country code " + fields.countryCode + ". Switching to country " + locale.region + " to parse the rest of the number");
24911 		
24912 		ret = {
24913 			number: number.substring(currentChar+1),
24914 			countryCode: cc
24915 		};
24916 		
24917 		return ret;
24918 	},
24919 	/**
24920 	 * @private
24921 	 * @param {string} number phone number
24922 	 * @param {number} currentChar currentChar to be parsed
24923 	 * @param {Object} fields the fields that have been extracted so far
24924 	 * @param {Object} regionSettings settings used to parse the rest of the number
24925 	 */
24926 	cic: function(number, currentChar, fields, regionSettings) {
24927 		return this.processField('cic', regionSettings.plan.getFieldLength('cic'), number, currentChar, fields, regionSettings);
24928 	},
24929 	/**
24930 	 * @private
24931 	 * @param {string} number phone number
24932 	 * @param {number} currentChar currentChar to be parsed
24933 	 * @param {Object} fields the fields that have been extracted so far
24934 	 * @param {Object} regionSettings settings used to parse the rest of the number
24935 	 */
24936 	service: function(number, currentChar, fields, regionSettings) {
24937 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('serviceCode'), number, currentChar, fields, regionSettings, false);
24938 	},
24939 	/**
24940 	 * @private
24941 	 * @param {string} number phone number
24942 	 * @param {number} currentChar currentChar to be parsed
24943 	 * @param {Object} fields the fields that have been extracted so far
24944 	 * @param {Object} regionSettings settings used to parse the rest of the number
24945 	 */
24946 	area: function(number, currentChar, fields, regionSettings) {
24947 		var ret, last, end, localLength;
24948 		
24949 		last = number.search(/[xwtp]/i);	// last digit of the local number
24950 		localLength = (last > -1) ? last : number.length;
24951 
24952 		if (regionSettings.plan.getFieldLength('areaCode') > 0) {
24953 			// fixed length
24954 			end = regionSettings.plan.getFieldLength('areaCode');
24955 			if (regionSettings.plan.getTrunkCode() === number.charAt(0)) {
24956 				end += regionSettings.plan.getTrunkCode().length;  // also extract the trunk access code
24957 				localLength -= regionSettings.plan.getTrunkCode().length;
24958 			}
24959 		} else {
24960 			// variable length
24961 			// the setting is the negative of the length to add, so subtract to make it positive
24962 			end = currentChar + 1 - regionSettings.plan.getFieldLength('areaCode');
24963 		}
24964 		
24965 		// substring() extracts the part of the string up to but not including the end character,
24966 		// so add one to compensate
24967 		if (regionSettings.plan.getFieldLength('maxLocalLength') !== undefined) {
24968 			if (fields.trunkAccess !== undefined || fields.mobilePrefix !== undefined ||
24969 					fields.countryCode !== undefined ||
24970 					localLength > regionSettings.plan.getFieldLength('maxLocalLength')) {
24971 				// too long for a local number by itself, or a different final state already parsed out the trunk
24972 				// or mobile prefix, then consider the rest of this number to be an area code + part of the subscriber number
24973 				fields.areaCode = number.substring(0, end);
24974 				if (number.length > end) {
24975 					this.processSubscriberNumber(number.substring(end), fields, regionSettings);
24976 				}
24977 			} else {
24978 				// shorter than the length needed for a local number, so just consider it a local number
24979 				this.processSubscriberNumber(number, fields, regionSettings);
24980 			}
24981 		} else {
24982 			fields.areaCode = number.substring(0, end);
24983 			if (number.length > end) {
24984 				this.processSubscriberNumber(number.substring(end), fields, regionSettings);
24985 			}
24986 		}
24987 		
24988 		// extensions are separated from the number by a dash in Germany
24989 		if (regionSettings.plan.getFindExtensions() !== undefined && fields.subscriberNumber !== undefined) {
24990 			var dash = fields.subscriberNumber.indexOf("-");
24991 			if (dash > -1) {
24992 				fields.subscriberNumber = fields.subscriberNumber.substring(0, dash);
24993 				fields.extension = fields.subscriberNumber.substring(dash+1);
24994 			}
24995 		}
24996 
24997 		ret = {
24998 			number: ""
24999 		};
25000 
25001 		return ret;
25002 	},
25003 	/**
25004 	 * @private
25005 	 * @param {string} number phone number
25006 	 * @param {number} currentChar currentChar to be parsed
25007 	 * @param {Object} fields the fields that have been extracted so far
25008 	 * @param {Object} regionSettings settings used to parse the rest of the number
25009 	 */
25010 	none: function(number, currentChar, fields, regionSettings) {
25011 		var ret;
25012 		
25013 		// this is a last resort function that is called when nothing is recognized.
25014 		// When this happens, just put the whole stripped number into the subscriber number
25015 			
25016 		if (number.length > 0) {
25017 			this.processSubscriberNumber(number, fields, regionSettings);
25018 			if (currentChar > 0 && currentChar < number.length) {
25019 				// if we were part-way through parsing, and we hit an invalid digit,
25020 				// indicate that the number could not be parsed properly
25021 				fields.invalid = true;
25022 			}
25023 		}
25024 		
25025 		ret = {
25026 			number:""
25027 		};
25028 		
25029 		return ret;
25030 	},
25031 	/**
25032 	 * @private
25033 	 * @param {string} number phone number
25034 	 * @param {number} currentChar currentChar to be parsed
25035 	 * @param {Object} fields the fields that have been extracted so far
25036 	 * @param {Object} regionSettings settings used to parse the rest of the number
25037 	 */
25038 	vsc: function(number, currentChar, fields, regionSettings) {
25039 		var ret, length, end;
25040 
25041 		if (fields.vsc === undefined) {
25042 			length = regionSettings.plan.getFieldLength('vsc') || 0;
25043 			if (length !== undefined && length > 0) {
25044 				// fixed length
25045 				end = length;
25046 			} else {
25047 				// variable length
25048 				// the setting is the negative of the length to add, so subtract to make it positive
25049 				end = currentChar + 1 - length;
25050 			}
25051 			
25052 			// found a VSC code (ie. a "star code"), so save it and cause the function to 
25053 			// parse the rest of the number with the same table for this locale
25054 			fields.vsc = number.substring(0, end);
25055 			number = (number.length > end) ? "^" + number.substring(end) : "";
25056 		} else {
25057 			// got it twice??? Okay, this is a bogus number then. Just put everything else into the subscriber number as the default
25058 			this.processSubscriberNumber(number, fields, regionSettings);
25059 			number = "";
25060 		}
25061 
25062 		// treat the rest of the number as if it were a completely new number
25063 		ret = {
25064 			number: number
25065 		};
25066 
25067 		return ret;
25068 	},
25069 	/**
25070 	 * @private
25071 	 * @param {string} number phone number
25072 	 * @param {number} currentChar currentChar to be parsed
25073 	 * @param {Object} fields the fields that have been extracted so far
25074 	 * @param {Object} regionSettings settings used to parse the rest of the number
25075 	 */
25076 	cell: function(number, currentChar, fields, regionSettings) {
25077 		return this.processFieldWithSubscriberNumber('mobilePrefix', regionSettings.plan.getFieldLength('mobilePrefix'), number, currentChar, fields, regionSettings, false);
25078 	},
25079 	/**
25080 	 * @private
25081 	 * @param {string} number phone number
25082 	 * @param {number} currentChar currentChar to be parsed
25083 	 * @param {Object} fields the fields that have been extracted so far
25084 	 * @param {Object} regionSettings settings used to parse the rest of the number
25085 	 */
25086 	personal: function(number, currentChar, fields, regionSettings) {
25087 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('personal'), number, currentChar, fields, regionSettings, false);
25088 	},
25089 	/**
25090 	 * @private
25091 	 * @param {string} number phone number
25092 	 * @param {number} currentChar currentChar to be parsed
25093 	 * @param {Object} fields the fields that have been extracted so far
25094 	 * @param {Object} regionSettings settings used to parse the rest of the number
25095 	 */
25096 	emergency: function(number, currentChar, fields, regionSettings) {
25097 		return this.processFieldWithSubscriberNumber('emergency', regionSettings.plan.getFieldLength('emergency'), number, currentChar, fields, regionSettings, true);
25098 	},
25099 	/**
25100 	 * @private
25101 	 * @param {string} number phone number
25102 	 * @param {number} currentChar currentChar to be parsed
25103 	 * @param {Object} fields the fields that have been extracted so far
25104 	 * @param {Object} regionSettings settings used to parse the rest of the number
25105 	 */
25106 	premium: function(number, currentChar, fields, regionSettings) {
25107 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('premium'), number, currentChar, fields, regionSettings, false);
25108 	},
25109 	/**
25110 	 * @private
25111 	 * @param {string} number phone number
25112 	 * @param {number} currentChar currentChar to be parsed
25113 	 * @param {Object} fields the fields that have been extracted so far
25114 	 * @param {Object} regionSettings settings used to parse the rest of the number
25115 	 */
25116 	special: function(number, currentChar, fields, regionSettings) {
25117 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('special'), number, currentChar, fields, regionSettings, false);
25118 	},
25119 	/**
25120 	 * @private
25121 	 * @param {string} number phone number
25122 	 * @param {number} currentChar currentChar to be parsed
25123 	 * @param {Object} fields the fields that have been extracted so far
25124 	 * @param {Object} regionSettings settings used to parse the rest of the number
25125 	 */
25126 	service2: function(number, currentChar, fields, regionSettings) {
25127 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service2'), number, currentChar, fields, regionSettings, false);
25128 	},
25129 	/**
25130 	 * @private
25131 	 * @param {string} number phone number
25132 	 * @param {number} currentChar currentChar to be parsed
25133 	 * @param {Object} fields the fields that have been extracted so far
25134 	 * @param {Object} regionSettings settings used to parse the rest of the number
25135 	 */
25136 	service3: function(number, currentChar, fields, regionSettings) {
25137 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service3'), number, currentChar, fields, regionSettings, false);
25138 	},
25139 	/**
25140 	 * @private
25141 	 * @param {string} number phone number
25142 	 * @param {number} currentChar currentChar to be parsed
25143 	 * @param {Object} fields the fields that have been extracted so far
25144 	 * @param {Object} regionSettings settings used to parse the rest of the number
25145 	 */
25146 	service4: function(number, currentChar, fields, regionSettings) {
25147 		return this.processFieldWithSubscriberNumber('serviceCode', regionSettings.plan.getFieldLength('service4'), number, currentChar, fields, regionSettings, false);
25148 	},
25149 	/**
25150 	 * @private
25151 	 * @param {string} number phone number
25152 	 * @param {number} currentChar currentChar to be parsed
25153 	 * @param {Object} fields the fields that have been extracted so far
25154 	 * @param {Object} regionSettings settings used to parse the rest of the number
25155 	 */
25156 	cic2: function(number, currentChar, fields, regionSettings) {
25157 		return this.processField('cic', regionSettings.plan.getFieldLength('cic2'), number, currentChar, fields, regionSettings);
25158 	},
25159 	/**
25160 	 * @private
25161 	 * @param {string} number phone number
25162 	 * @param {number} currentChar currentChar to be parsed
25163 	 * @param {Object} fields the fields that have been extracted so far
25164 	 * @param {Object} regionSettings settings used to parse the rest of the number
25165 	 */
25166 	cic3: function(number, currentChar, fields, regionSettings) {
25167 		return this.processField('cic', regionSettings.plan.getFieldLength('cic3'), number, currentChar, fields, regionSettings);
25168 	},
25169 	/**
25170 	 * @private
25171 	 * @param {string} number phone number
25172 	 * @param {number} currentChar currentChar to be parsed
25173 	 * @param {Object} fields the fields that have been extracted so far
25174 	 * @param {Object} regionSettings settings used to parse the rest of the number
25175 	 */
25176 	start: function(number, currentChar, fields, regionSettings) {
25177 		// don't do anything except transition to the next state
25178 		return {
25179 			number: number
25180 		};
25181 	},
25182 	/**
25183 	 * @private
25184 	 * @param {string} number phone number
25185 	 * @param {number} currentChar currentChar to be parsed
25186 	 * @param {Object} fields the fields that have been extracted so far
25187 	 * @param {Object} regionSettings settings used to parse the rest of the number
25188 	 */
25189 	local: function(number, currentChar, fields, regionSettings) {
25190 		// in open dialling plans, we can tell that this number is a local subscriber number because it
25191 		// starts with a digit that indicates as such
25192 		this.processSubscriberNumber(number, fields, regionSettings);
25193 		return {
25194 			number: ""
25195 		};
25196 	}
25197 };
25198 
25199 // context-sensitive handler
25200 /**
25201  * @class
25202  * @private
25203  * @extends PhoneHandler
25204  * @constructor
25205  */
25206 var CSStateHandler = function () {
25207 	return this;
25208 };
25209 
25210 CSStateHandler.prototype = new PhoneHandler();
25211 CSStateHandler.prototype.special = function (number, currentChar, fields, regionSettings) {
25212 	var ret;
25213 	
25214 	// found a special area code that is both a node and a leaf. In
25215 	// this state, we have found the leaf, so chop off the end 
25216 	// character to make it a leaf.
25217 	if (number.charAt(0) === "0") {
25218 		fields.trunkAccess = number.charAt(0);
25219 		fields.areaCode = number.substring(1, currentChar);
25220 	} else {
25221 		fields.areaCode = number.substring(0, currentChar);
25222 	}
25223 	this.processSubscriberNumber(number.substring(currentChar), fields, regionSettings);
25224 	
25225 	ret = {
25226 		number: ""
25227 	};
25228 	
25229 	return ret;
25230 };
25231 
25232 /**
25233  * @class
25234  * @private
25235  * @extends PhoneHandler
25236  * @constructor
25237  */
25238 var USStateHandler = function () {
25239 	return this;
25240 };
25241 
25242 USStateHandler.prototype = new PhoneHandler();
25243 USStateHandler.prototype.vsc = function (number, currentChar, fields, regionSettings) {
25244 	var ret;
25245 
25246 	// found a VSC code (ie. a "star code")
25247 	fields.vsc = number;
25248 
25249 	// treat the rest of the number as if it were a completely new number
25250 	ret = {
25251 		number: ""
25252 	};
25253 
25254 	return ret;
25255 };
25256 
25257 /**
25258  * Creates a phone handler instance that is correct for the locale. Phone handlers are
25259  * used to handle parsing of the various fields in a phone number.
25260  * 
25261  * @protected
25262  * @static
25263  * @return {PhoneHandler} the correct phone handler for the locale
25264  */
25265 var PhoneHandlerFactory = function (locale, plan) {
25266 	if (plan.getContextFree() !== undefined && typeof(plan.getContextFree()) === 'boolean' && plan.getContextFree() === false) {
25267 		return new CSStateHandler();
25268 	}
25269 	var region = (locale && locale.getRegion()) || "ZZ";
25270 	switch (region) {
25271 	case 'US':
25272 		return new USStateHandler();
25273 		break;
25274 	default:
25275 		return new PhoneHandler();
25276 	}
25277 };
25278 
25279 
25280 /*< PhoneNumber.js */
25281 /*
25282  * phonenum.js - Represent a phone number.
25283  * 
25284  * Copyright © 2014-2015, JEDLSoft
25285  *
25286  * Licensed under the Apache License, Version 2.0 (the "License");
25287  * you may not use this file except in compliance with the License.
25288  * You may obtain a copy of the License at
25289  *
25290  *     http://www.apache.org/licenses/LICENSE-2.0
25291  *
25292  * Unless required by applicable law or agreed to in writing, software
25293  * distributed under the License is distributed on an "AS IS" BASIS,
25294  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25295  *
25296  * See the License for the specific language governing permissions and
25297  * limitations under the License.
25298  */
25299 
25300 /*
25301 !depends 
25302 ilib.js
25303 NumberingPlan.js
25304 PhoneLocale.js
25305 PhoneHandlerFactory.js
25306 Utils.js
25307 JSUtils.js
25308 */
25309 
25310 // !data states idd mnc
25311 
25312 
25313 /**
25314  * @class
25315  * Create a new phone number instance that parses the phone number parameter for its 
25316  * constituent parts, and store them as separate fields in the returned object.
25317  * 
25318  * The options object may include any of these properties:
25319  * 
25320  * <ul>
25321  * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
25322  * numbering plan to use.
25323  * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
25324  * currently connected to, if known. This also can give a clue as to which numbering plan to
25325  * use
25326  * <li>onLoad - a callback function to call when this instance is fully 
25327  * loaded. When the onLoad option is given, this class will attempt to
25328  * load any missing locale data using the ilib loader callback.
25329  * When the constructor is done (even if the data is already preassembled), the 
25330  * onLoad function is called with the current instance as a parameter, so this
25331  * callback can be used with preassembled or dynamic loading or a mix of the two.
25332  * <li>sync - tell whether to load any missing locale data synchronously or 
25333  * asynchronously. If this option is given as "false", then the "onLoad"
25334  * callback must be given, as the instance returned from this constructor will
25335  * not be usable for a while.
25336  * <li><i>loadParams</i> - an object containing parameters to pass to the 
25337  * loader callback function when locale data is missing. The parameters are not
25338  * interpretted or modified in any way. They are simply passed along. The object 
25339  * may contain any property/value pairs as long as the calling code is in
25340  * agreement with the loader callback function as to what those parameters mean.
25341  * </ul>
25342  * 
25343  * This function is locale-sensitive, and will assume any number passed to it is
25344  * appropriate for the given locale. If the MCC is given, this method will assume
25345  * that numbers without an explicit country code have been dialled within the country
25346  * given by the MCC. This affects how things like area codes are parsed. If the MCC
25347  * is not given, this method will use the given locale to determine the country
25348  * code. If the locale is not explicitly given either, then this function uses the 
25349  * region of current locale as the default.<p>
25350  * 
25351  * The input number may contain any formatting characters for the given locale. Each 
25352  * field that is returned in the json object is a simple string of digits with
25353  * all formatting and whitespace characters removed.<p>
25354  * 
25355  * The number is decomposed into its parts, regardless if the number
25356  * contains formatting characters. If a particular part cannot be extracted from given 
25357  * number, the field will not be returned as a field in the object. If no fields can be
25358  * extracted from the number at all, then all digits found in the string will be 
25359  * returned in the subscriberNumber field. If the number parameter contains no 
25360  * digits, an empty object is returned.<p>
25361  * 
25362  * This instance can contain any of the following fields after parsing is done:
25363  * 
25364  * <ul>
25365  * <li>vsc - if this number starts with a VSC (Vertical Service Code, or "star code"), this field will contain the star and the code together
25366  * <li>iddPrefix - the prefix for international direct dialing. This can either be in the form of a plus character or the IDD access code for the given locale
25367  * <li>countryCode - if this number is an international direct dial number, this is the country code
25368  * <li>cic - for "dial-around" services (access to other carriers), this is the prefix used as the carrier identification code
25369  * <li>emergency - an emergency services number
25370  * <li>mobilePrefix - prefix that introduces a mobile phone number
25371  * <li>trunkAccess - trunk access code (long-distance access)
25372  * <li>serviceCode - like a geographic area code, but it is a required prefix for various services
25373  * <li>areaCode - geographic area codes
25374  * <li>subscriberNumber - the unique number of the person or company that pays for this phone line
25375  * <li>extension - in some countries, extensions are dialed directly without going through an operator or a voice prompt system. If the number includes an extension, it is given in this field.
25376  * <li>invalid - this property is added and set to true if the parser found that the number is invalid in the numbering plan for the country. This method will make its best effort at parsing, but any digits after the error will go into the subscriberNumber field
25377  * </ul>
25378  * 
25379  * The following rules determine how the number is parsed:
25380  * 
25381  * <ol>
25382  * <li>If the number starts with a character that is alphabetic instead of numeric, do
25383  * not parse the number at all. There is a good chance that it is not really a phone number.
25384  * In this case, an empty instance will be returned.
25385  * <li>If the phone number uses the plus notation or explicitly uses the international direct
25386  * dialing prefix for the given locale, then the country code is identified in 
25387  * the number. The rules of given locale are used to parse the IDD prefix, and then the rules
25388  * of the country in the prefix are used to parse the rest of the number.
25389  * <li>If a country code is provided as an argument to the function call, use that country's
25390  * parsing rules for the number. This is intended for programs like a Contacts application that 
25391  * know what the country is of the person that owns the phone number and can pass that on as 
25392  * a hint.
25393  * <li>If the appropriate locale cannot be easily determined, default to using the rules 
25394  * for the current user's region.
25395  * </ol>
25396  * 
25397  * Example: parsing the number "+49 02101345345-78" will give the following properties in the
25398  * resulting phone number instance:
25399  * 
25400  * <pre>
25401  *      {
25402  *        iddPrefix: "+",
25403  *        countryCode: "49",
25404  *        areaCode: "02101",
25405  *        subscriberNumber: "345345",
25406  *        extension: "78"
25407  *      }
25408  * </pre>
25409  *  
25410  * Note that in this example, because international direct dialing is explicitly used 
25411  * in the number, the part of this number after the IDD prefix and country code will be 
25412  * parsed exactly the same way in all locales with German rules (country code 49).
25413  *  
25414  * Regions currently supported are:
25415  *  
25416  * <ul>
25417  * <li>NANP (North American Numbering Plan) countries - USA, Canada, Bermuda, various Caribbean nations
25418  * <li>UK
25419  * <li>Republic of Ireland
25420  * <li>Germany
25421  * <li>France
25422  * <li>Spain
25423  * <li>Italy
25424  * <li>Mexico
25425  * <li>India
25426  * <li>People's Republic of China
25427  * <li>Netherlands
25428  * <li>Belgium
25429  * <li>Luxembourg
25430  * <li>Australia
25431  * <li>New Zealand
25432  * <li>Singapore
25433  * <li>Korea
25434  * <li>Japan
25435  * <li>Russia
25436  * <li>Brazil
25437  * </ul>
25438  * 
25439  * @constructor
25440  * @param {!string|PhoneNumber} number A free-form phone number to be parsed, or another phone
25441  * number instance to copy
25442  * @param {Object=} options options that guide the parser in parsing the number
25443  */
25444 var PhoneNumber = function(number, options) {
25445 	var stateData,
25446 		regionSettings;
25447 
25448 	this.sync = true;
25449 	this.loadParams = {};
25450 	
25451 	if (!number || (typeof number === "string" && number.length === 0)) {
25452 		return this;
25453 	}
25454 
25455 	if (options) {
25456 		if (typeof(options.sync) === 'boolean') {
25457 			this.sync = options.sync;
25458 		}
25459 
25460 		if (options.loadParams) {
25461 			this.loadParams = options.loadParams;
25462 		}
25463 
25464 		if (typeof(options.onLoad) === 'function') {
25465 			/** 
25466 			 * @private
25467 			 * @type {function(PhoneNumber)} 
25468 			 */
25469 			this.onLoad = options.onLoad;
25470 		}
25471 	}
25472 
25473 	if (typeof number === "object") {
25474 		/**
25475 		 * The vertical service code. These are codes that typically
25476 		 * start with a star or hash, like "*69" for "dial back the 
25477 		 * last number that called me".
25478 		 * @type {string|undefined} 
25479 		 */
25480 		this.vsc = number.vsc;
25481 
25482 		/**
25483 		 * The international direct dialing prefix. This is always
25484 		 * followed by the country code. 
25485 		 * @type {string} 
25486 		 */
25487 		this.iddPrefix = number.iddPrefix;
25488 		
25489 		/**
25490 		 * The unique IDD country code for the country where the
25491 		 * phone number is serviced. 
25492 		 * @type {string|undefined} 
25493 		 */
25494 		this.countryCode = number.countryCode;
25495 		
25496 		/**
25497 		 * The digits required to access the trunk. 
25498 		 * @type {string|undefined} 
25499 		 */
25500 		this.trunkAccess = number.trunkAccess;
25501 		
25502 		/**
25503 		 * The carrier identification code used to identify 
25504 		 * alternate long distance or international carriers. 
25505 		 * @type {string|undefined} 
25506 		 */
25507 		this.cic = number.cic;
25508 		
25509 		/**
25510 		 * Identifies an emergency number that is typically
25511 		 * short, such as "911" in North America or "112" in
25512 		 * many other places in the world. 
25513 		 * @type {string|undefined} 
25514 		 */
25515 		this.emergency = number.emergency;
25516 		
25517 		/**
25518 		 * The prefix of the subscriber number that indicates
25519 		 * that this is the number of a mobile phone. 
25520 		 * @type {string|undefined} 
25521 		 */
25522 		this.mobilePrefix = number.mobilePrefix;
25523 		
25524 		/**
25525 		 * The prefix that identifies this number as commercial
25526 		 * service number. 
25527 		 * @type {string|undefined} 
25528 		 */
25529 		this.serviceCode = number.serviceCode;
25530 		
25531 		/**
25532 		 * The area code prefix of a land line number. 
25533 		 * @type {string|undefined} 
25534 		 */
25535 		this.areaCode = number.areaCode;
25536 		
25537 		/**
25538 		 * The unique number associated with the subscriber
25539 		 * of this phone. 
25540 		 * @type {string|undefined} 
25541 		 */
25542 		this.subscriberNumber = number.subscriberNumber;
25543 		
25544 		/**
25545 		 * The direct dial extension number. 
25546 		 * @type {string|undefined} 
25547 		 */
25548 		this.extension = number.extension;
25549 		
25550 		/**
25551 		 * @private
25552 		 * @type {boolean} 
25553 		 */
25554 		this.invalid = number.invalid;
25555 
25556 		if (number.plan && number.locale) {
25557 			/** 
25558 			 * @private
25559 			 * @type {NumberingPlan} 
25560 			 */
25561 			this.plan = number.plan;
25562 			
25563 			/** 
25564 			 * @private
25565 			 * @type {PhoneLocale} 
25566 			 */
25567 			this.locale = number.locale;
25568 	
25569 			/** 
25570 			 * @private
25571 			 * @type {NumberingPlan} 
25572 			 */
25573 			this.destinationPlan = number.destinationPlan;
25574 			
25575 			/** 
25576 			 * @private
25577 			 * @type {PhoneLocale} 
25578 			 */
25579 			this.destinationLocale = number.destinationLocale;
25580 	
25581 			if (options && typeof(options.onLoad) === 'function') {
25582 				options.onLoad(this);
25583 			}
25584 			return;
25585 		}
25586 	}
25587 
25588 	new PhoneLocale({
25589 		locale: options && options.locale,
25590 		mcc: options && options.mcc,
25591 		sync: this.sync,
25592 		loadParams: this.loadParams,
25593 		onLoad: ilib.bind(this, function(loc) {
25594 			this.locale = this.destinationLocale = loc;
25595 			new NumberingPlan({
25596 				locale: this.locale,
25597 				sync: this.sync,
25598 				loadParms: this.loadParams,
25599 				onLoad: ilib.bind(this, function (plan) {
25600 					this.plan = this.destinationPlan = plan;
25601 			
25602 					if (typeof number === "object") {
25603 						// the copy constructor code above did not find the locale 
25604 						// or plan before, but now they are loaded, so we can return 
25605 						// already without going further
25606 						return;
25607 					}
25608 					Utils.loadData({
25609 						name: "states.json",
25610 						object: PhoneNumber,
25611 						locale: this.locale,
25612 						sync: this.sync,
25613 						loadParams: JSUtils.merge(this.loadParams, {
25614 							returnOne: true
25615 						}),
25616 						callback: ilib.bind(this, function (stdata) {
25617 							if (!stdata) {
25618 								stdata = PhoneNumber._defaultStates;
25619 							}
25620 		
25621 							stateData = stdata;
25622 
25623 							regionSettings = {
25624 								stateData: stateData,
25625 								plan: plan,
25626 								handler: PhoneHandlerFactory(this.locale, plan)
25627 							};
25628 							
25629 							// use ^ to indicate the beginning of the number, because certain things only match at the beginning
25630 							number = "^" + number.replace(/\^/g, '');
25631 							number = PhoneNumber._stripFormatting(number);
25632 
25633 							this._parseNumber(number, regionSettings, options);
25634 						})
25635 					});
25636 				})
25637 			});
25638 		})
25639 	});
25640 };
25641 
25642 /**
25643  * Parse an International Mobile Subscriber Identity (IMSI) number into its 3 constituent parts:
25644  * 
25645  * <ol>
25646  * <li>mcc - Mobile Country Code, which identifies the country where the phone is currently receiving 
25647  * service.
25648  * <li>mnc - Mobile Network Code, which identifies the carrier which is currently providing service to the phone 
25649  * <li>msin - Mobile Subscription Identifier Number. This is a unique number identifying the mobile phone on 
25650  * the network, which usually maps to an account/subscriber in the carrier's database.
25651  * </ol>
25652  * 
25653  * Because this function may need to load data to identify the above parts, you can pass an options
25654  * object that controls how the data is loaded. The options may contain any of the following properties:
25655  *
25656  * <ul>
25657  * <li>onLoad - a callback function to call when the parsing is done. When the onLoad option is given, 
25658  * this method will attempt to load the locale data using the ilib loader callback. When it is done
25659  * (even if the data is already preassembled), the onLoad function is called with the parsing results
25660  * as a parameter, so this callback can be used with preassembled or dynamic, synchronous or 
25661  * asynchronous loading or a mix of the above.
25662  * <li>sync - tell whether to load any missing locale data synchronously or asynchronously. If this 
25663  * option is given as "false", then the "onLoad" callback must be given, as the results returned from 
25664  * this constructor will not be usable for a while.
25665  * <li><i>loadParams</i> - an object containing parameters to pass to the loader callback function 
25666  * when locale data is missing. The parameters are not interpretted or modified in any way. They are 
25667  * simply passed along. The object may contain any property/value pairs as long as the calling code is in
25668  * agreement with the loader callback function as to what those parameters mean.
25669  * </ul>
25670  *
25671  * @static
25672  * @param {string} imsi IMSI number to parse
25673  * @param {Object} options options controlling the loading of the locale data
25674  * @return {{mcc:string,mnc:string,msin:string}|undefined} components of the IMSI number, when the locale data
25675  * is loaded synchronously, or undefined if asynchronous
25676  */
25677 PhoneNumber.parseImsi = function(imsi, options) {
25678 	var sync = true,
25679 		loadParams = {},
25680 		fields = {};
25681 	
25682 	if (!imsi) {
25683 		return undefined;
25684 	}
25685 
25686 	if (options) {
25687 		if (typeof(options.sync) !== 'undefined') {
25688 			sync = (options.sync == true);
25689 		}
25690 		
25691 		if (options.loadParams) {
25692 			loadParams = options.loadParams;
25693 		}
25694 	}	
25695 
25696 	if (ilib.data.mnc) {
25697 		fields = PhoneNumber._parseImsi(ilib.data.mnc, imsi);
25698 		
25699 		if (options && typeof(options.onLoad) === 'function') {
25700 			options.onLoad(fields);
25701 		}
25702 	} else {
25703 		Utils.loadData({
25704 			name: "mnc.json", 
25705 			object: PhoneNumber, 
25706 			nonlocale: true, 
25707 			sync: sync, 
25708 			loadParams: loadParams, 
25709 			callback: ilib.bind(this, function(data) {
25710 				ilib.data.mnc = data;
25711 				fields = PhoneNumber._parseImsi(data, imsi);
25712 				
25713 				if (options && typeof(options.onLoad) === 'function') {
25714 					options.onLoad(fields);
25715 				}
25716 			})
25717 		});
25718 	}
25719 	return fields;
25720 };
25721 
25722 
25723 /**
25724  * @static
25725  * @protected
25726  */
25727 PhoneNumber._parseImsi = function(data, imsi) {
25728 	var ch, 
25729 		i,
25730 		currentState, 
25731 		end, 
25732 		handlerMethod,
25733 		state = 0,
25734 		newState,
25735 		fields = {},
25736 		lastLeaf,
25737 		consumed = 0;
25738 	
25739 	currentState = data;
25740 	if (!currentState) {
25741 		// can't parse anything
25742 		return undefined;
25743 	}
25744 	
25745 	i = 0;
25746 	while (i < imsi.length) {
25747 		ch = PhoneNumber._getCharacterCode(imsi.charAt(i));
25748 		// console.info("parsing char " + imsi.charAt(i) + " code: " + ch);
25749 		if (ch >= 0) {
25750 			newState = currentState.s && currentState.s[ch];
25751 			
25752 			if (typeof(newState) === 'object') {
25753 				if (typeof(newState.l) !== 'undefined') {
25754 					// save for latter if needed
25755 					lastLeaf = newState;
25756 					consumed = i;
25757 				}
25758 				// console.info("recognized digit " + ch + " continuing...");
25759 				// recognized digit, so continue parsing
25760 				currentState = newState;
25761 				i++;
25762 			} else {
25763 				if ((typeof(newState) === 'undefined' || newState === 0 ||
25764 					(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
25765 					 lastLeaf) {
25766 					// this is possibly a look-ahead and it didn't work... 
25767 					// so fall back to the last leaf and use that as the
25768 					// final state
25769 					newState = lastLeaf;
25770 					i = consumed;
25771 				}
25772 				
25773 				if ((typeof(newState) === 'number' && newState) ||
25774 					(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
25775 					// final state
25776 					var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
25777 					handlerMethod = PhoneNumber._states[stateNumber];
25778 
25779 					// console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
25780 	
25781 					// deal with syntactic ambiguity by using the "special" end state instead of "area"
25782 					if ( handlerMethod === "area" ) {
25783 						end = i+1;
25784 					} else {
25785 						// unrecognized imsi, so just assume the mnc is 3 digits
25786 						end = 6;
25787 					}
25788 					
25789 					fields.mcc = imsi.substring(0,3);
25790 					fields.mnc = imsi.substring(3,end);
25791 					fields.msin = imsi.substring(end);
25792 	
25793 					return fields;
25794 				} else {
25795 					// parse error
25796 					if (imsi.length >= 6) {
25797 						fields.mcc = imsi.substring(0,3);
25798 						fields.mnc = imsi.substring(3,6);
25799 						fields.msin = imsi.substring(6);
25800 					}
25801 					return fields;
25802 				}
25803 			}
25804 		} else if (ch === -1) {
25805 			// non-transition character, continue parsing in the same state
25806 			i++;
25807 		} else {
25808 			// should not happen
25809 			// console.info("skipping character " + ch);
25810 			// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
25811 			i++;
25812 		}
25813 	}
25814 		
25815 	if (i >= imsi.length && imsi.length >= 6) {
25816 		// we reached the end of the imsi, but did not finish recognizing anything. 
25817 		// Default to last resort and assume 3 digit mnc
25818 		fields.mcc = imsi.substring(0,3);
25819 		fields.mnc = imsi.substring(3,6);
25820 		fields.msin = imsi.substring(6);
25821 	} else {
25822 		// unknown or not enough characters for a real imsi 
25823 		fields = undefined;
25824 	}
25825 		
25826 	// console.info("Globalization.Phone.parseImsi: final result is: " + JSON.stringify(fields));
25827 	return fields;
25828 };
25829 
25830 /**
25831  * @static
25832  * @private
25833  */
25834 PhoneNumber._stripFormatting = function(str) {
25835 	var ret = "";
25836 	var i;
25837 
25838 	for (i = 0; i < str.length; i++) {
25839 		if (PhoneNumber._getCharacterCode(str.charAt(i)) >= -1) {
25840 			ret += str.charAt(i);
25841 		}
25842 	}
25843 	return ret;
25844 };
25845 
25846 /**
25847  * @static
25848  * @protected
25849  */
25850 PhoneNumber._getCharacterCode = function(ch) {
25851 	if (ch >= '0' && ch <= '9') {
25852 			return ch - '0';
25853 		}
25854 	switch (ch) {
25855 	case '+':
25856 		return 10;
25857 	case '*':
25858 		return 11;
25859 	case '#':
25860 		return 12;
25861 	case '^':
25862 		return 13;
25863 	case 'p':		// pause chars
25864 	case 'P':
25865 	case 't':
25866 	case 'T':
25867 	case 'w':
25868 	case 'W':
25869 		return -1;
25870 	case 'x':
25871 	case 'X':
25872 	case ',':
25873 	case ';':		// extension char
25874 		return -1;
25875 	}
25876 	return -2;
25877 };
25878 
25879 /**
25880  * @private
25881  */
25882 PhoneNumber._states = [
25883 	"none",
25884 	"unknown",
25885 	"plus",
25886 	"idd",
25887 	"cic",
25888 	"service",
25889 	"cell",
25890 	"area",
25891 	"vsc",
25892 	"country",
25893 	"personal",
25894 	"special",
25895 	"trunk",
25896 	"premium",
25897 	"emergency",
25898 	"service2",
25899 	"service3",
25900 	"service4",
25901 	"cic2",
25902 	"cic3",
25903 	"start",
25904 	"local"
25905 ];
25906 
25907 /**
25908  * @private
25909  */
25910 PhoneNumber._fieldOrder = [
25911 	"vsc",
25912 	"iddPrefix",
25913 	"countryCode",
25914 	"trunkAccess",
25915 	"cic",
25916 	"emergency",
25917 	"mobilePrefix",
25918 	"serviceCode",
25919 	"areaCode",
25920 	"subscriberNumber",
25921 	"extension"
25922 ];
25923 
25924 PhoneNumber._defaultStates = {
25925 	"s": [
25926         0,
25927 		21,  // 1 -> local
25928         21,  // 2 -> local
25929         21,  // 3 -> local
25930         21,  // 4 -> local
25931         21,  // 5 -> local
25932         21,  // 6 -> local
25933         21,  // 7 -> local
25934         21,  // 8 -> local
25935         21,  // 9 -> local
25936         0,0,0,
25937 	    { // ^
25938 	    	"s": [
25939 				{ // ^0
25940 					"s": [3], // ^00 -> idd
25941 					"l": 12   // ^0  -> trunk
25942 				},
25943 				21,  // ^1 -> local
25944 	            21,  // ^2 -> local
25945 	            21,  // ^3 -> local
25946 	            21,  // ^4 -> local
25947 	            21,  // ^5 -> local
25948 	            21,  // ^6 -> local
25949 	            21,  // ^7 -> local
25950 	            21,  // ^8 -> local
25951 	            21,  // ^9 -> local
25952 	            2    // ^+ -> plus
25953 	        ]
25954 	    }
25955 	]
25956 };
25957 
25958 PhoneNumber.prototype = {
25959 	/**
25960 	 * @protected
25961 	 * @param {string} number
25962 	 * @param {Object} regionData
25963 	 * @param {Object} options
25964 	 * @param {string} countryCode
25965 	 */
25966 	_parseOtherCountry: function(number, regionData, options, countryCode) {
25967 		new PhoneLocale({
25968 			locale: this.locale,
25969 			countryCode: countryCode,
25970 			sync: this.sync,
25971 			loadParms: this.loadParams,
25972 			onLoad: ilib.bind(this, function (loc) {
25973 				/*
25974 				 * this.locale is the locale where this number is being parsed,
25975 				 * and is used to parse the IDD prefix, if any, and this.destinationLocale is 
25976 				 * the locale of the rest of this number after the IDD prefix.
25977 				 */
25978 				/** @type {PhoneLocale} */
25979 				this.destinationLocale = loc;
25980 
25981 				Utils.loadData({
25982 					name: "states.json",
25983 					object: PhoneNumber,
25984 					locale: this.destinationLocale,
25985 					sync: this.sync,
25986 					loadParams: JSUtils.merge(this.loadParams, {
25987 						returnOne: true
25988 					}),
25989 					callback: ilib.bind(this, function (stateData) {
25990 						if (!stateData) {
25991 							stateData = PhoneNumber._defaultStates;
25992 						}
25993 						
25994 						new NumberingPlan({
25995 							locale: this.destinationLocale,
25996 							sync: this.sync,
25997 							loadParms: this.loadParams,
25998 							onLoad: ilib.bind(this, function (plan) {
25999 								/*
26000 								 * this.plan is the plan where this number is being parsed,
26001 								 * and is used to parse the IDD prefix, if any, and this.destinationPlan is 
26002 								 * the plan of the rest of this number after the IDD prefix in the 
26003 								 * destination locale.
26004 								 */
26005 								/** @type {NumberingPlan} */
26006 								this.destinationPlan = plan;
26007 
26008 								var regionSettings = {
26009 									stateData: stateData,
26010 									plan: plan,
26011 									handler: PhoneHandlerFactory(this.destinationLocale, plan)
26012 								};
26013 								
26014 								// for plans that do not skip the trunk code when dialing from
26015 								// abroad, we need to treat the number from here on in as if it 
26016 								// were parsing a local number from scratch. That way, the parser
26017 								// does not get confused between parts of the number at the
26018 								// beginning of the number, and parts in the middle.
26019 								if (!plan.getSkipTrunk()) {
26020 									number = '^' + number;
26021 								}
26022 									
26023 								// recursively call the parser with the new states data
26024 								// to finish the parsing
26025 								this._parseNumber(number, regionSettings, options);
26026 							})
26027 						});
26028 					})
26029 				});
26030 			})
26031 		});
26032 	},
26033 	
26034 	/**
26035 	 * @protected
26036 	 * @param {string} number
26037 	 * @param {Object} regionData
26038 	 * @param {Object} options
26039 	 */
26040 	_parseNumber: function(number, regionData, options) {
26041 		var i, ch,
26042 			regionSettings,
26043 			newState,
26044 			dot,
26045 			handlerMethod,
26046 			result,
26047 			currentState = regionData.stateData,
26048 			lastLeaf = undefined,
26049 			consumed = 0;
26050 
26051 		regionSettings = regionData;
26052 		dot = 14; // special transition which matches all characters. See AreaCodeTableMaker.java
26053 
26054 		i = 0;
26055 		while (i < number.length) {
26056 			ch = PhoneNumber._getCharacterCode(number.charAt(i));
26057 			if (ch >= 0) {
26058 				// newState = stateData.states[state][ch];
26059 				newState = currentState.s && currentState.s[ch];
26060 				
26061 				if (!newState && currentState.s && currentState.s[dot]) {
26062 					newState = currentState.s[dot];
26063 				}
26064 				
26065 				if (typeof(newState) === 'object' && i+1 < number.length) {
26066 					if (typeof(newState.l) !== 'undefined') {
26067 						// this is a leaf node, so save that for later if needed
26068 						lastLeaf = newState;
26069 						consumed = i;
26070 					}
26071 					// console.info("recognized digit " + ch + " continuing...");
26072 					// recognized digit, so continue parsing
26073 					currentState = newState;
26074 					i++;
26075 				} else {
26076 					if ((typeof(newState) === 'undefined' || newState === 0 ||
26077 						(typeof(newState) === 'object' && typeof(newState.l) === 'undefined')) &&
26078 						 lastLeaf) {
26079 						// this is possibly a look-ahead and it didn't work... 
26080 						// so fall back to the last leaf and use that as the
26081 						// final state
26082 						newState = lastLeaf;
26083 						i = consumed;
26084 						consumed = 0;
26085 						lastLeaf = undefined;
26086 					}
26087 					
26088 					if ((typeof(newState) === 'number' && newState) ||
26089 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
26090 						// final state
26091 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
26092 						handlerMethod = PhoneNumber._states[stateNumber];
26093 						
26094 						if (number.charAt(0) === '^') {
26095 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26096 						} else {
26097 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26098 						}
26099 		
26100 						// reparse whatever is left
26101 						number = result.number;
26102 						i = consumed = 0;
26103 						lastLeaf = undefined;
26104 						
26105 						//console.log("reparsing with new number: " +  number);
26106 						currentState = regionSettings.stateData;
26107 						// if the handler requested a special sub-table, use it for this round of parsing,
26108 						// otherwise, set it back to the regular table to continue parsing
26109 	
26110 						if (result.countryCode !== undefined) {
26111 							this._parseOtherCountry(number, regionData, options, result.countryCode);
26112 							// don't process any further -- let the work be done in the onLoad callbacks
26113 							return;
26114 						} else if (result.table !== undefined) {
26115 							Utils.loadData({
26116 								name: result.table + ".json",
26117 								object: PhoneNumber,
26118 								nonlocale: true,
26119 								sync: this.sync,
26120 								loadParams: this.loadParams,
26121 								callback: ilib.bind(this, function (data) {
26122 									if (!data) {
26123 										data = PhoneNumber._defaultStates;
26124 									}
26125 	
26126 									regionSettings = {
26127 										stateData: data,
26128 										plan: regionSettings.plan,
26129 										handler: regionSettings.handler
26130 									};
26131 									
26132 									// recursively call the parser with the new states data
26133 									// to finish the parsing
26134 									this._parseNumber(number, regionSettings, options);
26135 								})
26136 							});
26137 							// don't process any further -- let the work be done in the onLoad callbacks
26138 							return;
26139 						} else if (result.skipTrunk !== undefined) {
26140 							ch = PhoneNumber._getCharacterCode(regionSettings.plan.getTrunkCode());
26141 							currentState = currentState.s && currentState.s[ch];
26142 						}
26143 					} else {
26144 						handlerMethod = (typeof(newState) === 'number') ? "none" : "local";
26145 						// failed parse. Either no last leaf to fall back to, or there was an explicit
26146 						// zero in the table. Put everything else in the subscriberNumber field as the
26147 						// default place
26148 						if (number.charAt(0) === '^') {
26149 							result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26150 						} else {
26151 							result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26152 						}
26153 						break;
26154 					}
26155 				}
26156 			} else if (ch === -1) {
26157 				// non-transition character, continue parsing in the same state
26158 				i++;
26159 			} else {
26160 				// should not happen
26161 				// console.info("skipping character " + ch);
26162 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
26163 				i++;
26164 			}
26165 		}
26166 		if (i >= number.length && currentState !== regionData.stateData) {
26167 			handlerMethod = (typeof(currentState.l) === 'undefined' || currentState === 0) ? "none" : "local";
26168 			// we reached the end of the phone number, but did not finish recognizing anything. 
26169 			// Default to last resort and put everything that is left into the subscriber number
26170 			//console.log("Reached end of number before parsing was complete. Using handler for method none.")
26171 			if (number.charAt(0) === '^') {
26172 				result = regionSettings.handler[handlerMethod](number.slice(1), i-1, this, regionSettings);
26173 			} else {
26174 				result = regionSettings.handler[handlerMethod](number, i, this, regionSettings);
26175 			}
26176 		}
26177 
26178 		// let the caller know we are done parsing
26179 		if (this.onLoad) {
26180 			this.onLoad(this);
26181 		}
26182 	},
26183 	/**
26184 	 * @protected
26185 	 */
26186 	_getPrefix: function() {
26187 		return this.areaCode || this.serviceCode || this.mobilePrefix || "";
26188 	},
26189 	
26190 	/**
26191 	 * @protected
26192 	 */
26193 	_hasPrefix: function() {
26194 		return (this._getPrefix() !== "");
26195 	},
26196 	
26197 	/**
26198 	 * Exclusive or -- return true, if one is defined and the other isn't
26199 	 * @protected
26200 	 */
26201 	_xor : function(left, right) {
26202 		if ((left === undefined && right === undefined ) || (left !== undefined && right !== undefined)) {
26203 			return false;
26204 		} else {
26205 			return true;
26206 		}
26207 	},
26208 	
26209 	/**
26210 	 * return a version of the phone number that contains only the dialable digits in the correct order 
26211 	 * @protected
26212 	 */
26213 	_join: function () {
26214 		var fieldName, formatted = "";
26215 		
26216 		try {
26217 			for (var field in PhoneNumber._fieldOrder) {
26218 				if (typeof field === 'string' && typeof PhoneNumber._fieldOrder[field] === 'string') {
26219 					fieldName = PhoneNumber._fieldOrder[field];
26220 					// console.info("normalize: formatting field " + fieldName);
26221 					if (this[fieldName] !== undefined) {
26222 						formatted += this[fieldName];
26223 					}
26224 				}
26225 			}
26226 		} catch ( e ) {
26227 			//console.warn("caught exception in _join: " + e);
26228 			throw e;
26229 		}
26230 		return formatted;
26231 	},
26232 
26233 	/**
26234 	 * This routine will compare the two phone numbers in an locale-sensitive
26235 	 * manner to see if they possibly reference the same phone number.<p>
26236 	 * 
26237 	 * In many places,
26238 	 * there are multiple ways to reach the same phone number. In North America for 
26239 	 * example, you might have a number with the trunk access code of "1" and another
26240 	 * without, and they reference the exact same phone number. This is considered a
26241 	 * strong match. For a different pair of numbers, one may be a local number and
26242 	 * the other a full phone number with area code, which may reference the same 
26243 	 * phone number if the local number happens to be located in that area code. 
26244 	 * However, you cannot say for sure if it is in that area code, so it will 
26245 	 * be considered a somewhat weaker match.<p>
26246 	 *  
26247 	 * Similarly, in other countries, there are sometimes different ways of 
26248 	 * reaching the same destination, and the way that numbers
26249 	 * match depends on the locale.<p>
26250 	 * 
26251 	 * The various phone number fields are handled differently for matches. There
26252 	 * are various fields that do not need to match at all. For example, you may
26253 	 * type equally enter "00" or "+" into your phone to start international direct
26254 	 * dialling, so the iddPrefix field does not need to match at all.<p> 
26255 	 * 
26256 	 * Typically, fields that require matches need to match exactly if both sides have a value 
26257 	 * for that field. If both sides specify a value and those values differ, that is
26258 	 * a strong non-match. If one side does not have a value and the other does, that 
26259 	 * causes a partial match, because the number with the missing field may possibly
26260 	 * have an implied value that matches the other number. For example, the numbers
26261 	 * "650-555-1234" and "555-1234" have a partial match as the local number "555-1234"
26262 	 * might possibly have the same 650 area code as the first number, and might possibly
26263 	 * not. If both side do not specify a value for a particular field, that field is 
26264 	 * considered matching.<p>
26265 	 *  
26266 	 * The values of following fields are ignored when performing matches:
26267 	 * 
26268 	 * <ul>
26269 	 * <li>vsc
26270 	 * <li>iddPrefix
26271 	 * <li>cic
26272 	 * <li>trunkAccess
26273 	 * </ul>
26274 	 * 
26275 	 * The values of the following fields matter if they do not match:
26276 	 *   
26277 	 * <ul>
26278 	 * <li>countryCode - A difference causes a moderately strong problem except for 
26279 	 * certain countries where there is a way to access the same subscriber via IDD 
26280 	 * and via intranetwork dialling
26281 	 * <li>mobilePrefix - A difference causes a possible non-match
26282 	 * <li>serviceCode - A difference causes a possible non-match
26283 	 * <li>areaCode - A difference causes a possible non-match
26284 	 * <li>subscriberNumber - A difference causes a very strong non-match
26285 	 * <li>extension - A difference causes a minor non-match
26286 	 * </ul>
26287 	 *  
26288 	 * @param {string|PhoneNumber} other other phone number to compare this one to
26289 	 * @return {number} non-negative integer describing the percentage quality of the 
26290 	 * match. 100 means a very strong match (100%), and lower numbers are less and 
26291 	 * less strong, down to 0 meaning not at all a match. 
26292 	 */
26293 	compare: function (other) {
26294 		var match = 100,
26295 			FRdepartments = {"590":1, "594":1, "596":1, "262":1},
26296 			ITcountries = {"378":1, "379":1},
26297 			thisPrefix,
26298 			otherPrefix,
26299 			currentCountryCode = 0;
26300 
26301 		if (typeof this.locale.region === "string") {
26302 			currentCountryCode = this.locale._mapRegiontoCC(this.locale.region);
26303 		}
26304 		
26305 		// subscriber number must be present and must match
26306 		if (!this.subscriberNumber || !other.subscriberNumber || this.subscriberNumber !== other.subscriberNumber) {
26307 			return 0;
26308 		}
26309 
26310 		// extension must match if it is present
26311 		if (this._xor(this.extension, other.extension) || this.extension !== other.extension) {
26312 			return 0;
26313 		}
26314 
26315 		if (this._xor(this.countryCode, other.countryCode)) {
26316 			// if one doesn't have a country code, give it some demerit points, but if the
26317 			// one that has the country code has something other than the current country
26318 			// add even more. Ignore the special cases where you can dial the same number internationally or via 
26319 			// the local numbering system
26320 			switch (this.locale.getRegion()) {
26321 			case 'FR':
26322 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
26323 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
26324 						match -= 100;
26325 					}
26326 				} else {
26327 					match -= 16;
26328 				}
26329 				break;
26330 			case 'IT':
26331 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
26332 					if (this.areaCode !== other.areaCode) {
26333 						match -= 100;
26334 					}
26335 				} else {
26336 					match -= 16;
26337 				}
26338 				break;
26339 			default:
26340 				match -= 16;
26341 				if ((this.countryCode !== undefined && this.countryCode !== currentCountryCode) || 
26342 					(other.countryCode !== undefined && other.countryCode !== currentCountryCode)) {
26343 					match -= 16;
26344 				}
26345 			}
26346 		} else if (this.countryCode !== other.countryCode) {
26347 			// ignore the special cases where you can dial the same number internationally or via 
26348 			// the local numbering system
26349 			if (other.countryCode === '33' || this.countryCode === '33') {
26350 				// france
26351 				if (this.countryCode in FRdepartments || other.countryCode in FRdepartments) {
26352 					if (this.areaCode !== other.areaCode || this.mobilePrefix !== other.mobilePrefix) {
26353 						match -= 100;
26354 					}
26355 				} else {
26356 					match -= 100;
26357 				}
26358 			} else if (this.countryCode === '39' || other.countryCode === '39') {
26359 				// italy
26360 				if (this.countryCode in ITcountries || other.countryCode in ITcountries) { 
26361 					if (this.areaCode !== other.areaCode) {
26362 						match -= 100;
26363 					}
26364 				} else {
26365 					match -= 100;
26366 				}
26367 			} else {
26368 				match -= 100;
26369 			}
26370 		}
26371 
26372 		if (this._xor(this.serviceCode, other.serviceCode)) {
26373 			match -= 20;
26374 		} else if (this.serviceCode !== other.serviceCode) {
26375 			match -= 100;
26376 		}
26377 
26378 		if (this._xor(this.mobilePrefix, other.mobilePrefix)) {
26379 			match -= 20;
26380 		} else if (this.mobilePrefix !== other.mobilePrefix) {
26381 			match -= 100;
26382 		}
26383 
26384 		if (this._xor(this.areaCode, other.areaCode)) {
26385 			// one has an area code, the other doesn't, so dock some points. It could be a match if the local
26386 			// number in the one number has the same implied area code as the explicit area code in the other number.
26387 			match -= 12;
26388 		} else if (this.areaCode !== other.areaCode) {
26389 			match -= 100;
26390 		}
26391 
26392 		thisPrefix = this._getPrefix();
26393 		otherPrefix = other._getPrefix();
26394 		
26395 		if (thisPrefix && otherPrefix && thisPrefix !== otherPrefix) {
26396 			match -= 100;
26397 		}
26398 		
26399 		// make sure we are between 0 and 100
26400 		if (match < 0) {
26401 			match = 0;	
26402 		} else if (match > 100) {
26403 			match = 100;
26404 		}
26405 
26406 		return match;
26407 	},
26408 	
26409 	/**
26410 	 * Determine whether or not the other phone number is exactly equal to the current one.<p>
26411 	 *  
26412 	 * The difference between the compare method and the equals method is that the compare 
26413 	 * method compares normalized numbers with each other and returns the degree of match,
26414 	 * whereas the equals operator returns true iff the two numbers contain the same fields
26415 	 * and the fields are exactly the same. Functions and other non-phone number properties
26416 	 * are not compared.
26417 	 * @param {string|PhoneNumber} other another phone number to compare to this one
26418 	 * @return {boolean} true if the numbers are the same, false otherwise
26419 	 */
26420 	equals: function equals(other) {
26421 		if (other.locale && this.locale && !this.locale.equals(other.locale) && (!this.countryCode || !other.countryCode)) {
26422 			return false;
26423 		}
26424 		
26425 		for (var p in other) {
26426 			if (p !== undefined && this[p] !== undefined && typeof(this[p]) !== 'object') {
26427 				if (other[p] === undefined) {
26428 					/*console.error("PhoneNumber.equals: other is missing property " + p + " which has the value " + this[p] + " in this");
26429 					console.error("this is : " + JSON.stringify(this));
26430 					console.error("other is: " + JSON.stringify(other));*/
26431 					return false;
26432 				}
26433 				if (this[p] !== other[p]) {
26434 					/*console.error("PhoneNumber.equals: difference in property " + p);
26435 					console.error("this is : " + JSON.stringify(this));
26436 					console.error("other is: " + JSON.stringify(other));*/
26437 					return false;
26438 				}
26439 			}
26440 		}
26441 		for (var p in other) {
26442 			if (p !== undefined && other[p] !== undefined && typeof(other[p]) !== 'object') {
26443 				if (this[p] === undefined) {
26444 					/*console.error("PhoneNumber.equals: this is missing property " + p + " which has the value " + other[p] + " in the other");
26445 					console.error("this is : " + JSON.stringify(this));
26446 					console.error("other is: " + JSON.stringify(other));*/
26447 					return false;
26448 				}
26449 				if (this[p] !== other[p]) {
26450 					/*console.error("PhoneNumber.equals: difference in property " + p);
26451 					console.error("this is : " + JSON.stringify(this));
26452 					console.error("other is: " + JSON.stringify(other));*/
26453 					return false;
26454 				}
26455 			}
26456 		}
26457 		return true;
26458 	},
26459 	
26460 
26461 	/**
26462 	 * @private
26463 	 * @param {{
26464 	 *   mcc:string,
26465 	 *   defaultAreaCode:string,
26466 	 *   country:string,
26467 	 *   networkType:string,
26468 	 *   assistedDialing:boolean,
26469 	 *   sms:boolean,
26470 	 *   manualDialing:boolean
26471 	 * }} options an object containing options to help in normalizing. 
26472 	 * @param {PhoneNumber} norm
26473 	 * @param {PhoneLocale} homeLocale
26474 	 * @param {PhoneLocale} currentLocale
26475 	 * @param {NumberingPlan} currentPlan
26476 	 * @param {PhoneLocale} destinationLocale
26477 	 * @param {NumberingPlan} destinationPlan
26478 	 * @param {boolean} sync
26479 	 * @param {Object|undefined} loadParams
26480 	 */
26481 	_doNormalize: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams) {
26482 		var formatted = "";
26483 		
26484 		if (!norm.invalid && options && options.assistedDialing) {
26485 			// don't normalize things that don't have subscriber numbers. Also, don't normalize
26486 			// manually dialed local numbers. Do normalize local numbers in contact entries.
26487 			if (norm.subscriberNumber && 
26488 					(!options.manualDialing ||
26489 					 norm.iddPrefix ||
26490 					 norm.countryCode ||
26491 					 norm.trunkAccess)) {
26492 				// console.log("normalize: assisted dialling normalization of " + JSON.stringify(norm));
26493 				if (currentLocale.getRegion() !== destinationLocale.getRegion()) {
26494 					// we are currently calling internationally
26495 					if (!norm._hasPrefix() && 
26496 							options.defaultAreaCode && 
26497 							destinationLocale.getRegion() === homeLocale.getRegion() &&
26498 							(!destinationPlan.getFieldLength("minLocalLength") || 
26499 								norm.subscriberNumber.length >= destinationPlan.getFieldLength("minLocalLength"))) {
26500 						// area code is required when dialling from international, but only add it if we are dialing
26501 						// to our home area. Otherwise, the default area code is not valid!
26502 						norm.areaCode = options.defaultAreaCode;
26503 						if (!destinationPlan.getSkipTrunk() && destinationPlan.getTrunkCode()) {
26504 							// some phone systems require the trunk access code, even when dialling from international
26505 							norm.trunkAccess = destinationPlan.getTrunkCode();
26506 						}
26507 					}
26508 					
26509 					if (norm.trunkAccess && destinationPlan.getSkipTrunk()) {
26510 						// on some phone systems, the trunk access code is dropped when dialling from international
26511 						delete norm.trunkAccess;
26512 					}
26513 					
26514 					// make sure to get the country code for the destination region, not the current region!
26515 					if (options.sms) {
26516 						if (homeLocale.getRegion() === "US" && currentLocale.getRegion() !== "US") {
26517 							if (destinationLocale.getRegion() !== "US") {
26518 								norm.iddPrefix = "011"; // non-standard code to make it go through the US first
26519 								norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.getRegion());
26520 							} else if (options.networkType === "cdma") {
26521 								delete norm.iddPrefix;
26522 								delete norm.countryCode;
26523 								if (norm.areaCode) {
26524 									norm.trunkAccess = "1";
26525 								}
26526 							} else if (norm.areaCode) {
26527 								norm.iddPrefix = "+";
26528 								norm.countryCode = "1";
26529 								delete norm.trunkAccess;
26530 							}
26531 						} else {
26532 							norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
26533 							norm.countryCode = norm.countryCode || homeLocale._mapRegiontoCC(destinationLocale.region);
26534 						}
26535 					} else if (norm._hasPrefix() && !norm.countryCode) {
26536 						norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.region);
26537 					}
26538 
26539 					if (norm.countryCode && !options.sms) {
26540 						// for CDMA, make sure to get the international dialling access code for the current region, not the destination region
26541 						// all umts carriers support plus dialing
26542 						norm.iddPrefix = (options.networkType === "cdma") ? currentPlan.getIDDCode() : "+";
26543 					}
26544 				} else {
26545 					// console.log("normalize: dialing within the country");
26546 					if (options.defaultAreaCode) {
26547 						if (destinationPlan.getPlanStyle() === "open") {
26548 							if (!norm.trunkAccess && norm._hasPrefix() && destinationPlan.getTrunkCode()) {
26549 								// call is not local to this area code, so you have to dial the trunk code and the area code
26550 								norm.trunkAccess = destinationPlan.getTrunkCode();
26551 							}
26552 						} else {
26553 							// In closed plans, you always have to dial the area code, even if the call is local.
26554 							if (!norm._hasPrefix()) {
26555 								if (destinationLocale.getRegion() === homeLocale.getRegion()) {
26556 									norm.areaCode = options.defaultAreaCode;
26557 									if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
26558 										norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
26559 									}
26560 								}
26561 							} else {
26562 								if (destinationPlan.getTrunkRequired() && destinationPlan.getTrunkCode()) {
26563 									norm.trunkAccess = norm.trunkAccess || destinationPlan.getTrunkCode();
26564 								}
26565 							}
26566 						}
26567 					}
26568 					
26569 					if (options.sms &&
26570 							homeLocale.getRegion() === "US" && 
26571 							currentLocale.getRegion() !== "US") {
26572 						norm.iddPrefix = "011"; // make it go through the US first
26573 						if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
26574 							delete norm.trunkAccess;
26575 						}
26576 					} else if (norm.iddPrefix || norm.countryCode) {
26577 						// we are in our destination country, so strip the international dialling prefixes
26578 						delete norm.iddPrefix;
26579 						delete norm.countryCode;
26580 						
26581 						if ((destinationPlan.getPlanStyle() === "open" || destinationPlan.getTrunkRequired()) && destinationPlan.getTrunkCode()) {
26582 							norm.trunkAccess = destinationPlan.getTrunkCode();
26583 						}
26584 					}
26585 				}
26586 			}
26587 		} else if (!norm.invalid) {
26588 			// console.log("normalize: non-assisted normalization");
26589 			if (!norm._hasPrefix() && options && options.defaultAreaCode && destinationLocale.getRegion() === homeLocale.region) {
26590 				norm.areaCode = options.defaultAreaCode;
26591 			}
26592 			
26593 			if (!norm.countryCode && norm._hasPrefix()) {
26594 				norm.countryCode = homeLocale._mapRegiontoCC(destinationLocale.getRegion());
26595 			}
26596 
26597 			if (norm.countryCode) {
26598 				if (options && options.networkType && options.networkType === "cdma") {
26599 					norm.iddPrefix = currentPlan.getIDDCode(); 
26600 				} else {
26601 					// all umts carriers support plus dialing
26602 					norm.iddPrefix = "+";
26603 				}
26604 		
26605 				if (destinationPlan.getSkipTrunk() && norm.trunkAccess) {
26606 					delete norm.trunkAccess;
26607 				} else if (!destinationPlan.getSkipTrunk() && !norm.trunkAccess && destinationPlan.getTrunkCode()) {
26608 					norm.trunkAccess = destinationPlan.getTrunkCode();
26609 				}
26610 			}
26611 		}
26612 		
26613 		// console.info("normalize: after normalization, the normalized phone number is: " + JSON.stringify(norm));
26614 		formatted = norm._join();
26615 
26616 		return formatted;
26617 	},
26618 	
26619 	/**
26620 	 * @private
26621 	 * @param {{
26622 	 *   mcc:string,
26623 	 *   defaultAreaCode:string,
26624 	 *   country:string,
26625 	 *   networkType:string,
26626 	 *   assistedDialing:boolean,
26627 	 *   sms:boolean,
26628 	 *   manualDialing:boolean
26629 	 * }} options an object containing options to help in normalizing. 
26630 	 * @param {PhoneNumber} norm
26631 	 * @param {PhoneLocale} homeLocale
26632 	 * @param {PhoneLocale} currentLocale
26633 	 * @param {NumberingPlan} currentPlan
26634 	 * @param {PhoneLocale} destinationLocale
26635 	 * @param {NumberingPlan} destinationPlan
26636 	 * @param {boolean} sync
26637 	 * @param {Object|undefined} loadParams
26638 	 * @param {function(string)} callback
26639 	 */
26640 	_doReparse: function(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams, callback) {
26641 		var formatted, 
26642 			tempRegion;
26643 		
26644 		if (options &&
26645 				options.assistedDialing &&
26646 				!norm.trunkAccess && 
26647 				!norm.iddPrefix &&
26648 				norm.subscriberNumber && 
26649 				norm.subscriberNumber.length > destinationPlan.getFieldLength("maxLocalLength")) {
26650 
26651 			// numbers that are too long are sometimes international direct dialed numbers that
26652 			// are missing the IDD prefix. So, try reparsing it using a plus in front to see if that works.
26653 			new PhoneNumber("+" + this._join(), {
26654 				locale: this.locale,
26655 				sync: sync,
26656 				loadParms: loadParams,
26657 				onLoad: ilib.bind(this, function (data) {
26658 					tempRegion = (data.countryCode && data.locale._mapCCtoRegion(data.countryCode));
26659 
26660 					if (tempRegion && tempRegion !== "unknown" && tempRegion !== "SG") {
26661 						// only use it if it is a recognized country code. Singapore (SG) is a special case.
26662 						norm = data;
26663 						destinationLocale = data.destinationLocale;
26664 						destinationPlan = data.destinationPlan;
26665 					}
26666 					
26667 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
26668 					if (typeof(callback) === 'function') {
26669 						callback(formatted);
26670 					}
26671 				})
26672 			});
26673 		} else if (options && options.assistedDialing && norm.invalid && currentLocale.region !== norm.locale.region) {
26674 			// if this number is not valid for the locale it was parsed with, try again with the current locale
26675 			// console.log("norm is invalid. Attempting to reparse with the current locale");
26676 
26677 			new PhoneNumber(this._join(), {
26678 				locale: currentLocale,
26679 				sync: sync,
26680 				loadParms: loadParams,
26681 				onLoad: ilib.bind(this, function (data) {
26682 					if (data && !data.invalid) {
26683 						norm = data;
26684 					}
26685 					
26686 					formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
26687 					if (typeof(callback) === 'function') {
26688 						callback(formatted);
26689 					}
26690 				})
26691 			});
26692 		} else {
26693 			formatted = this._doNormalize(options, norm, homeLocale, currentLocale, currentPlan, destinationLocale, destinationPlan, sync, loadParams);
26694 			if (typeof(callback) === 'function') {
26695 				callback(formatted);
26696 			}
26697 		}
26698 	},
26699 	
26700 	/**
26701 	 * This function normalizes the current phone number to a canonical format and returns a
26702 	 * string with that phone number. If parts are missing, this function attempts to fill in 
26703 	 * those parts.<p>
26704 	 * 	  
26705 	 * The options object contains a set of properties that can possibly help normalize
26706 	 * this number by providing "extra" information to the algorithm. The options
26707 	 * parameter may be null or an empty object if no hints can be determined before
26708 	 * this call is made. If any particular hint is not
26709 	 * available, it does not need to be present in the options object.<p>
26710 	 * 
26711 	 * The following is a list of hints that the algorithm will look for in the options
26712 	 * object:
26713 	 * 
26714 	 * <ul>
26715 	 * <li><i>mcc</i> the mobile carrier code of the current network upon which this 
26716 	 * phone is operating. This is translated into an IDD country code. This is 
26717 	 * useful if the number being normalized comes from CNAP (callerid) and the
26718 	 * MCC is known.
26719 	 * <li><i>defaultAreaCode</i> the area code of the phone number of the current
26720 	 * device, if available. Local numbers in a person's contact list are most 
26721 	 * probably in this same area code.
26722 	 * <li><i>country</i> the 2 letter ISO 3166 code of the country if it is
26723 	 * known from some other means such as parsing the physical address of the
26724 	 * person associated with the phone number, or the from the domain name 
26725 	 * of the person's email address
26726 	 * <li><i>networkType</i> specifies whether the phone is currently connected to a
26727 	 * CDMA network or a UMTS network. Valid values are the strings "cdma" and "umts".
26728 	 * If one of those two strings are not specified, or if this property is left off
26729 	 * completely, this method will assume UMTS.
26730 	 * </ul>
26731 	 * 
26732 	 * The following are a list of options that control the behaviour of the normalization:
26733 	 * 
26734 	 * <ul>
26735 	 * <li><i>assistedDialing</i> if this is set to true, the number will be normalized
26736 	 * so that it can dialled directly on the type of network this phone is 
26737 	 * currently connected to. This allows customers to dial numbers or use numbers 
26738 	 * in their contact list that are specific to their "home" region when they are 
26739 	 * roaming and those numbers would not otherwise work with the current roaming 
26740 	 * carrier as they are. The home region is 
26741 	 * specified as the phoneRegion system preference that is settable in the 
26742 	 * regional settings app. With assisted dialling, this method will add or 
26743 	 * remove international direct dialling prefixes and country codes, as well as
26744 	 * national trunk access codes, as required by the current roaming carrier and the
26745 	 * home region in order to dial the number properly. If it is not possible to 
26746 	 * construct a full international dialling sequence from the options and hints given,
26747 	 * this function will not modify the phone number, and will return "undefined".
26748 	 * If assisted dialling is false or not specified, then this method will attempt
26749 	 * to add all the information it can to the number so that it is as fully
26750 	 * specified as possible. This allows two numbers to be compared more easily when
26751 	 * those two numbers were otherwise only partially specified.
26752 	 * <li><i>sms</i> set this option to true for the following conditions: 
26753 	 *   <ul>
26754 	 *   <li>assisted dialing is turned on
26755 	 *   <li>the phone number represents the destination of an SMS message
26756 	 *   <li>the phone is UMTS 
26757 	 *   <li>the phone is SIM-locked to its carrier
26758 	 *   </ul> 
26759 	 * This enables special international direct dialling codes to route the SMS message to
26760 	 * the correct carrier. If assisted dialling is not turned on, this option has no
26761 	 * affect.
26762 	 * <li><i>manualDialing</i> set this option to true if the user is entering this number on
26763 	 * the keypad directly, and false when the number comes from a stored location like a 
26764 	 * contact entry or a call log entry. When true, this option causes the normalizer to 
26765 	 * not perform any normalization on numbers that look like local numbers in the home 
26766 	 * country. If false, all numbers go through normalization. This option only has an effect
26767 	 * when the assistedDialing option is true as well, otherwise it is ignored.
26768 	 * </ul> 
26769 	 * 
26770 	 * If both a set of options and a locale are given, and they offer conflicting
26771 	 * information, the options will take precedence. The idea is that the locale
26772 	 * tells you the region setting that the user has chosen (probably in 
26773 	 * firstuse), whereas the the hints are more current information such as
26774 	 * where the phone is currently operating (the MCC).<p> 
26775 	 * 
26776 	 * This function performs the following types of normalizations with assisted
26777 	 * dialling turned on:
26778 	 * 
26779 	 * <ol>
26780 	 * <li>If the current location of the phone matches the home country, this is a
26781 	 * domestic call.
26782 	 *   <ul> 
26783 	 *   <li>Remove any iddPrefix and countryCode fields, as they are not needed
26784 	 *   <li>Add in a trunkAccess field that may be necessary to call a domestic numbers 
26785 	 *     in the home country
26786 	 *   </ul>
26787 	 * <li> If the current location of the phone does not match the home country,
26788 	 * attempt to form a whole international number.
26789 	 *   <ul>
26790 	 *   <li>Add in the area code if it is missing from the phone number and the area code
26791 	 *     of the current phone is available in the hints
26792 	 *   <li>Add the country dialling code for the home country if it is missing from the 
26793 	 *     phone number
26794 	 *   <li>Add or replace the iddPrefix with the correct one for the current country. The
26795 	 *     phone number will have been parsed with the settings for the home country, so
26796 	 *     the iddPrefix may be incorrect for the
26797 	 *     current country. The iddPrefix for the current country can be "+" if the phone 
26798 	 *     is connected to a UMTS network, and either a "+" or a country-dependent 
26799 	 *     sequences of digits for CDMA networks.
26800 	 *   </ul>
26801 	 * </ol>
26802 	 * 
26803 	 * This function performs the following types of normalization with assisted
26804 	 * dialling turned off:
26805 	 * 
26806 	 * <ul>
26807 	 * <li>Normalize the international direct dialing prefix to be a plus or the
26808 	 * international direct dialling access code for the current country, depending
26809 	 * on the network type.
26810 	 * <li>If a number is a local number (ie. it is missing its area code), 
26811 	 * use a default area code from the hints if available. CDMA phones always know their area 
26812 	 * code, and GSM/UMTS phones know their area code in many instances, but not always 
26813 	 * (ie. not on Vodaphone or Telcel phones). If the default area code is not available, 
26814 	 * do not add it.
26815 	 * <li>In assisted dialling mode, if a number is missing its country code, 
26816 	 * use the current MCC number if
26817 	 * it is available to figure out the current country code, and prepend that 
26818 	 * to the number. If it is not available, leave it off. Also, use that 
26819 	 * country's settings to parse the number instead of the current format 
26820 	 * locale.
26821 	 * <li>For North American numbers with an area code but no trunk access 
26822 	 * code, add in the trunk access code.
26823 	 * <li>For other countries, if the country code is added in step 3, remove the 
26824 	 * trunk access code when required by that country's conventions for 
26825 	 * international calls. If the country requires a trunk access code for 
26826 	 * international calls and it doesn't exist, add one.
26827 	 * </ul>
26828 	 *  
26829 	 * This method modifies the current object, and also returns a string 
26830 	 * containing the normalized phone number that can be compared directly against
26831 	 * other normalized numbers. The canonical format for phone numbers that is 
26832 	 * returned from thhomeLocaleis method is simply an uninterrupted and unformatted string 
26833 	 * of dialable digits.
26834 	 * 
26835 	 * @param {{
26836 	 *   mcc:string,
26837 	 *   defaultAreaCode:string,
26838 	 *   country:string,
26839 	 *   networkType:string,
26840 	 *   assistedDialing:boolean,
26841 	 *   sms:boolean,
26842 	 *   manualDialing:boolean
26843 	 * }} options an object containing options to help in normalizing. 
26844 	 * @return {string|undefined} the normalized string, or undefined if the number
26845 	 * could not be normalized
26846 	 */
26847 	normalize: function(options) {
26848 		var norm,
26849 			sync = true,
26850 			loadParams = {};
26851 			
26852 
26853 		if (options) {
26854 			if (typeof(options.sync) !== 'undefined') {
26855 				sync = (options.sync == true);
26856 			}
26857 			
26858 			if (options.loadParams) {
26859 				loadParams = options.loadParams;
26860 			}
26861 		}
26862 		
26863 		// Clone this number, so we don't mess with the original.
26864 		// No need to do this asynchronously because it's a copy constructor which doesn't 
26865 		// load any extra files.
26866 		norm = new PhoneNumber(this);
26867 
26868 		var normalized;
26869 		
26870 		if (options && (typeof(options.mcc) !== 'undefined' || typeof(options.country) !== 'undefined')) {
26871 			new PhoneLocale({
26872 				mcc: options.mcc,
26873 				countryCode: options.countryCode,
26874 				locale: this.locale,
26875 				sync: sync,
26876 				loadParams: loadParams,
26877 				onLoad: ilib.bind(this, function(loc) {
26878 					new NumberingPlan({
26879 						locale: loc,
26880 						sync: sync,
26881 						loadParms: loadParams,
26882 						onLoad: ilib.bind(this, function (plan) {
26883 							this._doReparse(options, norm, this.locale, loc, plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
26884 								normalized = fmt;
26885 								
26886 								if (options && typeof(options.onLoad) === 'function') {
26887 									options.onLoad(fmt);
26888 								}
26889 							});
26890 						})
26891 					});
26892 				})
26893 			});
26894 		} else {
26895 			this._doReparse(options, norm, this.locale, this.locale, this.plan, this.destinationLocale, this.destinationPlan, sync, loadParams, function (fmt) {
26896 				normalized = fmt;
26897 				
26898 				if (options && typeof(options.onLoad) === 'function') {
26899 					options.onLoad(fmt);
26900 				}
26901 			});
26902 		}
26903 
26904 		// return the value for the synchronous case
26905 		return normalized;
26906 	}
26907 };
26908 
26909 
26910 /*< PhoneFmt.js */
26911 /*
26912  * phonefmt.js - Represent a phone number formatter.
26913  * 
26914  * Copyright © 2014-2015, JEDLSoft
26915  *
26916  * Licensed under the Apache License, Version 2.0 (the "License");
26917  * you may not use this file except in compliance with the License.
26918  * You may obtain a copy of the License at
26919  *
26920  *     http://www.apache.org/licenses/LICENSE-2.0
26921  *
26922  * Unless required by applicable law or agreed to in writing, software
26923  * distributed under the License is distributed on an "AS IS" BASIS,
26924  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26925  *
26926  * See the License for the specific language governing permissions and
26927  * limitations under the License.
26928  */
26929 
26930 /*
26931 !depends 
26932 ilib.js 
26933 Locale.js 
26934 NumberingPlan.js
26935 PhoneNumber.js
26936 PhoneLocale.js
26937 Utils.js
26938 JSUtils.js
26939 */
26940 
26941 // !data phonefmt
26942 
26943 
26944 /**
26945  * @class
26946  * Create a new phone number formatter object that formats numbers according to the parameters.<p>
26947  * 
26948  * The options object can contain zero or more of the following parameters:
26949  *
26950  * <ul>
26951  * <li><i>locale</i> locale to use to format this number, or undefined to use the default locale
26952  * <li><i>style</i> the name of style to use to format numbers, or undefined to use the default style
26953  * <li><i>mcc</i> the MCC of the country to use if the number is a local number and the country code is not known
26954  *
26955  * <li><i>onLoad</i> - a callback function to call when the locale data is fully loaded and the address has been 
26956  * parsed. When the onLoad option is given, the address formatter object 
26957  * will attempt to load any missing locale data using the ilib loader callback.
26958  * When the constructor is done (even if the data is already preassembled), the 
26959  * onLoad function is called with the current instance as a parameter, so this
26960  * callback can be used with preassembled or dynamic loading or a mix of the two. 
26961  * 
26962  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
26963  * asynchronously. If this option is given as "false", then the "onLoad"
26964  * callback must be given, as the instance returned from this constructor will
26965  * not be usable for a while. 
26966  *
26967  * <li><i>loadParams</i> - an object containing parameters to pass to the 
26968  * loader callback function when locale data is missing. The parameters are not
26969  * interpretted or modified in any way. They are simply passed along. The object 
26970  * may contain any property/value pairs as long as the calling code is in
26971  * agreement with the loader callback function as to what those parameters mean.
26972  * </ul>
26973  *
26974  * Some regions have more than one style of formatting, and the style parameter
26975  * selects which style the user prefers. An array of style names that this locale
26976  * supports can be found by calling {@link PhoneFmt.getAvailableStyles}. 
26977  * Example phone numbers can be retrieved for each style by calling 
26978  * {@link PhoneFmt.getStyleExample}.
26979  * <p>
26980  *
26981  * If the MCC is given, numbers will be formatted in the manner of the country
26982  * specified by the MCC. If it is not given, but the locale is, the manner of
26983  * the country in the locale will be used. If neither the locale or MCC are not given,
26984  * then the country of the current ilib locale is used. 
26985  *
26986  * @constructor
26987  * @param {Object} options properties that control how this formatter behaves
26988  */
26989 var PhoneFmt = function(options) {
26990 	this.sync = true;
26991 	this.styleName = 'default',
26992 	this.loadParams = {};
26993 
26994 	var locale = new Locale();
26995 
26996 	if (options) {
26997 		if (options.locale) {
26998 			locale = options.locale;
26999 		}
27000 
27001 		if (typeof(options.sync) !== 'undefined') {
27002 			this.sync = (options.sync == true);
27003 		}
27004 
27005 		if (options.loadParams) {
27006 			this.loadParams = options.loadParams;
27007 		}
27008 
27009 		if (options.style) {
27010 			this.style = options.style;
27011 		}
27012 	}
27013 
27014 	new PhoneLocale({
27015 		locale: locale,
27016 		mcc: options && options.mcc,
27017 		countryCode: options && options.countryCode,
27018 		onLoad: ilib.bind(this, function (data) {
27019 			/** @type {PhoneLocale} */
27020 			this.locale = data;
27021 
27022 			new NumberingPlan({
27023 				locale: this.locale,
27024 				sync: this.sync,
27025 				loadParms: this.loadParams,
27026 				onLoad: ilib.bind(this, function (plan) {
27027 					/** @type {NumberingPlan} */
27028 					this.plan = plan;
27029 
27030 					Utils.loadData({
27031 						name: "phonefmt.json",
27032 						object: PhoneFmt,
27033 						locale: this.locale, 
27034 						sync: this.sync,
27035 						loadParams: JSUtils.merge(this.loadParams, {
27036 							returnOne: true
27037 						}),
27038 						callback: ilib.bind(this, function (fmtdata) {
27039 							this.fmtdata = fmtdata;
27040 							
27041 							if (options && typeof(options.onLoad) === 'function') {
27042 								options.onLoad(this);
27043 							}
27044 						})
27045 					});
27046 				})
27047 			});
27048 		})
27049 	});
27050 };
27051 
27052 PhoneFmt.prototype = {
27053 	/**
27054 	 * 
27055 	 * @protected
27056 	 * @param {string} part
27057 	 * @param {Object} formats
27058 	 * @param {boolean} mustUseAll
27059 	 */
27060 	_substituteDigits: function(part, formats, mustUseAll) {
27061 		var formatString,
27062 			formatted = "",
27063 			partIndex = 0,
27064 			templates,
27065 			i;
27066 
27067 		// console.info("Globalization.Phone._substituteDigits: typeof(formats) is " + typeof(formats));
27068 		if (!part) {
27069 			return formatted;
27070 		}
27071 
27072 		if (typeof(formats) === "object") {
27073 			templates = (typeof(formats.template) !== 'undefined') ? formats.template : formats;
27074 			if (part.length > templates.length) {
27075 				// too big, so just use last resort rule.
27076 				throw "part " + part + " is too big. We do not have a format template to format it.";
27077 			}
27078 			// use the format in this array that corresponds to the digit length of this
27079 			// part of the phone number
27080 			formatString =  templates[part.length-1];
27081 			// console.info("Globalization.Phone._substituteDigits: formats is an Array: " + JSON.stringify(formats));
27082 		} else {
27083 			formatString = formats;
27084 		}
27085 
27086 		for (i = 0; i < formatString.length; i++) {
27087 			if (formatString.charAt(i) === "X") {
27088 				formatted += part.charAt(partIndex);
27089 				partIndex++;
27090 			} else {
27091 				formatted += formatString.charAt(i);
27092 			}
27093 		}
27094 		
27095 		if (mustUseAll && partIndex < part.length-1) {
27096 			// didn't use the whole thing in this format? Hmm... go to last resort rule
27097 			throw "too many digits in " + part + " for format " + formatString;
27098 		}
27099 		
27100 		return formatted;
27101 	},
27102 	
27103 	/**
27104 	 * Returns the style with the given name, or the default style if there
27105 	 * is no style with that name.
27106 	 * @protected
27107 	 * @return {{example:string,whole:Object.<string,string>,partial:Object.<string,string>}|Object.<string,string>}
27108 	 */
27109 	_getStyle: function (name, fmtdata) {
27110 		return fmtdata[name] || fmtdata["default"];
27111 	},
27112 
27113 	/**
27114 	 * Do the actual work of formatting the phone number starting at the given
27115 	 * field in the regular field order.
27116 	 * 
27117 	 * @param {!PhoneNumber} number
27118 	 * @param {{
27119 	 *   partial:boolean,
27120 	 *   style:string,
27121 	 *   mcc:string,
27122 	 *   locale:(string|Locale),
27123 	 *   sync:boolean,
27124 	 *   loadParams:Object,
27125 	 *   onLoad:function(string)
27126 	 * }} options Parameters which control how to format the number
27127 	 * @param {number} startField
27128 	 */
27129 	_doFormat: function(number, options, startField, locale, fmtdata, callback) {
27130 		var sync = true,
27131 			loadParams = {},
27132 			temp, 
27133 			templates, 
27134 			fieldName, 
27135 			countryCode, 
27136 			isWhole, 
27137 			style,
27138 			formatted = "",
27139 			styleTemplates,
27140 			lastFieldName;
27141 	
27142 		if (options) {
27143 			if (typeof(options.sync) !== 'undefined') {
27144 				sync = (options.sync == true);				
27145 			}
27146 		
27147 			if (options.loadParams) {
27148 				loadParams = options.loadParams;
27149 			}
27150 		}
27151 	
27152 		style = this.style; // default style for this formatter
27153 
27154 		// figure out what style to use for this type of number
27155 		if (number.countryCode) {
27156 			// dialing from outside the country
27157 			// check to see if it to a mobile number because they are often formatted differently
27158 			style = (number.mobilePrefix) ? "internationalmobile" : "international";
27159 		} else if (number.mobilePrefix !== undefined) {
27160 			style = "mobile";
27161 		} else if (number.serviceCode !== undefined && typeof(fmtdata["service"]) !== 'undefined') {
27162 			// if there is a special format for service numbers, then use it
27163 			style = "service";
27164 		}
27165 
27166 		isWhole = (!options || !options.partial);
27167 		styleTemplates = this._getStyle(style, fmtdata);
27168 		
27169 		// console.log("Style ends up being " + style + " and using subtype " + (isWhole ? "whole" : "partial"));
27170 		styleTemplates = (isWhole ? styleTemplates.whole : styleTemplates.partial) || styleTemplates;
27171 
27172 		for (var i = startField; i < PhoneNumber._fieldOrder.length; i++) {
27173 			fieldName = PhoneNumber._fieldOrder[i];
27174 			// console.info("format: formatting field " + fieldName + " value: " + number[fieldName]);
27175 			if (number[fieldName] !== undefined) {
27176 				if (styleTemplates[fieldName] !== undefined) {
27177 					templates = styleTemplates[fieldName];
27178 					if (fieldName === "trunkAccess") {
27179 						if (number.areaCode === undefined && number.serviceCode === undefined && number.mobilePrefix === undefined) {
27180 							templates = "X";
27181 						}
27182 					}
27183 					if (lastFieldName && typeof(styleTemplates[lastFieldName].suffix) !== 'undefined') {
27184 						if (fieldName !== "extension" && number[fieldName].search(/[xwtp,;]/i) <= -1) {
27185 							formatted += styleTemplates[lastFieldName].suffix;	
27186 						}
27187 					}
27188 					lastFieldName = fieldName;
27189 					
27190 					// console.info("format: formatting field " + fieldName + " with templates " + JSON.stringify(templates));
27191 					temp = this._substituteDigits(number[fieldName], templates, (fieldName === "subscriberNumber"));
27192 					// console.info("format: formatted is: " + temp);
27193 					formatted += temp;
27194 	
27195 					if (fieldName === "countryCode") {
27196 						// switch to the new country to format the rest of the number
27197 						countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
27198 
27199 						new PhoneLocale({
27200 							locale: this.locale,
27201 							sync: sync,							
27202 							loadParms: loadParams,
27203 							countryCode: countryCode,
27204 							onLoad: ilib.bind(this, function (/** @type {PhoneLocale} */ locale) {
27205 								Utils.loadData({
27206 									name: "phonefmt.json",
27207 									object: PhoneFmt,
27208 									locale: locale,
27209 									sync: sync,
27210 									loadParams: JSUtils.merge(loadParams, {
27211 										returnOne: true
27212 									}),
27213 									callback: ilib.bind(this, function (fmtdata) {
27214 										// console.info("format: switching to region " + locale.region + " and style " + style + " to format the rest of the number ");
27215 										
27216 										var subfmt = "";
27217 
27218 										this._doFormat(number, options, i+1, locale, fmtdata, function (subformat) {
27219 											subfmt = subformat;
27220 											if (typeof(callback) === 'function') {
27221 												callback(formatted + subformat);
27222 											}
27223 										});
27224 										
27225 										formatted += subfmt;
27226 									})
27227 								});
27228 							})
27229 						});
27230 						return formatted;
27231 					}
27232 				} else {
27233 					//console.warn("PhoneFmt.format: cannot find format template for field " + fieldName + ", region " + locale.region + ", style " + style);
27234 					// use default of "minimal formatting" so we don't miss parts because of bugs in the format templates
27235 					formatted += number[fieldName];
27236 				}
27237 			}
27238 		}
27239 		
27240 		if (typeof(callback) === 'function') {
27241 			callback(formatted);
27242 		}
27243 
27244 		return formatted;
27245 	},
27246 	
27247 	/**
27248 	 * Format the parts of a phone number appropriately according to the settings in 
27249 	 * this formatter instance.
27250 	 *  
27251 	 * The options can contain zero or more of these properties:
27252 	 * 
27253 	 * <ul>
27254 	 * <li><i>partial</i> boolean which tells whether or not this phone number 
27255 	 * represents a partial number or not. The default is false, which means the number 
27256 	 * represents a whole number. 
27257 	 * <li><i>style</i> style to use to format the number, if different from the 
27258 	 * default style or the style specified in the constructor
27259 	 * <li><i>locale</i> The locale with which to parse the number. This gives a clue as to which
27260      * numbering plan to use.
27261      * <li><i>mcc</i> The mobile carrier code (MCC) associated with the carrier that the phone is 
27262      * currently connected to, if known. This also can give a clue as to which numbering plan to
27263      * use
27264      * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
27265      * loaded. When the onLoad option is given, the DateFmt object will attempt to
27266      * load any missing locale data using the ilib loader callback.
27267      * When the constructor is done (even if the data is already preassembled), the 
27268      * onLoad function is called with the current instance as a parameter, so this
27269      * callback can be used with preassembled or dynamic loading or a mix of the two.
27270      * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27271      * asynchronously. If this option is given as "false", then the "onLoad"
27272      * callback must be given, as the instance returned from this constructor will
27273      * not be usable for a while.
27274      * <li><i>loadParams</i> - an object containing parameters to pass to the 
27275      * loader callback function when locale data is missing. The parameters are not
27276      * interpretted or modified in any way. They are simply passed along. The object 
27277      * may contain any property/value pairs as long as the calling code is in
27278      * agreement with the loader callback function as to what those parameters mean.
27279 	 * </ul>
27280 	 *      
27281 	 * The partial parameter specifies whether or not the phone number contains
27282 	 * a partial phone number or if it is a whole phone number. A partial 
27283 	 * number is usually a number as the user is entering it with a dial pad. The
27284 	 * reason is that certain types of phone numbers should be formatted differently
27285 	 * depending on whether or not it represents a whole number. Specifically, SMS
27286 	 * short codes are formatted differently.<p>
27287 	 * 
27288 	 * Example: a subscriber number of "48773" in the US would get formatted as:
27289 	 * 
27290 	 * <ul>
27291 	 * <li>partial: 487-73  (perhaps the user is in the process of typing a whole phone 
27292 	 * number such as 487-7379)
27293 	 * <li>whole:   48773   (this is the entire SMS short code)
27294 	 * </ul>
27295 	 * 
27296 	 * Any place in the UI where the user types in phone numbers, such as the keypad in 
27297 	 * the phone app, should pass in partial: true to this formatting routine. All other 
27298 	 * places, such as the call log in the phone app, should pass in partial: false, or 
27299 	 * leave the partial flag out of the parameters entirely. 
27300 	 * 
27301 	 * @param {!PhoneNumber} number object containing the phone number to format
27302 	 * @param {{
27303 	 *   partial:boolean,
27304 	 *   style:string,
27305 	 *   mcc:string,
27306 	 *   locale:(string|Locale),
27307 	 *   sync:boolean,
27308 	 *   loadParams:Object,
27309 	 *   onLoad:function(string)
27310 	 * }} options Parameters which control how to format the number
27311 	 * @return {string} Returns the formatted phone number as a string.
27312 	 */
27313 	format: function (number, options) {
27314 		var formatted = "",
27315 		    callback;
27316 
27317 		callback = options && options.onLoad;
27318 
27319 		try {
27320 			this._doFormat(number, options, 0, this.locale, this.fmtdata, function (fmt) {
27321 				formatted = fmt;
27322 				
27323 				if (typeof(callback) === 'function') {
27324 					callback(fmt);
27325 				}
27326 			});
27327 		} catch (e) {
27328 			if (typeof(e) === 'string') { 
27329 				// console.warn("caught exception: " + e + ". Using last resort rule.");
27330 				// if there was some exception, use this last resort rule
27331 				formatted = "";
27332 				for (var field in PhoneNumber._fieldOrder) {
27333 					if (typeof field === 'string' && typeof PhoneNumber._fieldOrder[field] === 'string' && number[PhoneNumber._fieldOrder[field]] !== undefined) {
27334 						// just concatenate without any formatting
27335 						formatted += number[PhoneNumber._fieldOrder[field]];
27336 						if (PhoneNumber._fieldOrder[field] === 'countryCode') {
27337 							formatted += ' ';		// fix for NOV-107894
27338 						}
27339 					}
27340 				}
27341 			} else {
27342 				throw e;
27343 			}
27344 			
27345 			if (typeof(callback) === 'function') {
27346 				callback(formatted);
27347 			}
27348 		}
27349 		return formatted;
27350 	},
27351 	
27352 	/**
27353 	 * Return an array of names of all available styles that can be used with the current 
27354 	 * formatter.
27355 	 * @return {Array.<string>} an array of names of styles that are supported by this formatter
27356 	 */
27357 	getAvailableStyles: function () {
27358 		var ret = [],
27359 			style;
27360 
27361 		if (this.fmtdata) {
27362 			for (style in this.fmtdata) {
27363 				if (this.fmtdata[style].example) {
27364 					ret.push(style);
27365 				}
27366 			}
27367 		}
27368 		return ret;
27369 	},
27370 	
27371 	/**
27372 	 * Return an example phone number formatted with the given style.
27373 	 * 
27374 	 * @param {string|undefined} style style to get an example of, or undefined to use
27375 	 * the current default style for this formatter
27376 	 * @return {string|undefined} an example phone number formatted according to the 
27377 	 * given style, or undefined if the style is not recognized or does not have an 
27378 	 * example 
27379 	 */
27380 	getStyleExample: function (style) {
27381 		return this.fmtdata[style].example || undefined;
27382 	}
27383 };
27384 
27385 
27386 /*< PhoneGeoLocator.js */
27387 /*
27388  * phonegeo.js - Represent a phone number geolocator object.
27389  * 
27390  * Copyright © 2014-2015, JEDLSoft
27391  *
27392  * Licensed under the Apache License, Version 2.0 (the "License");
27393  * you may not use this file except in compliance with the License.
27394  * You may obtain a copy of the License at
27395  *
27396  *     http://www.apache.org/licenses/LICENSE-2.0
27397  *
27398  * Unless required by applicable law or agreed to in writing, software
27399  * distributed under the License is distributed on an "AS IS" BASIS,
27400  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27401  *
27402  * See the License for the specific language governing permissions and
27403  * limitations under the License.
27404  */
27405 
27406 /*
27407 !depends 
27408 ilib.js 
27409 NumberingPlan.js
27410 PhoneLocale.js
27411 PhoneNumber.js
27412 Utils.js
27413 JSUtils.js
27414 ResBundle.js
27415 */
27416 
27417 // !data iddarea area extarea extstates phoneres
27418 
27419 
27420 
27421 /**
27422  * @class
27423  * Create an instance that can geographically locate a phone number.<p>
27424  * 
27425  * The location of the number is calculated according to the following rules:
27426  * 
27427  * <ol>
27428  * <li>If the areaCode property is undefined or empty, or if the number specifies a 
27429  * country code for which we do not have information, then the area property may be 
27430  * missing from the returned object. In this case, only the country object will be returned.
27431  * 
27432  * <li>If there is no area code, but there is a mobile prefix, service code, or emergency 
27433  * code, then a fixed string indicating the type of number will be returned.
27434  * 
27435  * <li>The country object is filled out according to the countryCode property of the phone
27436  * number. 
27437  * 
27438  * <li>If the phone number does not have an explicit country code, the MCC will be used if
27439  * it is available. The country code can be gleaned directly from the MCC. If the MCC 
27440  * of the carrier to which the phone is currently connected is available, it should be 
27441  * passed in so that local phone numbers will look correct.
27442  * 
27443  * <li>If the country's dialling plan mandates a fixed length for phone numbers, and a 
27444  * particular number exceeds that length, then the area code will not be given on the
27445  * assumption that the number has problems in the first place and we cannot guess
27446  * correctly.
27447  * </ol>
27448  * 
27449  * The returned area property varies in specificity according
27450  * to the locale. In North America, the area is no finer than large parts of states
27451  * or provinces. In Germany and the UK, the area can be as fine as small towns.<p>
27452  * 
27453  * If the number passed in is invalid, no geolocation will be performed. If the location
27454  * information about the country where the phone number is located is not available,
27455  * then the area information will be missing and only the country will be available.<p>
27456  * 
27457  * The options parameter can contain any one of the following properties:
27458  * 
27459  * <ul>
27460  * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
27461  * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
27462  * but the phone number being geolocated is in Germany, then this class would return the the names
27463  * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
27464  * phone number in Munich and return the country "Germany" and the area code "Munich"
27465  * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
27466  * If translations are not available, the region and area names are given in English, which should 
27467  * always be available.
27468  * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
27469  * 
27470  * <li><i>onLoad</i> - a callback function to call when the data for the
27471  * locale is fully loaded. When the onLoad option is given, this object 
27472  * will attempt to load any missing locale data using the ilib loader callback.
27473  * When the constructor is done (even if the data is already preassembled), the 
27474  * onLoad function is called with the current instance as a parameter, so this
27475  * callback can be used with preassembled or dynamic loading or a mix of the two. 
27476  * 
27477  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27478  * asynchronously. If this option is given as "false", then the "onLoad"
27479  * callback must be given, as the instance returned from this constructor will
27480  * not be usable for a while. 
27481  *
27482  * <li><i>loadParams</i> - an object containing parameters to pass to the 
27483  * loader callback function when locale data is missing. The parameters are not
27484  * interpretted or modified in any way. They are simply passed along. The object 
27485  * may contain any property/value pairs as long as the calling code is in
27486  * agreement with the loader callback function as to what those parameters mean.
27487  * </ul>
27488  * 
27489  * @constructor
27490  * @param {Object} options parameters controlling the geolocation of the phone number.
27491  */
27492 var PhoneGeoLocator = function(options) {
27493 	var sync = true,
27494 		loadParams = {},
27495 		locale = ilib.getLocale();
27496 
27497 	if (options) {
27498 		if (options.locale) {
27499 			locale = options.locale;
27500 		}
27501 
27502 		if (typeof(options.sync) === 'boolean') {
27503 			sync = options.sync;
27504 		}
27505 		
27506 		if (options.loadParams) {
27507 			loadParams = options.loadParams;
27508 		}
27509 	}
27510 	
27511 	new PhoneLocale({
27512 		locale: locale,
27513 		mcc: options && options.mcc,
27514 		countryCode: options && options.countryCode,
27515 		sync: sync,
27516 		loadParams: loadParams,
27517 		onLoad: ilib.bind(this, function (loc) {
27518 			this.locale = loc;
27519 			new NumberingPlan({
27520 				locale: this.locale,
27521 				sync: sync,
27522 				loadParams: loadParams,
27523 				onLoad: ilib.bind(this, function (plan) {
27524 					this.plan = plan;
27525 					
27526 					new ResBundle({
27527 						locale: this.locale,
27528 						name: "phoneres",
27529 						sync: sync,
27530 						loadParams: loadParams,
27531 						onLoad: ilib.bind(this, function (rb) {
27532 							this.rb = rb;
27533 							
27534 							Utils.loadData({
27535 								name: "iddarea.json",
27536 								object: PhoneGeoLocator,
27537 								nonlocale: true,
27538 								sync: sync,
27539 								loadParams: loadParams,
27540 								callback: ilib.bind(this, function (data) {
27541 									this.regiondata = data;
27542 									Utils.loadData({
27543 										name: "area.json",
27544 										object: PhoneGeoLocator,
27545 										locale: this.locale,
27546 										sync: sync,
27547 										loadParams: JSUtils.merge(loadParams, {
27548 											returnOne: true
27549 										}),
27550 										callback: ilib.bind(this, function (areadata) {
27551 											this.areadata = areadata;
27552 		
27553 											if (options && typeof(options.onLoad) === 'function') {
27554 												options.onLoad(this);
27555 											}
27556 										})
27557 									});
27558 								})
27559 							});
27560 						})
27561 					});
27562 				})
27563 			});
27564 		})
27565 	});
27566 };
27567 
27568 PhoneGeoLocator.prototype = {
27569 	/**
27570 	 * @private
27571 	 * 
27572 	 * Used for locales where the area code is very general, and you need to add in
27573 	 * the initial digits of the subscriber number in order to get the area
27574 	 * 
27575 	 * @param {string} number
27576 	 * @param {Object} stateTable
27577 	 */
27578 	_parseAreaAndSubscriber: function (number, stateTable) {
27579 		var ch,
27580 			i,
27581 			handlerMethod,
27582 			newState,
27583 			prefix = "",
27584 			consumed,
27585 			lastLeaf,
27586 			currentState,
27587 			dot = 14;	// special transition which matches all characters. See AreaCodeTableMaker.java
27588 
27589 		if (!number || !stateTable) {
27590 			// can't parse anything
27591 			return undefined;
27592 		}
27593 
27594 		//console.log("GeoLocator._parseAreaAndSubscriber: parsing number " + number);
27595 
27596 		currentState = stateTable;
27597 		i = 0;
27598 		while (i < number.length) {
27599 			ch = PhoneNumber._getCharacterCode(number.charAt(i));
27600 			if (ch >= 0) {
27601 				// newState = stateData.states[state][ch];
27602 				newState = currentState.s && currentState.s[ch];
27603 				
27604 				if (!newState && currentState.s && currentState.s[dot]) {
27605 					newState = currentState.s[dot];
27606 				}
27607 				
27608 				if (typeof(newState) === 'object') {
27609 					if (typeof(newState.l) !== 'undefined') {
27610 						// save for latter if needed
27611 						lastLeaf = newState;
27612 						consumed = i;
27613 					}
27614 					// console.info("recognized digit " + ch + " continuing...");
27615 					// recognized digit, so continue parsing
27616 					currentState = newState;
27617 					i++;
27618 				} else {
27619 					if (typeof(newState) === 'undefined' || newState === 0) {
27620 						// this is possibly a look-ahead and it didn't work... 
27621 						// so fall back to the last leaf and use that as the
27622 						// final state
27623 						newState = lastLeaf;
27624 						i = consumed;
27625 					}
27626 					
27627 					if ((typeof(newState) === 'number' && newState) ||
27628 						(typeof(newState) === 'object' && typeof(newState.l) !== 'undefined')) {
27629 						// final state
27630 						var stateNumber = typeof(newState) === 'number' ? newState : newState.l;
27631 						handlerMethod = PhoneNumber._states[stateNumber];
27632 
27633 						//console.info("reached final state " + newState + " handler method is " + handlerMethod + " and i is " + i);
27634 	
27635 						return (handlerMethod === "area") ? number.substring(0, i+1) : undefined;
27636 					} else {
27637 						// failed parse. Either no last leaf to fall back to, or there was an explicit
27638 						// zero in the table
27639 						break;
27640 					}
27641 				}
27642 			} else if (ch === -1) {
27643 				// non-transition character, continue parsing in the same state
27644 				i++;
27645 			} else {
27646 				// should not happen
27647 				// console.info("skipping character " + ch);
27648 				// not a digit, plus, pound, or star, so this is probably a formatting char. Skip it.
27649 				i++;
27650 			}
27651 		}
27652 		return undefined;
27653 	},
27654 	/**
27655 	 * @private
27656 	 * @param prefix
27657 	 * @param table
27658 	 * @returns
27659 	 */
27660 	_matchPrefix: function(prefix, table)  {
27661 		var i, matchedDot, matchesWithDots = [];
27662 
27663 		if (table[prefix]) {
27664 			return table[prefix];
27665 		}
27666 		for (var entry in table) {
27667 			if (entry && typeof(entry) === 'string') {
27668 				i = 0;
27669 				matchedDot = false;
27670 				while (i < entry.length && (entry.charAt(i) === prefix.charAt(i) || entry.charAt(i) === '.')) {
27671 					if (entry.charAt(i) === '.') {
27672 						matchedDot = true;
27673 					}
27674 					i++;
27675 				}
27676 				if (i >= entry.length) {
27677 					if (matchedDot) {
27678 						matchesWithDots.push(entry);
27679 					} else {
27680 						return table[entry];
27681 					}
27682 				}
27683 			}
27684 		}
27685 
27686 		// match entries with dots last, so sort the matches so that the entry with the 
27687 		// most dots sorts last. The entry that ends up at the beginning of the list is
27688 		// the best match because it has the fewest dots
27689 		if (matchesWithDots.length > 0) {
27690 			matchesWithDots.sort(function (left, right) {
27691 				return (right < left) ? -1 : ((left < right) ? 1 : 0);
27692 			});
27693 			return table[matchesWithDots[0]];
27694 		}
27695 		
27696 		return undefined;
27697 	},
27698 	/**
27699 	 * @private
27700 	 * @param number
27701 	 * @param data
27702 	 * @param locale
27703 	 * @param plan
27704 	 * @param options
27705 	 * @returns {Object}
27706 	 */
27707 	_getAreaInfo: function(number, data, locale, plan, options) {
27708 		var sync = true,
27709 			ret = {}, 
27710 			countryCode, 
27711 			areaInfo, 
27712 			temp, 
27713 			areaCode, 
27714 			geoTable, 
27715 			tempNumber, 
27716 			prefix;
27717 
27718 		if (options && typeof(options.sync) === 'boolean') {
27719 			sync = options.sync;
27720 		}
27721 
27722 		prefix = number.areaCode || number.serviceCode;
27723 		geoTable = data;
27724 		
27725 		if (prefix !== undefined) {
27726 			if (plan.getExtendedAreaCode()) {
27727 				// for countries where the area code is very general and large, and you need a few initial
27728 				// digits of the subscriber number in order find the actual area
27729 				tempNumber = prefix + number.subscriberNumber;
27730 				tempNumber = tempNumber.replace(/[wWpPtT\+#\*]/g, '');	// fix for NOV-108200
27731 		
27732 				Utils.loadData({
27733 					name: "extarea.json",
27734 					object: PhoneGeoLocator, 
27735 					locale: locale,
27736 					sync: sync,
27737 					loadParams: JSUtils.merge((options && options.loadParams) || {}, {returnOne: true}),
27738 					callback: ilib.bind(this, function (data) {
27739 						this.extarea = data;
27740 						Utils.loadData({
27741 							name: "extstates.json",
27742 							object: PhoneGeoLocator, 
27743 							locale: locale,
27744 							sync: sync,
27745 							loadParams: JSUtils.merge((options && options.loadParams) || {}, {returnOne: true}),
27746 							callback: ilib.bind(this, function (data) {
27747 								this.extstates = data;
27748 								geoTable = this.extarea;
27749 								if (this.extarea && this.extstates) {
27750 									prefix = this._parseAreaAndSubscriber(tempNumber, this.extstates);
27751 								}
27752 								
27753 								if (!prefix) {
27754 									// not a recognized prefix, so now try the general table
27755 									geoTable = this.areadata;
27756 									prefix = number.areaCode || number.serviceCode;					
27757 								}
27758 
27759 								if ((!plan.fieldLengths || 
27760 								  plan.getFieldLength('maxLocalLength') === undefined ||
27761 								  !number.subscriberNumber ||
27762 								 	number.subscriberNumber.length <= plan.fieldLengths('maxLocalLength'))) {
27763 								  	areaInfo = this._matchPrefix(prefix, geoTable);
27764 									if (areaInfo && areaInfo.sn && areaInfo.ln) {
27765 										//console.log("Found areaInfo " + JSON.stringify(areaInfo));
27766 										ret.area = {
27767 											sn: this.rb.getString(areaInfo.sn).toString(),
27768 											ln: this.rb.getString(areaInfo.ln).toString()
27769 										};
27770 									}
27771 								}		
27772 							})
27773 						});
27774 					})
27775 				});
27776 
27777 			} else if (!plan || 
27778 					plan.getFieldLength('maxLocalLength') === undefined || 
27779 					!number.subscriberNumber ||
27780 					number.subscriberNumber.length <= plan.getFieldLength('maxLocalLength')) {
27781 				if (geoTable) {
27782 					areaCode = prefix.replace(/[wWpPtT\+#\*]/g, '');
27783 					areaInfo = this._matchPrefix(areaCode, geoTable);
27784 
27785 					if (areaInfo && areaInfo.sn && areaInfo.ln) {
27786 						ret.area = {
27787 							sn: this.rb.getString(areaInfo.sn).toString(),
27788 							ln: this.rb.getString(areaInfo.ln).toString()
27789 						};
27790 					} else if (number.serviceCode) {
27791 						ret.area = {
27792 							sn: this.rb.getString("Service Number").toString(),
27793 							ln: this.rb.getString("Service Number").toString()
27794 						};
27795 					}
27796 				} else {
27797 					countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
27798 					if (countryCode !== "0" && this.regiondata) {
27799 						temp = this.regiondata[countryCode];
27800 						if (temp && temp.sn) {
27801 							ret.country = {
27802 								sn: this.rb.getString(temp.sn).toString(),
27803 								ln: this.rb.getString(temp.ln).toString(),
27804 								code: this.locale.getRegion()
27805 							};
27806 						}
27807 					}
27808 				}
27809 			} else {
27810 				countryCode = number.locale._mapRegiontoCC(this.locale.getRegion());
27811 				if (countryCode !== "0" && this.regiondata) {
27812 					temp = this.regiondata[countryCode];
27813 					if (temp && temp.sn) {
27814 						ret.country = {
27815 							sn: this.rb.getString(temp.sn).toString(),
27816 							ln: this.rb.getString(temp.ln).toString(),
27817 							code: this.locale.getRegion()
27818 						};
27819 					}
27820 				}
27821 			}
27822 
27823 		} else if (number.mobilePrefix) {
27824 			ret.area = {
27825 				sn: this.rb.getString("Mobile Number").toString(),
27826 				ln: this.rb.getString("Mobile Number").toString()
27827 			};
27828 		} else if (number.emergency) {
27829 			ret.area = {
27830 				sn: this.rb.getString("Emergency Services Number").toString(),
27831 				ln: this.rb.getString("Emergency Services Number").toString()
27832 			};
27833 		}
27834 
27835 		return ret;
27836 	},
27837 	/**
27838 	 * Returns a the location of the given phone number, if known. 
27839 	 * The returned object has 2 properties, each of which has an sn (short name) 
27840 	 * and an ln (long name) string. Additionally, the country code, if given,
27841 	 * includes the 2 letter ISO code for the recognized country.
27842 	 *	 	{
27843 	 *			"country": {
27844 	 *	        	"sn": "North America",
27845 	 *            	"ln": "North America and the Caribbean Islands",
27846 	 *				"code": "us"
27847 	 *         	 },
27848 	 *         	 "area": {
27849 	 *       	    "sn": "California",
27850 	 *          	 "ln": "Central California: San Jose, Los Gatos, Milpitas, Sunnyvale, Cupertino, Gilroy"
27851 	 *         	 }
27852 	 *    	 }
27853 	 * 
27854 	 * The location name is subject to the following rules:
27855 	 *
27856 	 * If the areaCode property is undefined or empty, or if the number specifies a 
27857 	 * country code for which we do not have information, then the area property may be 
27858 	 * missing from the returned object. In this case, only the country object will be returned.
27859 	 *
27860 	 * If there is no area code, but there is a mobile prefix, service code, or emergency 
27861 	 * code, then a fixed string indicating the type of number will be returned.
27862 	 * 
27863 	 * The country object is filled out according to the countryCode property of the phone
27864 	 * number. 
27865 	 * 
27866 	 * If the phone number does not have an explicit country code, the MCC will be used if
27867 	 * it is available. The country code can be gleaned directly from the MCC. If the MCC 
27868 	 * of the carrier to which the phone is currently connected is available, it should be 
27869 	 * passed in so that local phone numbers will look correct.
27870 	 * 
27871 	 * If the country's dialling plan mandates a fixed length for phone numbers, and a 
27872 	 * particular number exceeds that length, then the area code will not be given on the
27873 	 * assumption that the number has problems in the first place and we cannot guess
27874 	 * correctly.
27875 	 *
27876 	 * The returned area property varies in specificity according
27877 	 * to the locale. In North America, the area is no finer than large parts of states
27878 	 * or provinces. In Germany and the UK, the area can be as fine as small towns.
27879 	 *
27880 	 * The strings returned from this function are already localized to the 
27881 	 * given locale, and thus are ready for display to the user.
27882 	 *
27883 	 * If the number passed in is invalid, an empty object is returned. If the location
27884 	 * information about the country where the phone number is located is not available,
27885 	 * then the area information will be missing and only the country will be returned.
27886      *
27887 	 * The options parameter can contain any one of the following properties:
27888  	 * 
27889  	 * <ul>
27890  	 * <li><i>locale</i> The locale parameter is used to load translations of the names of regions and
27891  	 * areas if available. For example, if the locale property is given as "en-US" (English for USA), 
27892  	 * but the phone number being geolocated is in Germany, then this class would return the the names
27893  	 * of the country (Germany) and region inside of Germany in English instead of German. That is, a 
27894  	 * phone number in Munich and return the country "Germany" and the area code "Munich"
27895  	 * instead of "Deutschland" and "München". The default display locale is the current ilib locale. 
27896  	 * If translations are not available, the region and area names are given in English, which should 
27897  	 * always be available.
27898  	 * <li><i>mcc</i> The mcc of the current mobile carrier, if known.
27899  	 * 
27900  	 * <li><i>onLoad</i> - a callback function to call when the data for the
27901  	 * locale is fully loaded. When the onLoad option is given, this object 
27902  	 * will attempt to load any missing locale data using the ilib loader callback.
27903  	 * When the constructor is done (even if the data is already preassembled), the 
27904  	 * onLoad function is called with the current instance as a parameter, so this
27905  	 * callback can be used with preassembled or dynamic loading or a mix of the two. 
27906  	 * 
27907  	 * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
27908  	 * asynchronously. If this option is given as "false", then the "onLoad"
27909  	 * callback must be given, as the instance returned from this constructor will
27910  	 * not be usable for a while. 
27911  	 *
27912  	 * <li><i>loadParams</i> - an object containing parameters to pass to the 
27913  	 * loader callback function when locale data is missing. The parameters are not
27914  	 * interpretted or modified in any way. They are simply passed along. The object 
27915  	 * may contain any property/value pairs as long as the calling code is in
27916  	 * agreement with the loader callback function as to what those parameters mean.
27917  	 * </ul>
27918 	 * 
27919 	 * @param {PhoneNumber} number phone number to locate
27920 	 * @param {Object} options options governing the way this ares is loaded
27921 	 * @return {Object} an object  
27922 	 * that describes the country and the area in that country corresponding to this
27923 	 * phone number. Each of the country and area contain a short name (sn) and long
27924 	 * name (ln) that describes the location.
27925 	 */
27926 	locate: function(number, options) {
27927 		var loadParams = {},
27928 			ret = {}, 
27929 			region, 
27930 			countryCode, 
27931 			temp, 
27932 			plan,
27933 			areaResult,
27934 			phoneLoc = this.locale,
27935 			sync = true;
27936 
27937 		if (number === undefined || typeof(number) !== 'object' || !(number instanceof PhoneNumber)) {
27938 			return ret;
27939 		}
27940 
27941 		if (options) {
27942 			if (typeof(options.sync) !== 'undefined') {
27943 				sync = (options.sync == true);
27944 			}
27945 		
27946 			if (options.loadParams) {
27947 				loadParams = options.loadParams;
27948 			}
27949 		}
27950 
27951 		// console.log("GeoLocator.locate: looking for geo for number " + JSON.stringify(number));
27952 		region = this.locale.getRegion();
27953 		if (number.countryCode !== undefined && this.regiondata) {
27954 			countryCode = number.countryCode.replace(/[wWpPtT\+#\*]/g, '');
27955 			temp = this.regiondata[countryCode];
27956 			phoneLoc = number.destinationLocale;
27957 			plan = number.destinationPlan;
27958 			ret.country = {
27959 				sn: this.rb.getString(temp.sn).toString(),
27960 				ln: this.rb.getString(temp.ln).toString(),
27961 				code: phoneLoc.getRegion()
27962 			};
27963 		}
27964 		
27965 		if (!plan) {
27966 			plan = this.plan;
27967 		}
27968 		
27969 		Utils.loadData({
27970 			name: "area.json",
27971 			object: PhoneGeoLocator,
27972 			locale: phoneLoc,
27973 			sync: sync,
27974 			loadParams: JSUtils.merge(loadParams, {
27975 				returnOne: true
27976 			}),
27977 			callback: ilib.bind(this, function (areadata) {
27978 				if (areadata) {
27979 					this.areadata = areadata;	
27980 				}
27981 				areaResult = this._getAreaInfo(number, this.areadata, phoneLoc, plan, options);
27982 				ret = JSUtils.merge(ret, areaResult);
27983 
27984 				if (ret.country === undefined) {
27985 					countryCode = number.locale._mapRegiontoCC(region);
27986 					
27987 					if (countryCode !== "0" && this.regiondata) {
27988 						temp = this.regiondata[countryCode];
27989 						if (temp && temp.sn) {
27990 							ret.country = {
27991 								sn: this.rb.getString(temp.sn).toString(),
27992 								ln: this.rb.getString(temp.ln).toString(),
27993 								code: this.locale.getRegion()
27994 							};
27995 						}
27996 					}
27997 				}
27998 			})
27999 		});
28000 		
28001 		return ret;
28002 	},
28003 	
28004 	/**
28005 	 * Returns a string that describes the ISO-3166-2 country code of the given phone
28006 	 * number.<p> 
28007 	 * 
28008 	 * If the phone number is a local phone number and does not contain
28009 	 * any country information, this routine will return the region for the current
28010 	 * formatter instance.
28011      *
28012 	 * @param {PhoneNumber} number An PhoneNumber instance
28013 	 * @return {string}
28014 	 */
28015 	country: function(number) {
28016 		var countryCode,
28017 			region,
28018 			phoneLoc;
28019 
28020 		if (!number || !(number instanceof PhoneNumber)) {
28021 			return "";
28022 		}
28023 
28024 		phoneLoc = number.locale;
28025 
28026 		region = (number.countryCode && phoneLoc._mapCCtoRegion(number.countryCode)) ||
28027 			(number.locale && number.locale.region) || 
28028 			phoneLoc.locale.getRegion() ||
28029 			this.locale.getRegion();
28030 
28031 		countryCode = number.countryCode || phoneLoc._mapRegiontoCC(region);
28032 		
28033 		if (number.areaCode) {
28034 			region = phoneLoc._mapAreatoRegion(countryCode, number.areaCode);
28035 		} else if (countryCode === "33" && number.serviceCode) {
28036 			// french departments are in the service code, not the area code
28037 			region = phoneLoc._mapAreatoRegion(countryCode, number.serviceCode);
28038 		}		
28039 		return region;
28040 	}
28041 };
28042 
28043 
28044 /*< Measurement.js */
28045 /*
28046  * Measurement.js - Measurement unit superclass
28047  * 
28048  * Copyright © 2014-2015, JEDLSoft
28049  *
28050  * Licensed under the Apache License, Version 2.0 (the "License");
28051  * you may not use this file except in compliance with the License.
28052  * You may obtain a copy of the License at
28053  *
28054  *     http://www.apache.org/licenses/LICENSE-2.0
28055  *
28056  * Unless required by applicable law or agreed to in writing, software
28057  * distributed under the License is distributed on an "AS IS" BASIS,
28058  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28059  *
28060  * See the License for the specific language governing permissions and
28061  * limitations under the License.
28062  */
28063 
28064 /**
28065  * @class
28066  * Superclass for measurement instances that contains shared functionality
28067  * and defines the interface. <p>
28068  * 
28069  * This class is never instantiated on its own. Instead, measurements should
28070  * be created using the {@link MeasurementFactory} function, which creates the
28071  * correct subclass based on the given parameters.<p>
28072  * 
28073  * @private
28074  * @constructor 
28075  */
28076 var Measurement = function() {
28077 };
28078 
28079 /**
28080  * @private
28081  */
28082 Measurement._constructors = {};
28083 
28084 Measurement.prototype = {
28085 	/**
28086 	 * Return the normalized name of the given units. If the units are
28087 	 * not recognized, this method returns its parameter unmodified.<p>
28088 	 * 
28089 	 * Examples:
28090 	 * 
28091 	 * <ui>
28092 	 * <li>"metres" gets normalized to "meter"<br>
28093 	 * <li>"ml" gets normalized to "milliliter"<br>
28094 	 * <li>"foobar" gets normalized to "foobar" (no change because it is not recognized)
28095 	 * </ul>
28096 	 *  
28097 	 * @param {string} name name of the units to normalize. 
28098 	 * @returns {string} normalized name of the units
28099 	 */
28100 	normalizeUnits: function(name) {
28101 		return this.aliases[name] || name;
28102 	},
28103 
28104 	/**
28105 	 * Return the normalized units used in this measurement.
28106 	 * @return {string} name of the unit of measurement 
28107 	 */
28108 	getUnit: function() {
28109 		return this.unit;
28110 	},
28111      
28112 	/**
28113 	 * Return the units originally used to construct this measurement
28114 	 * before it was normalized.
28115 	 * @return {string} name of the unit of measurement 
28116 	 */
28117 	getOriginalUnit: function() {
28118 		return this.originalUnit;
28119 	},
28120 	
28121 	/**
28122 	 * Return the numeric amount of this measurement.
28123 	 * @return {number} the numeric amount of this measurement
28124 	 */
28125 	getAmount: function() {
28126 		return this.amount;
28127 	},
28128 	
28129 	/**
28130 	 * Return the type of this measurement. Examples are "mass",
28131 	 * "length", "speed", etc. Measurements can only be converted
28132 	 * to measurements of the same type.<p>
28133 	 * 
28134 	 * The type of the units is determined automatically from the 
28135 	 * units. For example, the unit "grams" is type "mass". Use the 
28136 	 * static call {@link Measurement.getAvailableUnits}
28137 	 * to find out what units this version of ilib supports.
28138 	 * 
28139 	 * @abstract
28140 	 * @return {string} the name of the type of this measurement
28141 	 */
28142 	getMeasure: function() {},
28143 	
28144 	/**
28145 	 * Return a new measurement instance that is converted to a new
28146 	 * measurement unit. Measurements can only be converted
28147 	 * to measurements of the same type.<p>
28148 	 * 
28149 	 * @abstract
28150 	 * @param {string} to The name of the units to convert to
28151 	 * @return {Measurement|undefined} the converted measurement
28152 	 * or undefined if the requested units are for a different
28153 	 * measurement type
28154 	 */
28155 	convert: function(to) {},     
28156         
28157         /**
28158 	 * Scale the measurement unit to an acceptable level. The scaling
28159 	 * happens so that the integer part of the amount is as small as
28160 	 * possible without being below zero. This will result in the 
28161 	 * largest units that can represent this measurement without
28162 	 * fractions. Measurements can only be scaled to other measurements 
28163 	 * of the same type.
28164 	 * 
28165 	 * @abstract
28166 	 * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28167 	 * or undefined if the system can be inferred from the current measure
28168 	 * @return {Measurement} a new instance that is scaled to the 
28169 	 * right level
28170 	 */
28171 	scale: function(measurementsystem) {},
28172         
28173 	/**
28174 	 * Localize the measurement to the commonly used measurement in that locale, for example
28175 	 * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28176 	 * the formatted number should be automatically converted to the most appropriate 
28177 	 * measure in the other system, in this case, mph. The formatted result should
28178 	 * appear as "37.3 mph". 
28179 	 * 
28180 	 * @abstract
28181 	 * @param {string} locale current locale string
28182 	 * @returns {Measurement} a new instance that is converted to locale
28183 	 */
28184 	localize: function(locale) {}
28185 };
28186 
28187 
28188 
28189 /*< UnknownUnit.js */
28190 /*
28191  * Unknown.js - Dummy unit conversions for unknown types
28192  * 
28193  * Copyright © 2014-2015, JEDLSoft
28194  *
28195  * Licensed under the Apache License, Version 2.0 (the "License");
28196  * you may not use this file except in compliance with the License.
28197  * You may obtain a copy of the License at
28198  *
28199  *     http://www.apache.org/licenses/LICENSE-2.0
28200  *
28201  * Unless required by applicable law or agreed to in writing, software
28202  * distributed under the License is distributed on an "AS IS" BASIS,
28203  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28204  *
28205  * See the License for the specific language governing permissions and
28206  * limitations under the License.
28207  */
28208 
28209 // !depends Measurement.js
28210 
28211 
28212 /**
28213  * @class
28214  * Create a new unknown measurement instance.
28215  * 
28216  * @constructor
28217  * @extends Measurement
28218  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28219  * the construction of this instance
28220  */
28221 var UnknownUnit = function (options) {
28222 	if (options) {
28223 		this.unit = options.unit;
28224 		this.amount = options.amount;
28225 	}
28226 };
28227 
28228 UnknownUnit.prototype = new Measurement();
28229 UnknownUnit.prototype.parent = Measurement;
28230 UnknownUnit.prototype.constructor = UnknownUnit;
28231 
28232 UnknownUnit.aliases = {
28233 	"unknown":"unknown"
28234 };
28235 
28236 /**
28237  * Return the type of this measurement. Examples are "mass",
28238  * "length", "speed", etc. Measurements can only be converted
28239  * to measurements of the same type.<p>
28240  * 
28241  * The type of the units is determined automatically from the 
28242  * units. For example, the unit "grams" is type "mass". Use the 
28243  * static call {@link Measurement.getAvailableUnits}
28244  * to find out what units this version of ilib supports.
28245  *  
28246  * @return {string} the name of the type of this measurement
28247  */
28248 UnknownUnit.prototype.getMeasure = function() {
28249 	return "unknown";
28250 };
28251 
28252 /**
28253  * Return a new measurement instance that is converted to a new
28254  * measurement unit. Measurements can only be converted
28255  * to measurements of the same type.<p>
28256  *  
28257  * @param {string} to The name of the units to convert to
28258  * @return {Measurement|undefined} the converted measurement
28259  * or undefined if the requested units are for a different
28260  * measurement type 
28261  */
28262 UnknownUnit.prototype.convert = function(to) {
28263 	return undefined;
28264 };
28265 
28266 /**
28267  * Convert a unknown to another measure.
28268  * @static
28269  * @param {string} to unit to convert to
28270  * @param {string} from unit to convert from
28271  * @param {number} unknown amount to be convert
28272  * @returns {number|undefined} the converted amount
28273  */
28274 UnknownUnit.convert = function(to, from, unknown) {
28275     return undefined;
28276 };
28277 
28278 /**
28279  * Localize the measurement to the commonly used measurement in that locale. For example
28280  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28281  * the formatted number should be automatically converted to the most appropriate 
28282  * measure in the other system, in this case, mph. The formatted result should
28283  * appear as "37.3 mph". 
28284  * 
28285  * @abstract
28286  * @param {string} locale current locale string
28287  * @returns {Measurement} a new instance that is converted to locale
28288  */
28289 UnknownUnit.prototype.localize = function(locale) {
28290     return new UnknownUnit({
28291         unit: this.unit,
28292         amount: this.amount
28293     });
28294 };
28295 
28296 /**
28297  * Scale the measurement unit to an acceptable level. The scaling
28298  * happens so that the integer part of the amount is as small as
28299  * possible without being below zero. This will result in the 
28300  * largest units that can represent this measurement without
28301  * fractions. Measurements can only be scaled to other measurements 
28302  * of the same type.
28303  * 
28304  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28305  * or undefined if the system can be inferred from the current measure
28306  * @return {Measurement} a new instance that is scaled to the 
28307  * right level
28308  */
28309 UnknownUnit.prototype.scale = function(measurementsystem) {
28310     return new UnknownUnit({
28311         unit: this.unit,
28312         amount: this.amount
28313     }); 
28314 };
28315 
28316 /**
28317  * @private
28318  * @static
28319  */
28320 UnknownUnit.getMeasures = function () {
28321 	return [];
28322 };
28323 
28324 
28325 /*< AreaUnit.js */
28326 /*
28327  * area.js - Unit conversions for Area
28328  * 
28329  * Copyright © 2014-2015, JEDLSoft
28330  *
28331  * Licensed under the Apache License, Version 2.0 (the "License");
28332  * you may not use this file except in compliance with the License.
28333  * You may obtain a copy of the License at
28334  *
28335  *     http://www.apache.org/licenses/LICENSE-2.0
28336  *
28337  * Unless required by applicable law or agreed to in writing, software
28338  * distributed under the License is distributed on an "AS IS" BASIS,
28339  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28340  *
28341  * See the License for the specific language governing permissions and
28342  * limitations under the License.
28343  */
28344 
28345 /*
28346 !depends 
28347 Measurement.js
28348 */
28349 
28350 
28351 /**
28352  * @class
28353  * Create a new area measurement instance.
28354  * @constructor
28355  * @extends Measurement
28356  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28357  * the construction of this instance
28358  */
28359 var AreaUnit = function (options) {
28360 	this.unit = "square meter";
28361 	this.amount = 0;
28362 	this.aliases = AreaUnit.aliases; // share this table in all instances
28363 	
28364 	if (options) {
28365 		if (typeof(options.unit) !== 'undefined') {
28366 			this.originalUnit = options.unit;
28367 			this.unit = this.aliases[options.unit] || options.unit;
28368 		}
28369 		
28370 		if (typeof(options.amount) === 'object') {
28371 			if (options.amount.getMeasure() === "area") {
28372 				this.amount = AreaUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28373 			} else {
28374 				throw "Cannot convert unit " + options.amount.unit + " to area";
28375 			}
28376 		} else if (typeof(options.amount) !== 'undefined') {
28377 			this.amount = parseFloat(options.amount);
28378 		}
28379 	}
28380 	
28381 	if (typeof(AreaUnit.ratios[this.unit]) === 'undefined') {
28382 		throw "Unknown unit: " + options.unit;
28383 	}
28384 };
28385 
28386 AreaUnit.prototype = new Measurement();
28387 AreaUnit.prototype.parent = Measurement;
28388 AreaUnit.prototype.constructor = AreaUnit;
28389 
28390 AreaUnit.ratios = {
28391     /*               index		square cm,		square meter,   hectare,   	square km, 	, square inch 	square foot, 		square yard, 	  	  		acre,			square mile			        */
28392     "square centimeter":[1,   	1,				0.0001,			1e-8,	    1e-10,        0.15500031,	0.00107639104,		0.000119599005,			2.47105381e-8,		3.86102159e-11 		],
28393     "square meter": 	[2,   	10000,			1,              1e-4,       1e-6,         1550,    	 	10.7639,    	  	1.19599,   				0.000247105,		3.861e-7     	    ],
28394     "hectare":      	[3,	 	100000000,  	10000,          1,          0.01,         1.55e+7, 	  	107639,     	 	11959.9,   				2.47105	,			0.00386102    	    ],
28395     "square km":    	[4,	  	10000000000, 	1e+6,          	100,        1,	          1.55e+9, 	  	1.076e+7,   	 	1.196e+6,  				247.105 ,   		0.386102     	    ],
28396     "square inch":  	[5,	  	6.4516,			0.00064516,     6.4516e-8,  6.4516e-10,   1,			0.000771605,	  	0.0007716051, 			1.5942e-7,			2.491e-10    	    ],
28397     "square foot":  	[6,		929.0304,		0.092903,       9.2903e-6,  9.2903e-8,    144,			1,          	  	0.111111,  				2.2957e-5,			3.587e-8    		],
28398     "square yard":  	[7,		8361.2736,		0.836127,       8.3613e-5,  8.3613e-7,    1296,    	  	9,          	  	1,         				0.000206612,		3.2283e-7    	    ],
28399     "acre":         	[8,		40468564.2,		4046.86,        0.404686,   0.00404686,   6.273e+6,	  	43560,      	  	4840,      				1,		    		0.0015625    	    ],
28400     "square mile":  	[9,	   	2.58998811e+10,	2.59e+6,        258.999,    2.58999,      4.014e+9,	 	2.788e+7,   	  	3.098e+6,  				640,     			1   	     		]
28401 }
28402 
28403 /**
28404  * Return the type of this measurement. Examples are "mass",
28405  * "length", "speed", etc. Measurements can only be converted
28406  * to measurements of the same type.<p>
28407  * 
28408  * The type of the units is determined automatically from the 
28409  * units. For example, the unit "grams" is type "mass". Use the 
28410  * static call {@link Measurement.getAvailableUnits}
28411  * to find out what units this version of ilib supports.
28412  *  
28413  * @return {string} the name of the type of this measurement
28414  */
28415 AreaUnit.prototype.getMeasure = function() {
28416 	return "area";
28417 }; 
28418 
28419 /**
28420  * Return a new measurement instance that is converted to a new
28421  * measurement unit. Measurements can only be converted
28422  * to measurements of the same type.<p>
28423  *  
28424  * @param {string} to The name of the units to convert to
28425  * @return {Measurement|undefined} the converted measurement
28426  * or undefined if the requested units are for a different
28427  * measurement type
28428  * 
28429  */
28430 AreaUnit.prototype.convert = function(to) {
28431 	if (!to || typeof(AreaUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
28432 		return undefined;
28433 	}
28434 	return new AreaUnit({
28435 		unit: to, 
28436 		amount: this
28437 	});
28438 };
28439 
28440 AreaUnit.aliases = {
28441     "square centimeter":"square centimeter",
28442     "square cm":"square centimeter",
28443     "sq cm":"square centimeter",
28444     "Square Cm":"square centimeter",
28445     "square Centimeters":"square centimeter",
28446     "square Centimeter":"square centimeter",
28447     "square Centimetre":"square centimeter",
28448     "square Centimetres":"square centimeter",
28449     "square centimeters":"square centimeter",
28450     "Square km": "square km",
28451 	"Square kilometre":"square km",
28452 	"square kilometer":"square km",
28453 	"square kilometre":"square km",
28454 	"square kilometers":"square km",
28455 	"square kilometres":"square km",
28456     "square km":"square km",
28457 	"sq km":"square km",
28458 	"km2":"square km",
28459 	"Hectare":"hectare",
28460 	"hectare":"hectare",
28461 	"ha":"hectare",
28462 	"Square meter": "square meter",
28463 	"Square meters":"square meter",
28464 	"square meter": "square meter",
28465 	"square meters":"square meter",
28466 	"Square metre": "square meter",
28467 	"Square metres":"square meter",
28468 	"square metres": "square meter",
28469 	"Square Metres":"square meter",
28470 	"sqm":"square meter",
28471 	"m2": "square meter",
28472 	"Square mile":"square mile",
28473 	"Square miles":"square mile",
28474 	"square mile":"square mile",
28475 	"square miles":"square mile",
28476 	"square mi":"square mile",
28477 	"Square mi":"square mile",
28478 	"sq mi":"square mile",
28479 	"mi2":"square mile",
28480 	"Acre": "acre",
28481 	"acre": "acre",
28482 	"Acres":"acre",
28483 	"acres":"acre",
28484 	"Square yard": "square yard",
28485 	"Square yards":"square yard",
28486 	"square yard": "square yard",
28487 	"square yards":"square yard",
28488 	"yd2":"square yard",
28489 	"Square foot": "square foot",
28490 	"square foot": "square foot",
28491 	"Square feet": "square foot",
28492 	"Square Feet": "square foot",
28493 	"sq ft":"square foot",
28494 	"ft2":"square foot",
28495 	"Square inch":"square inch",
28496 	"square inch":"square inch",
28497 	"Square inches":"square inch",
28498 	"square inches":"square inch",
28499 	"in2":"square inch"
28500 };
28501 
28502 /**
28503  * Convert a Area to another measure.
28504  * @static
28505  * @param to {string} unit to convert to
28506  * @param from {string} unit to convert from
28507  * @param area {number} amount to be convert
28508  * @returns {number|undefined} the converted amount
28509  */
28510 AreaUnit.convert = function(to, from, area) {
28511     from = AreaUnit.aliases[from] || from;
28512     to = AreaUnit.aliases[to] || to;
28513 	var fromRow = AreaUnit.ratios[from];
28514 	var toRow = AreaUnit.ratios[to];
28515 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
28516 		return undefined;
28517 	}
28518 	return area* fromRow[toRow[0]];
28519 };
28520 
28521 /**
28522  * @private
28523  * @static
28524  */
28525 AreaUnit.getMeasures = function () {
28526 	var ret = [];
28527 	for (var m in AreaUnit.ratios) {
28528 		ret.push(m);
28529 	}
28530 	return ret;
28531 };
28532 
28533 AreaUnit.metricSystem = {
28534 	"square centimeter" : 1,
28535 	"square meter" : 2,
28536 	"hectare" : 3,
28537 	"square km" : 4
28538 };
28539 AreaUnit.imperialSystem = {
28540 	"square inch" : 5,
28541 	"square foot" : 6,
28542 	"square yard" : 7,
28543 	"acre" : 8,
28544 	"square mile" : 9
28545 };
28546 AreaUnit.uscustomarySystem = {
28547 	"square inch" : 5,
28548 	"square foot" : 6,
28549 	"square yard" : 7,
28550 	"acre" : 8,
28551 	"square mile" : 9
28552 };
28553 
28554 AreaUnit.metricToUScustomary = {
28555 	"square centimeter" : "square inch",
28556 	"square meter" : "square yard",
28557 	"hectare" : "acre",
28558 	"square km" : "square mile"
28559 };
28560 AreaUnit.usCustomaryToMetric = {
28561 	"square inch" : "square centimeter",
28562 	"square foot" : "square meter",
28563 	"square yard" : "square meter",
28564 	"acre" : "hectare",
28565 	"square mile" : "square km"
28566 };
28567 
28568 
28569 /**
28570  * Scale the measurement unit to an acceptable level. The scaling
28571  * happens so that the integer part of the amount is as small as
28572  * possible without being below zero. This will result in the 
28573  * largest units that can represent this measurement without
28574  * fractions. Measurements can only be scaled to other measurements 
28575  * of the same type.
28576  * 
28577  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28578  * or undefined if the system can be inferred from the current measure
28579  * @return {Measurement} a new instance that is scaled to the 
28580  * right level
28581  */
28582 AreaUnit.prototype.scale = function(measurementsystem) {
28583     var fromRow = AreaUnit.ratios[this.unit];
28584     var mSystem;
28585 
28586     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined'
28587         && typeof(AreaUnit.metricSystem[this.unit]) !== 'undefined')) {
28588         mSystem = AreaUnit.metricSystem;
28589     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
28590         && typeof(AreaUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
28591         mSystem = AreaUnit.uscustomarySystem;
28592     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined'
28593         && typeof(AreaUnit.imperialSystem[this.unit]) !== 'undefined')) {
28594         mSystem = AreaUnit.imperialSystem;
28595     }
28596 
28597     var area = this.amount;
28598     var munit = this.unit;
28599 
28600     area = 18446744073709551999;
28601     
28602     for (var m in mSystem) {
28603         var tmp = this.amount * fromRow[mSystem[m]];
28604         if (tmp >= 1 && tmp < area) {
28605 	        area = tmp;
28606 	        munit = m;
28607         }
28608     }
28609 
28610     return new AreaUnit({
28611         unit: munit,
28612         amount: area
28613     });
28614 };
28615 
28616 /**
28617  * Localize the measurement to the commonly used measurement in that locale. For example
28618  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28619  * the formatted number should be automatically converted to the most appropriate 
28620  * measure in the other system, in this case, mph. The formatted result should
28621  * appear as "37.3 mph". 
28622  * 
28623  * @abstract
28624  * @param {string} locale current locale string
28625  * @returns {Measurement} a new instance that is converted to locale
28626  */
28627 AreaUnit.prototype.localize = function(locale) {
28628     var to;
28629     if (locale === "en-US" || locale === "en-GB") {
28630         to = AreaUnit.metricToUScustomary[this.unit] || this.unit;
28631     } else {
28632         to = AreaUnit.usCustomaryToMetric[this.unit] || this.unit;
28633     }
28634     return new AreaUnit({
28635         unit: to,
28636         amount: this
28637     });
28638 };
28639 
28640 
28641 //register with the factory method
28642 Measurement._constructors["area"] = AreaUnit;
28643 
28644 
28645 /*< DigitalStorageUnit.js */
28646 /*
28647  * digitalStorage.js - Unit conversions for Digital Storage
28648  * 
28649  * Copyright © 2014-2015, JEDLSoft
28650  *
28651  * Licensed under the Apache License, Version 2.0 (the "License");
28652  * you may not use this file except in compliance with the License.
28653  * You may obtain a copy of the License at
28654  *
28655  *     http://www.apache.org/licenses/LICENSE-2.0
28656  *
28657  * Unless required by applicable law or agreed to in writing, software
28658  * distributed under the License is distributed on an "AS IS" BASIS,
28659  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28660  *
28661  * See the License for the specific language governing permissions and
28662  * limitations under the License.
28663  */
28664 
28665 /*
28666 !depends 
28667 Measurement.js
28668 */
28669 
28670 
28671 /**
28672  * @class
28673  * Create a new DigitalStorage measurement instance.
28674  *  
28675  * @constructor
28676  * @extends Measurement
28677  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
28678  * the construction of this instance
28679  */
28680 var DigitalStorageUnit = function (options) {
28681 	this.unit = "byte";
28682 	this.amount = 0;
28683 	this.aliases = DigitalStorageUnit.aliases; // share this table in all instances
28684 	
28685 	if (options) {
28686 		if (typeof(options.unit) !== 'undefined') {
28687 			this.originalUnit = options.unit;
28688 			this.unit = this.aliases[options.unit] || options.unit;
28689 		}
28690 		
28691 		if (typeof(options.amount) === 'object') {
28692 			if (options.amount.getMeasure() === "digitalStorage") {
28693 				this.amount = DigitalStorageUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
28694 			} else {
28695 				throw "Cannot convert unit " + options.amount.unit + " to a digitalStorage";
28696 			}
28697 		} else if (typeof(options.amount) !== 'undefined') {
28698 			this.amount = parseFloat(options.amount);
28699 		}
28700 	}
28701 	
28702 	if (typeof(DigitalStorageUnit.ratios[this.unit]) === 'undefined') {
28703 		throw "Unknown unit: " + options.unit;
28704 	}
28705 };
28706 
28707 DigitalStorageUnit.prototype = new Measurement();
28708 DigitalStorageUnit.prototype.parent = Measurement;
28709 DigitalStorageUnit.prototype.constructor = DigitalStorageUnit;
28710 
28711 DigitalStorageUnit.ratios = {
28712     /*            #    bit             byte            kb              kB              mb              mB              gb               gB               tb               tB               pb               pB   */           
28713 	"bit":      [ 1,   1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7, 1.192092896e-7, 9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13, 8.881784197e-16, 1.110223025e-16 ],
28714     "byte":     [ 2,   8,              1,              0.0078125,      0.0009765625,   7.629394531e-6, 9.536743164e-7, 7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13, 7.105427358e-15, 8.881784197e-16 ],
28715     "kilobit":  [ 3,   1024,           128,            1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13 ],
28716     "kilobyte": [ 4,   8192,           1024,           8,              1,              0.0078125,      0.0009765625,   7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13 ],
28717     "megabit":  [ 5,   1048576,        131072,         1024,           128,            1,              0.125,          0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10 ],
28718     "megabyte": [ 6,   8388608,        1048576,        8192,           1024,           8,              1,              0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10 ],
28719     "gigabit":  [ 7,   1073741824,     134217728,      1048576,        131072,         1024,           128,            1,               0.125,           0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7  ],
28720     "gigabyte": [ 8,   8589934592,     1073741824,     8388608,        1048576,        8192,           1024,           8,               1,               0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7  ],
28721     "terabit":  [ 9,   1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,        131072,         1024,            128,             1,               0.125,           0.0009765625,    1.220703125e-4  ],
28722     "terabyte": [ 10,  8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,        1048576,        8192,            1024,            8,               1,               0.0078125,       0.0009765625    ],
28723     "petabit":  [ 11,  1.125899907e15, 1.407374884e14, 1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,         131072,          1024,            128,             1,               0.125           ],
28724     "petabyte": [ 12,  9.007199255e15, 1.125899907e15, 8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,         1048576,         8192,            1024,            8,               1               ]
28725 };
28726 
28727 DigitalStorageUnit.bitSystem = {
28728     "bit":      1,
28729     "kilobit":  3,
28730     "megabit":  5,
28731     "gigabit":  7,
28732     "terabit":  9,
28733     "petabit":  11
28734 };
28735 DigitalStorageUnit.byteSystem = {
28736     "byte":     2,
28737     "kilobyte": 4,
28738     "megabyte": 6,
28739     "gigabyte": 8,
28740     "terabyte": 10,
28741     "petabyte": 12
28742 };
28743 
28744 /**
28745  * Return the type of this measurement. Examples are "mass",
28746  * "length", "speed", etc. Measurements can only be converted
28747  * to measurements of the same type.<p>
28748  * 
28749  * The type of the units is determined automatically from the 
28750  * units. For example, the unit "grams" is type "mass". Use the 
28751  * static call {@link Measurement.getAvailableUnits}
28752  * to find out what units this version of ilib supports.
28753  *  
28754  * @return {string} the name of the type of this measurement
28755  */
28756 DigitalStorageUnit.prototype.getMeasure = function() {
28757 	return "digitalStorage";
28758 };
28759 
28760 /**
28761  * Return a new measurement instance that is converted to a new
28762  * measurement unit. Measurements can only be converted
28763  * to measurements of the same type.<p>
28764  *  
28765  * @param {string} to The name of the units to convert to
28766  * @return {Measurement|undefined} the converted measurement
28767  * or undefined if the requested units are for a different
28768  * measurement type
28769  * 
28770  */
28771 DigitalStorageUnit.prototype.convert = function(to) {
28772 	if (!to || typeof(DigitalStorageUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
28773 		return undefined;
28774 	}
28775 	return new DigitalStorageUnit({
28776 		unit: to,
28777 		amount: this
28778 	});
28779 };
28780 
28781 /**
28782  * Localize the measurement to the commonly used measurement in that locale. For example
28783  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
28784  * the formatted number should be automatically converted to the most appropriate 
28785  * measure in the other system, in this case, mph. The formatted result should
28786  * appear as "37.3 mph". 
28787  * 
28788  * @abstract
28789  * @param {string} locale current locale string
28790  * @returns {Measurement} a new instance that is converted to locale
28791  */
28792 DigitalStorageUnit.prototype.localize = function(locale) {
28793     return new DigitalStorageUnit({
28794         unit: this.unit,
28795         amount: this.amount
28796     });
28797 };
28798 
28799 /**
28800  * Scale the measurement unit to an acceptable level. The scaling
28801  * happens so that the integer part of the amount is as small as
28802  * possible without being below zero. This will result in the 
28803  * largest units that can represent this measurement without
28804  * fractions. Measurements can only be scaled to other measurements 
28805  * of the same type.
28806  * 
28807  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
28808  * or undefined if the system can be inferred from the current measure
28809  * @return {Measurement} a new instance that is scaled to the 
28810  * right level
28811  */
28812 DigitalStorageUnit.prototype.scale = function(measurementsystem) {
28813     var mSystem;
28814     if (this.unit in DigitalStorageUnit.bitSystem) {
28815     	mSystem = DigitalStorageUnit.bitSystem;
28816     } else {
28817     	mSystem = DigitalStorageUnit.byteSystem;
28818     }
28819     
28820     var dStorage = this.amount;
28821     var munit = this.unit;
28822     var fromRow = DigitalStorageUnit.ratios[this.unit];
28823     
28824     dStorage = 18446744073709551999;
28825     for (var m in mSystem) {
28826     	var tmp = this.amount * fromRow[mSystem[m]];
28827         if (tmp >= 1 && tmp < dStorage) {
28828         	dStorage = tmp;
28829 	        munit = m;
28830         }
28831     }
28832     
28833     return new DigitalStorageUnit({
28834 		unit: munit,
28835 		amount: dStorage
28836     });
28837 };
28838 
28839 DigitalStorageUnit.aliases = {
28840     "bits": "bit",
28841     "bit": "bit",
28842     "Bits": "bit",
28843     "Bit": "bit",
28844     "byte": "byte",
28845     "bytes": "byte",
28846     "Byte": "byte",
28847     "Bytes": "byte",
28848     "kilobits": "kilobit",
28849     "Kilobits": "kilobit",
28850     "KiloBits": "kilobit",
28851     "kiloBits": "kilobit",
28852     "kilobit": "kilobit",
28853     "Kilobit": "kilobit",
28854     "kiloBit": "kilobit",
28855     "KiloBit": "kilobit",
28856     "kb": "kilobit",
28857     "Kb": "kilobit",
28858     "kilobyte": "kilobyte",
28859     "Kilobyte": "kilobyte",
28860     "kiloByte": "kilobyte",
28861     "KiloByte": "kilobyte",
28862     "kilobytes": "kilobyte",
28863     "Kilobytes": "kilobyte",
28864     "kiloBytes": "kilobyte",
28865     "KiloBytes": "kilobyte",
28866     "kB": "kilobyte",
28867     "KB": "kilobyte",
28868     "megabit": "megabit",
28869     "Megabit": "megabit",
28870     "megaBit": "megabit",
28871     "MegaBit": "megabit",
28872     "megabits": "megabit",
28873     "Megabits": "megabit",
28874     "megaBits": "megabit",
28875     "MegaBits": "megabit",
28876     "Mb": "megabit",
28877     "mb": "megabit",
28878     "megabyte": "megabyte",
28879     "Megabyte": "megabyte",
28880     "megaByte": "megabyte",
28881     "MegaByte": "megabyte",
28882     "megabytes": "megabyte",
28883     "Megabytes": "megabyte",
28884     "megaBytes": "megabyte",
28885     "MegaBytes": "megabyte",
28886     "MB": "megabyte",
28887     "mB": "megabyte",
28888     "gigabit": "gigabit",
28889     "Gigabit": "gigabit",
28890     "gigaBit": "gigabit",
28891     "GigaBit": "gigabit",
28892     "gigabits": "gigabit",
28893     "Gigabits": "gigabit",
28894     "gigaBits": "gigabyte",
28895     "GigaBits": "gigabit",
28896     "Gb": "gigabit",
28897     "gb": "gigabit",
28898     "gigabyte": "gigabyte",
28899     "Gigabyte": "gigabyte",
28900     "gigaByte": "gigabyte",
28901     "GigaByte": "gigabyte",
28902     "gigabytes": "gigabyte",
28903     "Gigabytes": "gigabyte",
28904     "gigaBytes": "gigabyte",
28905     "GigaBytes": "gigabyte",
28906     "GB": "gigabyte",
28907     "gB": "gigabyte",
28908     "terabit": "terabit",
28909     "Terabit": "terabit",
28910     "teraBit": "terabit",
28911     "TeraBit": "terabit",
28912     "terabits": "terabit",
28913     "Terabits": "terabit",
28914     "teraBits": "terabit",
28915     "TeraBits": "terabit",
28916     "tb": "terabit",
28917     "Tb": "terabit",
28918     "terabyte": "terabyte",
28919     "Terabyte": "terabyte",
28920     "teraByte": "terabyte",
28921     "TeraByte": "terabyte",
28922     "terabytes": "terabyte",
28923     "Terabytes": "terabyte",
28924     "teraBytes": "terabyte",
28925     "TeraBytes": "terabyte",
28926     "TB": "terabyte",
28927     "tB": "terabyte",
28928     "petabit": "petabit",
28929     "Petabit": "petabit",
28930     "petaBit": "petabit",
28931     "PetaBit": "petabit",
28932     "petabits": "petabit",
28933     "Petabits": "petabit",
28934     "petaBits": "petabit",
28935     "PetaBits": "petabit",
28936     "pb": "petabit",
28937     "Pb": "petabit",
28938     "petabyte": "petabyte",
28939     "Petabyte": "petabyte",
28940     "petaByte": "petabyte",
28941     "PetaByte": "petabyte",
28942     "petabytes": "petabyte",
28943     "Petabytes": "petabyte",
28944     "petaBytes": "petabyte",
28945     "PetaBytes": "petabyte",
28946     "PB": "petabyte",
28947     "pB": "petabyte"
28948 };
28949 
28950 /**
28951  * Convert a digitalStorage to another measure.
28952  * @static
28953  * @param to {string} unit to convert to
28954  * @param from {string} unit to convert from
28955  * @param digitalStorage {number} amount to be convert
28956  * @returns {number|undefined} the converted amount
28957  */
28958 DigitalStorageUnit.convert = function(to, from, digitalStorage) {
28959     from = DigitalStorageUnit.aliases[from] || from;
28960     to = DigitalStorageUnit.aliases[to] || to;
28961 	var fromRow = DigitalStorageUnit.ratios[from];
28962 	var toRow = DigitalStorageUnit.ratios[to];
28963 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
28964 		return undefined;
28965 	}	
28966 	var result = digitalStorage * fromRow[toRow[0]];
28967     return result;
28968 };
28969 
28970 /**
28971  * @private
28972  * @static
28973  */
28974 DigitalStorageUnit.getMeasures = function () {
28975 	var ret = [];
28976 	for (var m in DigitalStorageUnit.ratios) {
28977 		ret.push(m);
28978 	}
28979 	return ret;
28980 };
28981 
28982 //register with the factory method
28983 Measurement._constructors["digitalStorage"] = DigitalStorageUnit;
28984 
28985 
28986 /*< EnergyUnit.js */
28987 /*
28988  * Energy.js - Unit conversions for Energys/energys
28989  *
28990  * Copyright © 2014-2015, JEDLSoft
28991  *
28992  * Licensed under the Apache License, Version 2.0 (the "License");
28993  * you may not use this file except in compliance with the License.
28994  * You may obtain a copy of the License at
28995  *
28996  *     http://www.apache.org/licenses/LICENSE-2.0
28997  *
28998  * Unless required by applicable law or agreed to in writing, software
28999  * distributed under the License is distributed on an "AS IS" BASIS,
29000  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29001  *
29002  * See the License for the specific language governing permissions and
29003  * limitations under the License.
29004  */
29005 
29006 /*
29007 !depends
29008 Measurement.js
29009 */
29010 
29011 
29012 /**
29013  * @class
29014  * Create a new energy measurement instance.
29015  * 
29016  * @constructor
29017  * @extends Measurement
29018  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
29019  * the construction of this instance
29020  */
29021 var EnergyUnit = function (options) {
29022 	this.unit = "joule";
29023 	this.amount = 0;
29024 	this.aliases = EnergyUnit.aliases; // share this table in all instances
29025 
29026 	if (options) {
29027 		if (typeof(options.unit) !== 'undefined') {
29028 			this.originalUnit = options.unit;
29029 			this.unit = this.aliases[options.unit] || options.unit;
29030 		}
29031 
29032 		if (typeof(options.amount) === 'object') {
29033 			if (options.amount.getMeasure() === "energy") {
29034 				this.amount = EnergyUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29035 			} else {
29036 				throw "Cannot convert units " + options.amount.unit + " to a energy";
29037 			}
29038 		} else if (typeof(options.amount) !== 'undefined') {
29039 			this.amount = parseFloat(options.amount);
29040 		}
29041 	}
29042 
29043 	if (typeof(EnergyUnit.ratios[this.unit]) === 'undefined') {
29044 		throw "Unknown unit: " + options.unit;
29045 	}
29046 };
29047 
29048 EnergyUnit.prototype = new Measurement();
29049 EnergyUnit.prototype.parent = Measurement;
29050 EnergyUnit.prototype.constructor = EnergyUnit;
29051 
29052 EnergyUnit.ratios = {
29053    /*                index mJ          J           BTU               kJ          Wh                Cal               MJ             kWh                gJ             MWh                 GWh         */
29054     "millijoule":   [ 1,   1,          0.001,      9.4781707775e-7,  1e-6,       2.7777777778e-7,  2.3884589663e-7,  1.0e-9,        2.7777777778e-10,  1.0e-12,       2.7777777778e-13,   2.7777777778e-16  ],
29055     "joule":        [ 2,   1000,       1,          9.4781707775e-4,  0.001,      2.7777777778e-4,  2.3884589663e-4,  1.0e-6,        2.7777777778e-7,   1.0e-9,        2.7777777778e-10,   2.7777777778e-13  ],
29056     "BTU":          [ 3,   1055055.9,  1055.0559,  1,                1.0550559,  0.29307108333,    0.25199577243,    1.0550559e-3,  2.9307108333e-4,   1.0550559e-6,  2.9307108333e-7,    2.9307108333e-10  ],
29057     "kilojoule":    [ 4,   1000000,    1000,       0.94781707775,    1,          0.27777777778,    0.23884589663,    0.001,         2.7777777778e-4,   1.0e-6,        2.7777777778e-7,    2.7777777778e-10  ],
29058     "watt hour":    [ 5,   3.6e+6,     3600,       3.4121414799,     3.6,        1,                0.85984522786,    0.0036,        0.001,             3.6e-6,        1.0e-6,             1.0e-9            ],
29059     "calorie":      [ 6,   4.868e+5,   4186.8,     3.9683205411,     4.1868,     1.163,            1,                4.1868e-3,     1.163e-3,          4.1868e-6,     1.163e-6,           1.163e-9          ],
29060     "megajoule":    [ 7,   1e+9,       1e+6,       947.81707775,     1000,       277.77777778,     238.84589663,     1,             0.27777777778,     0.001,         2.7777777778e-4,    2.7777777778e-7   ],
29061     "kilowatt hour":[ 8,   3.6e+9,     3.6e+6,     3412.1414799,     3600,       1000,             859.84522786,     3.6,           1,                 3.6e-3,        0.001,              1e-6              ],
29062     "gigajoule":    [ 9,   1e+12,      1e+9,       947817.07775,     1e+6,       277777.77778,     238845.89663,     1000,          277.77777778,      1,             0.27777777778,      2.7777777778e-4   ],
29063     "megawatt hour":[ 10,  3.6e+12,    3.6e+9,     3412141.4799,     3.6e+6,     1e+6,             859845.22786,     3600,          1000,              3.6,           1,                  0.001             ],
29064     "gigawatt hour":[ 11,  3.6e+15,    3.6e+12,    3412141479.9,     3.6e+9,     1e+9,             859845227.86,     3.6e+6,        1e+6,              3600,          1000,               1                 ]
29065 };
29066 
29067 /**
29068  * Return the type of this measurement. Examples are "mass",
29069  * "length", "speed", etc. Measurements can only be converted
29070  * to measurements of the same type.<p>
29071  * 
29072  * The type of the units is determined automatically from the 
29073  * units. For example, the unit "grams" is type "mass". Use the 
29074  * static call {@link Measurement.getAvailableUnits}
29075  * to find out what units this version of ilib supports.
29076  *  
29077  * @return {string} the name of the type of this measurement
29078  */
29079 EnergyUnit.prototype.getMeasure = function() {
29080 	return "energy";
29081 };
29082 
29083 /**
29084  * Return a new measurement instance that is converted to a new
29085  * measurement unit. Measurements can only be converted
29086  * to measurements of the same type.<p>
29087  *  
29088  * @param {string} to The name of the units to convert to
29089  * @return {Measurement|undefined} the converted measurement
29090  * or undefined if the requested units are for a different
29091  * measurement type 
29092  */
29093 EnergyUnit.prototype.convert = function(to) {
29094 	if (!to || typeof(EnergyUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29095 		return undefined;
29096 	}
29097 	return new EnergyUnit({
29098 		unit: to,
29099 		amount: this
29100 	});
29101 };
29102 
29103 EnergyUnit.aliases = {
29104     "milli joule": "millijoule",
29105     "millijoule": "millijoule",
29106     "MilliJoule": "millijoule",
29107     "milliJ": "millijoule",
29108     "joule": "joule",
29109     "J": "joule",
29110     "j": "joule",
29111     "Joule": "joule",
29112     "Joules": "joule",
29113     "joules": "joule",
29114     "BTU": "BTU",
29115     "btu": "BTU",
29116     "British thermal unit": "BTU",
29117     "british thermal unit": "BTU",
29118     "kilo joule": "kilojoule",
29119     "kJ": "kilojoule",
29120     "kj": "kilojoule",
29121     "Kj": "kilojoule",
29122     "kiloJoule": "kilojoule",
29123     "kilojoule": "kilojoule",
29124     "kjoule": "kilojoule",
29125     "watt hour": "watt hour",
29126     "Wh": "watt hour",
29127     "wh": "watt hour",
29128     "watt-hour": "watt hour",
29129     "calorie": "calorie",
29130     "Cal": "calorie",
29131     "cal": "calorie",
29132     "Calorie": "calorie",
29133     "calories": "calorie",
29134     "mega joule": "megajoule",
29135     "MJ": "megajoule",
29136     "megajoule": "megajoule",
29137     "megajoules": "megajoule",
29138     "Megajoules": "megajoule",
29139     "megaJoules": "megajoule",
29140     "MegaJoules": "megajoule",
29141     "megaJoule": "megajoule",
29142     "MegaJoule": "megajoule",
29143     "kilo Watt hour": "kilowatt hour",
29144     "kWh": "kilowatt hour",
29145     "kiloWh": "kilowatt hour",
29146     "KiloWh": "kilowatt hour",
29147     "KiloWatt-hour": "kilowatt hour",
29148     "kilowatt hour": "kilowatt hour",
29149     "kilowatt-hour": "kilowatt hour",
29150     "KiloWatt-hours": "kilowatt hour",
29151     "kilowatt-hours": "kilowatt hour",
29152     "Kilo Watt-hour": "kilowatt hour",
29153     "Kilo Watt-hours": "kilowatt hour",
29154     "giga joule": "gigajoule",
29155     "gJ": "gigajoule",
29156     "GJ": "gigajoule",
29157     "GigaJoule": "gigajoule",
29158     "gigaJoule": "gigajoule",
29159     "gigajoule": "gigajoule",   
29160     "GigaJoules": "gigajoule",
29161     "gigaJoules": "gigajoule",
29162     "Gigajoules": "gigajoule",
29163     "gigajoules": "gigajoule",
29164     "mega watt hour": "megawatt hour",
29165     "MWh": "megawatt hour",
29166     "MegaWh": "megawatt hour",
29167     "megaWh": "megawatt hour",
29168     "megaWatthour": "megawatt hour",
29169     "megaWatt-hour": "megawatt hour",
29170     "mega Watt-hour": "megawatt hour",
29171     "megaWatt hour": "megawatt hour",
29172     "megawatt hour": "megawatt hour",
29173     "mega Watt hour": "megawatt hour",
29174     "giga watt hour": "gigawatt hour",
29175     "gWh": "gigawatt hour",
29176     "GWh": "gigawatt hour",
29177     "gigaWh": "gigawatt hour",
29178     "gigaWatt-hour": "gigawatt hour",
29179     "gigawatt-hour": "gigawatt hour",
29180     "gigaWatt hour": "gigawatt hour",
29181     "gigawatt hour": "gigawatt hour",
29182     "gigawatthour": "gigawatt hour"
29183 };
29184 
29185 /**
29186  * Convert a energy to another measure.
29187  * @static
29188  * @param to {string} unit to convert to
29189  * @param from {string} unit to convert from
29190  * @param energy {number} amount to be convert
29191  * @returns {number|undefined} the converted amount
29192  */
29193 EnergyUnit.convert = function(to, from, energy) {
29194     from = EnergyUnit.aliases[from] || from;
29195     to = EnergyUnit.aliases[to] || to;
29196     var fromRow = EnergyUnit.ratios[from];
29197     var toRow = EnergyUnit.ratios[to];
29198     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29199         return undefined;
29200     }
29201     return energy * fromRow[toRow[0]];
29202 };
29203 
29204 /**
29205  * @private
29206  * @static
29207  */
29208 EnergyUnit.getMeasures = function () {
29209 	var ret = [];
29210 	for (var m in EnergyUnit.ratios) {
29211 		ret.push(m);
29212 	}
29213 	return ret;
29214 };
29215 
29216 EnergyUnit.metricJouleSystem = {
29217     "millijoule": 1,
29218     "joule": 2,
29219     "kilojoule": 4,
29220     "megajoule": 7,
29221     "gigajoule": 9
29222 };
29223 EnergyUnit.metricWattHourSystem = {
29224     "watt hour": 5,
29225     "kilowatt hour": 8,
29226     "megawatt hour": 10,
29227     "gigawatt hour": 11
29228 };
29229 
29230 EnergyUnit.imperialSystem = {
29231 	"BTU": 3
29232 };
29233 EnergyUnit.uscustomarySystem = {
29234 	"calorie": 6
29235 };
29236 
29237 EnergyUnit.metricToImperial = {
29238     "millijoule": "BTU",
29239     "joule": "BTU",
29240     "kilojoule": "BTU",
29241     "megajoule": "BTU",
29242     "gigajoule": "BTU"
29243 };
29244 EnergyUnit.imperialToMetric = {
29245 	"BTU": "joule"
29246 };
29247 
29248 /**
29249  * Localize the measurement to the commonly used measurement in that locale. For example
29250  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29251  * the formatted number should be automatically converted to the most appropriate 
29252  * measure in the other system, in this case, mph. The formatted result should
29253  * appear as "37.3 mph". 
29254  * 
29255  * @abstract
29256  * @param {string} locale current locale string
29257  * @returns {Measurement} a new instance that is converted to locale
29258  */
29259 EnergyUnit.prototype.localize = function(locale) {
29260 	var to;
29261 	if (locale === "en-GB") {
29262 		to = EnergyUnit.metricToImperial[this.unit] || this.unit;
29263 	} else {
29264 		to = EnergyUnit.imperialToMetric[this.unit] || this.unit;
29265 	}
29266 
29267 	return new EnergyUnit({
29268 	    unit: to,
29269 	    amount: this
29270 	});
29271 };
29272 
29273 /**
29274  * Scale the measurement unit to an acceptable level. The scaling
29275  * happens so that the integer part of the amount is as small as
29276  * possible without being below zero. This will result in the 
29277  * largest units that can represent this measurement without
29278  * fractions. Measurements can only be scaled to other measurements 
29279  * of the same type.
29280  * 
29281  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29282  * or undefined if the system can be inferred from the current measure
29283  * @return {Measurement} a new instance that is scaled to the 
29284  * right level
29285  */
29286 EnergyUnit.prototype.scale = function(measurementsystem) {
29287     var fromRow = EnergyUnit.ratios[this.unit];
29288     var mSystem;
29289 
29290     if ((measurementsystem === "metric" && typeof(EnergyUnit.metricJouleSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
29291         && typeof(EnergyUnit.metricJouleSystem[this.unit]) !== 'undefined')) {
29292         mSystem = EnergyUnit.metricJouleSystem;
29293     }
29294     else if ((measurementsystem === "metric" && typeof(EnergyUnit.metricWattHourSystem[this.unit]) !== 'undefined')|| (typeof(measurementsystem) === 'undefined'
29295         && typeof(EnergyUnit.metricWattHourSystem[this.unit]) !== 'undefined')) {
29296         mSystem = EnergyUnit.metricWattHourSystem;
29297     }
29298 
29299     else  if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
29300         && typeof(EnergyUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
29301         mSystem = EnergyUnit.uscustomarySystem;
29302     }
29303     else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
29304         && typeof(EnergyUnit.imperialSystem[this.unit]) !== 'undefined')) {
29305         mSystem = EnergyUnit.imperialSystem;
29306     }
29307 
29308     var energy = this.amount;
29309     var munit = this.unit;
29310 
29311     energy = 18446744073709551999;
29312     
29313     for (var m in mSystem) {
29314         var tmp = this.amount * fromRow[mSystem[m]];
29315         if (tmp >= 1 && tmp < energy) {
29316 	        energy = tmp;
29317 	        munit = m;
29318         }
29319     }
29320 
29321     return new EnergyUnit({
29322         unit: munit,
29323         amount: energy
29324     });
29325 };
29326 //register with the factory method
29327 Measurement._constructors["energy"] = EnergyUnit;
29328 
29329 
29330 /*< FuelConsumptionUnit.js */
29331 /*
29332  * fuelconsumption.js - Unit conversions for FuelConsumption
29333  *
29334  * Copyright © 2014-2015, JEDLSoft
29335  *
29336  * Licensed under the Apache License, Version 2.0 (the "License");
29337  * you may not use this file except in compliance with the License.
29338  * You may obtain a copy of the License at
29339  *
29340  *     http://www.apache.org/licenses/LICENSE-2.0
29341  *
29342  * Unless required by applicable law or agreed to in writing, software
29343  * distributed under the License is distributed on an "AS IS" BASIS,
29344  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29345  *
29346  * See the License for the specific language governing permissions and
29347  * limitations under the License.
29348  */
29349 
29350 /*
29351 !depends 
29352 Measurement.js 
29353 */
29354 
29355 
29356 /**
29357  * @class
29358  * Create a new fuelconsumption measurement instance.
29359  * 
29360  * @constructor
29361  * @extends Measurement
29362  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
29363  * the construction of this instance
29364  */
29365 var FuelConsumptionUnit = function(options) {
29366     this.unit = "km/liter";
29367     this.amount = 0;
29368     this.aliases = FuelConsumptionUnit.aliases; // share this table in all instances
29369 
29370     if (options) {
29371         if (typeof(options.unit) !== 'undefined') {
29372             this.originalUnit = options.unit;
29373             this.unit = this.aliases[options.unit] || options.unit;
29374         }
29375 
29376         if (typeof(options.amount) === 'object') {
29377             if (options.amount.getMeasure() === "fuelconsumption") {
29378                 this.amount = FuelConsumptionUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29379             } else {
29380                 throw "Cannot convert unit " + options.amount.unit + " to fuelconsumption";
29381             }
29382         } else if (typeof(options.amount) !== 'undefined') {
29383             this.amount = parseFloat(options.amount);
29384         }
29385     }
29386 };
29387 
29388 FuelConsumptionUnit.prototype = new Measurement();
29389 FuelConsumptionUnit.prototype.parent = Measurement;
29390 FuelConsumptionUnit.prototype.constructor = FuelConsumptionUnit;
29391 
29392 FuelConsumptionUnit.ratios = [
29393     "km/liter",
29394     "liter/100km",
29395     "mpg",
29396     "mpg(imp)"
29397 ];
29398 
29399 /**
29400  * Return the type of this measurement. Examples are "mass",
29401  * "length", "speed", etc. Measurements can only be converted
29402  * to measurements of the same type.<p>
29403  * 
29404  * The type of the units is determined automatically from the 
29405  * units. For example, the unit "grams" is type "mass". Use the 
29406  * static call {@link Measurement.getAvailableUnits}
29407  * to find out what units this version of ilib supports.
29408  *  
29409  * @return {string} the name of the type of this measurement
29410  */
29411 FuelConsumptionUnit.prototype.getMeasure = function() {
29412     return "fuelconsumption";
29413 };
29414 
29415 /**
29416  * Return a new measurement instance that is converted to a new
29417  * measurement unit. Measurements can only be converted
29418  * to measurements of the same type.<p>
29419  *  
29420  * @param {string} to The name of the units to convert to
29421  * @return {Measurement|undefined} the converted measurement
29422  * or undefined if the requested units are for a different
29423  * measurement type 
29424  */
29425 FuelConsumptionUnit.prototype.convert = function(to) {
29426     if (!to || typeof(FuelConsumptionUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29427         return undefined;
29428     }
29429     return new FuelConsumptionUnit({
29430         unit: to,
29431         amount: this
29432     });
29433 };
29434 /*["km/liter", "liter/100km", "mpg", "mpg(imp)"*/
29435 FuelConsumptionUnit.aliases = {
29436     "Km/liter": "km/liter",
29437     "KM/Liter": "km/liter",
29438     "KM/L": "km/liter",
29439     "Kilometers Per Liter": "km/liter",
29440     "kilometers per liter": "km/liter",
29441     "km/l": "km/liter",
29442     "Kilometers/Liter": "km/liter",
29443     "Kilometer/Liter": "km/liter",
29444     "kilometers/liter": "km/liter",
29445     "kilometer/liter": "km/liter",
29446     "km/liter": "km/liter",
29447     "Liter/100km": "liter/100km",
29448     "Liters/100km": "liter/100km",
29449     "Liter/100kms": "liter/100km",
29450     "Liters/100kms": "liter/100km",
29451     "liter/100km": "liter/100km",
29452     "liters/100kms": "liter/100km",
29453     "liters/100km": "liter/100km",
29454     "liter/100kms": "liter/100km",
29455     "Liter/100KM": "liter/100km",
29456     "Liters/100KM": "liter/100km",
29457     "L/100km": "liter/100km",
29458     "L/100KM": "liter/100km",
29459     "l/100KM": "liter/100km",
29460     "l/100km": "liter/100km",
29461     "l/100kms": "liter/100km",
29462     "MPG(US)": "mpg",
29463     "USMPG ": "mpg",
29464     "mpg": "mpg",
29465     "mpgUS": "mpg",
29466     "mpg(US)": "mpg",
29467     "mpg(us)": "mpg",
29468     "mpg-us": "mpg",
29469     "mpg Imp": "mpg(imp)",
29470     "MPG(imp)": "mpg(imp)",
29471     "mpg(imp)": "mpg(imp)",
29472     "mpg-imp": "mpg(imp)"
29473 };
29474 
29475 FuelConsumptionUnit.metricToUScustomary = {
29476     "km/liter": "mpg",
29477     "liter/100km": "mpg"
29478 };
29479 FuelConsumptionUnit.metricToImperial = {
29480     "km/liter": "mpg(imp)",
29481     "liter/100km": "mpg(imp)"
29482 };
29483 
29484 FuelConsumptionUnit.imperialToMetric = {
29485 	"mpg(imp)": "km/liter"
29486 };
29487 FuelConsumptionUnit.imperialToUScustomary = {
29488 	"mpg(imp)": "mpg"
29489 };
29490 
29491 FuelConsumptionUnit.uScustomaryToImperial = {
29492 	"mpg": "mpg(imp)"
29493 };
29494 FuelConsumptionUnit.uScustomarylToMetric = {
29495 	"mpg": "km/liter"
29496 };
29497 
29498 /**
29499  * Localize the measurement to the commonly used measurement in that locale. For example
29500  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29501  * the formatted number should be automatically converted to the most appropriate 
29502  * measure in the other system, in this case, mph. The formatted result should
29503  * appear as "37.3 mph". 
29504  * 
29505  * @abstract
29506  * @param {string} locale current locale string
29507  * @returns {Measurement} a new instance that is converted to locale
29508  */
29509 FuelConsumptionUnit.prototype.localize = function(locale) {
29510 	var to;
29511 	if (locale === "en-US") {
29512 		to = FuelConsumptionUnit.metricToUScustomary[this.unit] ||
29513 		    FuelConsumptionUnit.imperialToUScustomary[this.unit] ||
29514 		    this.unit;
29515 	} else if (locale === "en-GB") {
29516 		to = FuelConsumptionUnit.metricToImperial[this.unit] ||
29517 		    FuelConsumptionUnit.uScustomaryToImperial[this.unit] ||
29518 		    this.unit;
29519 	} else {
29520 		to = FuelConsumptionUnit.uScustomarylToMetric[this.unit] ||
29521 		    FuelConsumptionUnit.imperialToUScustomary[this.unit] ||
29522 		    this.unit;
29523 	}
29524 	return new FuelConsumptionUnit({
29525 	    unit: to,
29526 	    amount: this
29527 	});
29528 };
29529 
29530 /**
29531  * Convert a FuelConsumption to another measure.
29532  * 
29533  * @static
29534  * @param to {string} unit to convert to
29535  * @param from {string} unit to convert from
29536  * @param fuelConsumption {number} amount to be convert
29537  * @returns {number|undefined} the converted amount
29538  */
29539 FuelConsumptionUnit.convert = function(to, from, fuelConsumption) {
29540     from = FuelConsumptionUnit.aliases[from] || from;
29541     to = FuelConsumptionUnit.aliases[to] || to;
29542     var returnValue = 0;
29543 
29544     switch (from) {
29545         case "km/liter":
29546             switch (to) {
29547                 case "km/liter":
29548                     returnValue = fuelConsumption * 1;
29549                     break;
29550                 case "liter/100km":
29551                     returnValue = 100 / fuelConsumption;
29552                     break;
29553                 case "mpg":
29554                     returnValue = fuelConsumption * 2.35215;
29555                     break;
29556                 case "mpg(imp)":
29557                     returnValue = fuelConsumption * 2.82481;
29558                     break;
29559             }
29560             break;
29561         case "liter/100km":
29562             switch (to) {
29563                 case "km/liter":
29564                     returnValue = 100 / fuelConsumption;
29565                     break;
29566                 case "liter/100km":
29567                     returnValue = fuelConsumption * 1;
29568                     break;
29569                 case "mpg":
29570                     returnValue = 235.215 / fuelConsumption;
29571                     break;
29572                 case "mpg(imp)":
29573                     returnValue = 282.481 / fuelConsumption;
29574                     break;
29575             }
29576             break;
29577         case "mpg":
29578             switch (to) {
29579                 case "km/liter":
29580                     returnValue = fuelConsumption * 0.425144;
29581                     break;
29582                 case "liter/100km":
29583                     returnValue = 235.215 / fuelConsumption;
29584                     break;
29585                 case "mpg":
29586                     returnValue = 1 * fuelConsumption;
29587                     break;
29588                 case "mpg(imp)":
29589                     returnValue = 1.20095 * fuelConsumption;
29590                     break;
29591             }
29592             break;
29593         case "mpg(imp)":
29594             switch (to) {
29595                 case "km/liter":
29596                     returnValue = fuelConsumption * 0.354006;
29597                     break;
29598                 case "liter/100km":
29599                     returnValue = 282.481 / fuelConsumption;
29600                     break;
29601                 case "mpg":
29602                     returnValue = 0.832674 * fuelConsumption;
29603                     break;
29604                 case "mpg(imp)":
29605                     returnValue = 1 * fuelConsumption;
29606                     break;
29607             }
29608             break;
29609     }
29610     return returnValue;
29611 };
29612 
29613 /**
29614  * Scale the measurement unit to an acceptable level. The scaling
29615  * happens so that the integer part of the amount is as small as
29616  * possible without being below zero. This will result in the 
29617  * largest units that can represent this measurement without
29618  * fractions. Measurements can only be scaled to other measurements 
29619  * of the same type.
29620  * 
29621  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29622  * or undefined if the system can be inferred from the current measure
29623  * @return {Measurement} a new instance that is scaled to the 
29624  * right level
29625  */
29626 FuelConsumptionUnit.prototype.scale = function(measurementsystem) {
29627     return new FuelConsumptionUnit({
29628         unit: this.unit,
29629         amount: this.amount
29630     }); 
29631 };
29632 
29633 /**
29634  * @private
29635  * @static
29636  */
29637 FuelConsumptionUnit.getMeasures = function() {
29638     var ret = [];
29639     ret.push("km/liter");
29640     ret.push("liter/100km");
29641     ret.push("mpg");
29642     ret.push("mpg(imp)");
29643     
29644     return ret;
29645 };
29646 
29647 //register with the factory method
29648 Measurement._constructors["fuelconsumption"] = FuelConsumptionUnit;
29649 
29650 
29651 /*< LengthUnit.js */
29652 /*
29653  * LengthUnit.js - Unit conversions for Lengths/lengths
29654  * 
29655  * Copyright © 2014-2015, JEDLSoft
29656  *
29657  * Licensed under the Apache License, Version 2.0 (the "License");
29658  * you may not use this file except in compliance with the License.
29659  * You may obtain a copy of the License at
29660  *
29661  *     http://www.apache.org/licenses/LICENSE-2.0
29662  *
29663  * Unless required by applicable law or agreed to in writing, software
29664  * distributed under the License is distributed on an "AS IS" BASIS,
29665  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29666  *
29667  * See the License for the specific language governing permissions and
29668  * limitations under the License.
29669  */
29670 
29671 /*
29672 !depends 
29673 Measurement.js
29674 */
29675 
29676 
29677 /**
29678  * @class
29679  * Create a new length measurement instance.
29680  *  
29681  * @constructor
29682  * @extends Measurement
29683  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
29684  * the construction of this instance
29685  */
29686 var LengthUnit = function (options) {
29687 	this.unit = "meter";
29688 	this.amount = 0;
29689 	this.aliases = LengthUnit.aliases; // share this table in all instances
29690 	
29691 	if (options) {
29692 		if (typeof(options.unit) !== 'undefined') {
29693 			this.originalUnit = options.unit;
29694 			this.unit = this.aliases[options.unit] || options.unit;
29695 		}
29696 		
29697 		if (typeof(options.amount) === 'object') {
29698 			if (options.amount.getMeasure() === "length") {
29699 				this.amount = LengthUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
29700 			} else {
29701 				throw "Cannot convert unit " + options.amount.unit + " to a length";
29702 			}
29703 		} else if (typeof(options.amount) !== 'undefined') {
29704 			this.amount = parseFloat(options.amount);
29705 		}
29706 	}
29707 	
29708 	if (typeof(LengthUnit.ratios[this.unit]) === 'undefined') {
29709 		throw "Unknown unit: " + options.unit;
29710 	}
29711 };
29712 
29713 LengthUnit.prototype = new Measurement();
29714 LengthUnit.prototype.parent = Measurement;
29715 LengthUnit.prototype.constructor = LengthUnit;
29716 
29717 LengthUnit.ratios = {
29718 	/*              index, µm           mm           cm           inch         dm           foot          yard          m             dam            hm              km              mile            nm            Mm             Gm             */ 
29719 	"micrometer":   [ 1,   1,           1e-3,        1e-4,        3.93701e-5,  1e-5,        3.28084e-6,   1.09361e-6,   1e-6,         1e-7,          1e-8,           1e-9,           6.21373e-10,  5.39957e-10,  1e-12,          1e-15           ],
29720 	"millimeter":   [ 2,   1000,        1,           0.1,         0.0393701,   0.01,        0.00328084,   1.09361e-3,   0.001,        1e-4,          1e-5,           1e-6,           6.21373e-7,   5.39957e-7,   1e-9,           1e-12           ],
29721 	"centimeter":   [ 3,   1e4,         10,          1,           0.393701,    0.1,         0.0328084,    0.0109361,    0.01,         0.001,         1e-4,           1e-5,           6.21373e-6,   5.39957e-6,   1e-8,           1e-9            ],
29722     "inch":         [ 4,   25399.986,   25.399986,   2.5399986,   1,           0.25399986,  0.083333333,  0.027777778,  0.025399986,  2.5399986e-3,  2.5399986e-4,   2.5399986e-5,   1.5783e-5,    1.3715e-5,    2.5399986e-8,   2.5399986e-11   ],
29723     "decimeter":    [ 5,   1e5,         100,         10,          3.93701,     1,           0.328084,     0.109361,     0.1,          0.01,          0.001,          1e-4,           6.21373e-5,   5.39957e-5,   1e-7,           1e-8            ],
29724     "foot":         [ 6,   304799.99,   304.79999,   30.479999,   12,          3.0479999,   1,            0.33333333,   0.30479999,   0.030479999,   3.0479999e-3,   3.0479999e-4,   1.89394e-4,   1.64579e-4,   3.0479999e-7,   3.0479999e-10   ],
29725     "yard":         [ 7,   914402.758,  914.402758,  91.4402758,  36,          9.14402758,  3,            1,            0.914402758,  0.0914402758,  9.14402758e-3,  9.14402758e-4,  5.68182e-4,   4.93737e-4,   9.14402758e-7,  9.14402758e-10  ],
29726 	"meter":        [ 8,   1e6,         1000,        100,         39.3701,     10,          3.28084,      1.09361,      1,            0.1,           0.01,           0.001,          6.213712e-4,  5.39957e-4,   1e-6,           1e-7            ],
29727 	"decameter":    [ 9,   1e7,         1e4,         1000,        393.701,     100,         32.8084,      10.9361,      10,           1,             0.1,            0.01,           6.21373e-3,   5.39957e-3,   1e-5,           1e-6            ],
29728 	"hectometer":   [ 10,  1e8,         1e5,         1e4,         3937.01,     1000,        328.084,      109.361,      100,          10,            1,              0.1,            0.0621373,    0.0539957,    1e-4,           1e-5            ],
29729 	"kilometer":    [ 11,  1e9,         1e6,         1e5,         39370.1,     1e4,         3280.84,      1093.61,      1000,         100,           10,             1,              0.621373,     0.539957,     0.001,          1e-4            ],
29730     "mile":         [ 12,  1.60934e9,   1.60934e6,   1.60934e5,   63360,       1.60934e4,   5280,         1760,         1609.34,      160.934,       16.0934,        1.60934,        1,            0.868976,     1.60934e-3,     1.60934e-6      ],
29731     "nauticalmile": [ 13,  1.852e9,     1.852e6,     1.852e5,     72913.4,     1.852e4,     6076.12,      2025.37,      1852,         185.2,         18.52,          1.852,          1.15078,      1,            1.852e-3,       1.852e-6        ],
29732 	"megameter":    [ 14,  1e12,        1e9,         1e6,         3.93701e7,   1e5,         3.28084e6,    1.09361e6,    1e4,          1000,          100,            10,             621.373,      539.957,      1,              0.001           ],        
29733     "gigameter":    [ 15,  1e15,        1e12,        1e9,         3.93701e10,  1e8,         3.28084e9,    1.09361e9,    1e7,          1e6,           1e5,            1e4,            621373.0,     539957.0,     1000,           1               ]	
29734 };
29735 
29736 LengthUnit.metricSystem = {
29737     "micrometer": 1,
29738     "millimeter": 2,
29739     "centimeter": 3,
29740     "decimeter": 5,
29741     "meter": 8,
29742     "decameter": 9,
29743     "hectometer": 10,
29744     "kilometer": 11,
29745     "megameter": 14,
29746     "gigameter": 15
29747 };
29748 LengthUnit.imperialSystem = {
29749     "inch": 4,
29750     "foot": 6,
29751     "yard": 7,
29752     "mile": 12,
29753     "nauticalmile": 13
29754 };
29755 LengthUnit.uscustomarySystem = {
29756     "inch": 4,
29757     "foot": 6,
29758     "yard": 7,
29759     "mile": 12,
29760     "nauticalmile": 13
29761 };
29762 
29763 LengthUnit.metricToUScustomary = {
29764     "micrometer": "inch",
29765     "millimeter": "inch",
29766     "centimeter": "inch",
29767     "decimeter": "inch",
29768     "meter": "yard",
29769     "decameter": "yard",
29770     "hectometer": "mile",
29771     "kilometer": "mile",
29772     "megameter": "nauticalmile",
29773     "gigameter": "nauticalmile"
29774 };
29775 LengthUnit.usCustomaryToMetric = {
29776     "inch": "centimeter",
29777     "foot": "centimeter",
29778     "yard": "meter",
29779     "mile": "kilometer",
29780     "nauticalmile": "kilometer"
29781 };
29782 
29783 /**
29784  * Return the type of this measurement. Examples are "mass",
29785  * "length", "speed", etc. Measurements can only be converted
29786  * to measurements of the same type.<p>
29787  * 
29788  * The type of the units is determined automatically from the 
29789  * units. For example, the unit "grams" is type "mass". Use the 
29790  * static call {@link Measurement.getAvailableUnits}
29791  * to find out what units this version of ilib supports.
29792  *  
29793  * @return {string} the name of the type of this measurement
29794  */
29795 LengthUnit.prototype.getMeasure = function() {
29796 	return "length";
29797 };
29798 
29799 /**
29800  * Localize the measurement to the commonly used measurement in that locale. For example
29801  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
29802  * the formatted number should be automatically converted to the most appropriate 
29803  * measure in the other system, in this case, mph. The formatted result should
29804  * appear as "37.3 mph". 
29805  * 
29806  * @abstract
29807  * @param {string} locale current locale string
29808  * @returns {Measurement} a new instance that is converted to locale
29809  */
29810 LengthUnit.prototype.localize = function(locale) {
29811     var to;
29812     if (locale === "en-US" || locale === "en-GB") {
29813         to = LengthUnit.metricToUScustomary[this.unit] || this.unit;
29814     } else {
29815         to = LengthUnit.usCustomaryToMetric[this.unit] || this.unit;
29816     }
29817     return new LengthUnit({
29818         unit: to,
29819         amount: this
29820     });
29821 };
29822 
29823 /**
29824  * Return a new measurement instance that is converted to a new
29825  * measurement unit. Measurements can only be converted
29826  * to measurements of the same type.<p>
29827  *  
29828  * @param {string} to The name of the units to convert to
29829  * @return {Measurement|undefined} the converted measurement
29830  * or undefined if the requested units are for a different
29831  * measurement type 
29832  */
29833 LengthUnit.prototype.convert = function(to) {
29834 	if (!to || typeof(LengthUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
29835 		return undefined;
29836 	}
29837 	return new LengthUnit({
29838 		unit: to,
29839 		amount: this
29840 	});
29841 };
29842 
29843 /**
29844  * Scale the measurement unit to an acceptable level. The scaling
29845  * happens so that the integer part of the amount is as small as
29846  * possible without being below zero. This will result in the 
29847  * largest units that can represent this measurement without
29848  * fractions. Measurements can only be scaled to other measurements 
29849  * of the same type.
29850  * 
29851  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
29852  * or undefined if the system can be inferred from the current measure
29853  * @return {Measurement} a new instance that is scaled to the 
29854  * right level
29855  */
29856 LengthUnit.prototype.scale = function(measurementsystem) {
29857     var mSystem;    
29858     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
29859             && typeof(LengthUnit.metricSystem[this.unit]) !== 'undefined')) {
29860         mSystem = LengthUnit.metricSystem;
29861     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
29862             && typeof(LengthUnit.imperialSystem[this.unit]) !== 'undefined')) {
29863         mSystem = LengthUnit.imperialSystem;
29864     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
29865             && typeof(LengthUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
29866         mSystem = LengthUnit.uscustomarySystem;
29867     } else {
29868         return new LengthUnit({
29869 			unit: this.unit,
29870 			amount: this.amount
29871 		});
29872     }    
29873     
29874     var length = this.amount;
29875     var munit = this.unit;
29876     var fromRow = LengthUnit.ratios[this.unit];
29877     
29878     length = 18446744073709551999;
29879     for (var m in mSystem) {
29880     	var tmp = this.amount * fromRow[mSystem[m]];
29881         if (tmp >= 1 && tmp < length) {
29882 	        length = tmp;
29883 	        munit = m;
29884         }
29885     }
29886     
29887     return new LengthUnit({
29888 		unit: munit,
29889 		amount: length
29890     });
29891 };
29892 
29893 LengthUnit.aliases = {
29894 	"miles": "mile",
29895 	"mile":"mile",
29896 	"nauticalmiles": "nauticalmile",
29897 	"nautical mile": "nauticalmile",
29898 	"nautical miles": "nauticalmile",
29899 	"nauticalmile":"nauticalmile",
29900 	"yards": "yard",
29901 	"yard": "yard",
29902 	"feet": "foot",
29903 	"foot": "foot",
29904 	"inches": "inch",
29905 	"inch": "inch",
29906 	"meters": "meter",
29907 	"metre": "meter",
29908 	"metres": "meter",
29909 	"m": "meter",
29910 	"meter": "meter",        
29911 	"micrometers": "micrometer",
29912 	"micrometres": "micrometer",
29913 	"micrometre": "micrometer",
29914 	"µm": "micrometer",
29915 	"micrometer": "micrometer",
29916 	"millimeters": "millimeter",
29917 	"millimetres": "millimeter",
29918 	"millimetre": "millimeter",
29919 	"mm": "millimeter",
29920 	"millimeter": "millimeter",
29921 	"centimeters": "centimeter",
29922 	"centimetres": "centimeter",
29923 	"centimetre": "centimeter",
29924 	"cm": "centimeter",
29925 	"centimeter": "centimeter",
29926 	"decimeters": "decimeter",
29927 	"decimetres": "decimeter",
29928 	"decimetre": "decimeter",
29929 	"dm": "decimeter",
29930 	"decimeter": "decimeter",
29931 	"decameters": "decameter",
29932 	"decametres": "decameter",
29933 	"decametre": "decameter",
29934 	"dam": "decameter",
29935 	"decameter": "decameter",
29936 	"hectometers": "hectometer",
29937 	"hectometres": "hectometer",
29938 	"hectometre": "hectometer",
29939 	"hm": "hectometer",
29940 	"hectometer": "hectometer",
29941 	"kilometers": "kilometer",
29942 	"kilometres": "kilometer",
29943 	"kilometre": "kilometer",
29944 	"km": "kilometer",
29945 	"kilometer": "kilometer",
29946 	"megameters": "megameter",
29947 	"megametres": "megameter",
29948 	"megametre": "megameter",
29949 	"Mm": "megameter",
29950 	"megameter": "megameter",
29951 	"gigameters": "gigameter",
29952 	"gigametres": "gigameter",
29953 	"gigametre": "gigameter",
29954 	"Gm": "gigameter",
29955 	"gigameter": "gigameter"
29956 };
29957 
29958 /**
29959  * Convert a length to another measure.
29960  * @static
29961  * @param to {string} unit to convert to
29962  * @param from {string} unit to convert from
29963  * @param length {number} amount to be convert
29964  * @returns {number|undefined} the converted amount
29965  */
29966 LengthUnit.convert = function(to, from, length) {
29967     from = LengthUnit.aliases[from] || from;
29968     to = LengthUnit.aliases[to] || to;
29969 	var fromRow = LengthUnit.ratios[from];
29970 	var toRow = LengthUnit.ratios[to];
29971 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
29972 		return undefined;
29973 	}
29974 	return length * fromRow[toRow[0]];
29975 };
29976 
29977 /**
29978  * @private
29979  * @static
29980  */
29981 LengthUnit.getMeasures = function () {
29982 	var ret = [];
29983 	for (var m in LengthUnit.ratios) {
29984 		ret.push(m);
29985 	}
29986 	return ret;
29987 };
29988 
29989 //register with the factory method
29990 Measurement._constructors["length"] = LengthUnit;
29991 
29992 
29993 /*< MassUnit.js */
29994 /*
29995  * MassUnit.js - Unit conversions for Mass/mass
29996  * 
29997  * Copyright © 2014-2015, JEDLSoft
29998  *
29999  * Licensed under the Apache License, Version 2.0 (the "License");
30000  * you may not use this file except in compliance with the License.
30001  * You may obtain a copy of the License at
30002  *
30003  *     http://www.apache.org/licenses/LICENSE-2.0
30004  *
30005  * Unless required by applicable law or agreed to in writing, software
30006  * distributed under the License is distributed on an "AS IS" BASIS,
30007  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30008  *
30009  * See the License for the specific language governing permissions and
30010  * limitations under the License.
30011  */
30012 
30013 /*
30014 !depends 
30015 Measurement.js
30016 */
30017 
30018 
30019 /**
30020  * @class
30021  * Create a new mass measurement instance.
30022  *
30023  * @constructor
30024  * @extends Measurement
30025  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30026  * the construction of this instance
30027  */
30028 var MassUnit = function (options) {
30029 	this.unit = "gram";
30030 	this.amount = 0;
30031 	this.aliases = MassUnit.aliases; // share this table in all instances
30032 	
30033 	if (options) {
30034 		if (typeof(options.unit) !== 'undefined') {
30035 			this.originalUnit = options.unit;
30036 			this.unit = this.aliases[options.unit] || options.unit;
30037 		}
30038 		
30039 		if (typeof(options.amount) === 'object') {
30040 			if (options.amount.getMeasure() === "mass") {
30041 				this.amount = MassUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30042 			} else {
30043 				throw "Cannot convert units " + options.amount.unit + " to a mass";
30044 			}
30045 		} else if (typeof(options.amount) !== 'undefined') {
30046 			this.amount = parseFloat(options.amount);
30047 		}
30048 	}
30049 	
30050 	if (typeof(MassUnit.ratios[this.unit]) === 'undefined') {
30051 		throw "Unknown unit: " + options.unit;
30052 	}
30053 };
30054 
30055 MassUnit.prototype = new Measurement();
30056 MassUnit.prototype.parent = Measurement;
30057 MassUnit.prototype.constructor = MassUnit;
30058 
30059 MassUnit.ratios = {
30060 	/*             index  µg          mg         g          oz          lp           kg          st            sh ton       mt ton        ln ton      */           
30061 	"microgram":   [ 1,   1,          0.001,     1e-6,      3.5274e-8,  2.2046e-9,   1e-9,       1.5747e-10,   1.1023e-12,  1e-12,        9.8421e-13   ],  
30062 	"milligram":   [ 2,   1000,       1,         0.001,     3.5274e-5,  2.2046e-6,   1e-6,       1.5747e-7,    1.1023e-9,   1e-9,         9.8421e-10   ],  
30063 	"gram":        [ 3,   1e+6,       1000,      1,         0.035274,   0.00220462,  0.001,      0.000157473,  1.1023e-6,   1e-6,         9.8421e-7    ],
30064 	"ounce":       [ 4,   2.835e+7,   28349.5,   28.3495,   1,          0.0625,      0.0283495,  0.00446429,   3.125e-5,    2.835e-5,     2.7902e-5    ],
30065 	"pound":       [ 5,   4.536e+8,   453592,    453.592,   16,         1,           0.453592,   0.0714286,    0.0005,      0.000453592,  0.000446429  ],
30066     "kilogram":    [ 6,   1e+9,       1e+6,      1000,      35.274,     2.20462,     1,          0.157473,     0.00110231,  0.001,        0.000984207  ],
30067     "stone":       [ 7,   6.35e+9,    6.35e+6,   6350.29,   224,        14,          6.35029,    1,            0.007,       0.00635029,   0.00625      ],
30068     "short ton":   [ 8,   9.072e+11,  9.072e+8,  907185,    32000,      2000,        907.185,    142.857,      1,           0.907185,     0.892857     ],
30069     "metric ton":  [ 9,   1e+12,      1e+9,      1e+6,      35274,      2204.62,     1000,       157.473,      1.10231,     1,            0.984207     ],
30070     "long ton":    [ 10,  1.016e+12,  1.016e+9,  1.016e+6,  35840,      2240,        1016.05,    160,          1.12,        1.01605,      1            ]
30071 };
30072 
30073 MassUnit.metricSystem = {
30074     "microgram": 1,
30075     "milligram": 2,
30076     "gram": 3,
30077     "kilogram": 6,
30078     "metric ton": 9
30079 };
30080 MassUnit.imperialSystem = {
30081     "ounce": 4,
30082     "pound": 5,
30083     "stone": 7,
30084     "long ton": 10
30085 };
30086 MassUnit.uscustomarySystem = {
30087     "ounce": 4,
30088     "pound": 5,
30089     "short ton": 8
30090 };
30091 
30092 MassUnit.metricToUScustomary = {
30093     "microgram": "ounce",
30094     "milligram": "ounce",
30095     "gram": "ounce",
30096     "kilogram": "pound",
30097     "metric ton": "long ton"
30098 };
30099 MassUnit.metricToImperial = {
30100     "microgram": "ounce",
30101     "milligram": "ounce",
30102     "gram": "ounce",
30103     "kilogram": "pound",
30104     "metric ton": "short ton"
30105 };
30106 
30107 MassUnit.imperialToMetric = {
30108     "ounce": "gram",
30109     "pound": "kilogram",
30110     "stone": "kilogram",
30111     "short ton": "metric ton"
30112 };
30113 MassUnit.imperialToUScustomary = {
30114     "ounce": "ounce",
30115     "pound": "pound",
30116     "stone": "stone",
30117     "short ton": "long ton"
30118 };
30119 
30120 MassUnit.uScustomaryToImperial = {
30121     "ounce": "ounce",
30122     "pound": "pound",
30123     "stone": "stone",
30124     "long ton": "short ton"
30125 };
30126 MassUnit.uScustomarylToMetric = {
30127     "ounce": "gram",
30128     "pound": "kilogram",
30129     "stone": "kilogram",
30130     "long ton": "metric ton"
30131 };
30132 
30133 /**
30134  * Localize the measurement to the commonly used measurement in that locale. For example
30135  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30136  * the formatted number should be automatically converted to the most appropriate 
30137  * measure in the other system, in this case, mph. The formatted result should
30138  * appear as "37.3 mph". 
30139  * 
30140  * @abstract
30141  * @param {string} locale current locale string
30142  * @returns {Measurement} a new instance that is converted to locale
30143  */
30144 MassUnit.prototype.localize = function(locale) {
30145 	var to;
30146 	if (locale === "en-US") {
30147 		to = MassUnit.metricToUScustomary[this.unit] ||
30148 		    MassUnit.imperialToUScustomary[this.unit] || this.unit;
30149 	} else if (locale === "en-GB") {
30150 		to = MassUnit.metricToImperial[this.unit] ||
30151 		    MassUnit.uScustomaryToImperial[this.unit] || this.unit;
30152 	} else {
30153 		to = MassUnit.uScustomarylToMetric[this.unit] ||
30154 		    MassUnit.imperialToUScustomary[this.unit] || this.unit;
30155 	}
30156 	return new MassUnit({
30157 	    unit: to,
30158 	    amount: this
30159 	});
30160 };
30161 
30162 /**
30163  * Return the type of this measurement. Examples are "mass",
30164  * "length", "speed", etc. Measurements can only be converted
30165  * to measurements of the same type.<p>
30166  * 
30167  * The type of the units is determined automatically from the 
30168  * units. For example, the unit "grams" is type "mass". Use the 
30169  * static call {@link Measurement.getAvailableUnits}
30170  * to find out what units this version of ilib supports.
30171  *  
30172  * @return {string} the name of the type of this measurement
30173  */
30174 MassUnit.prototype.getMeasure = function() {
30175 	return "mass";
30176 };
30177 
30178 /**
30179  * Return a new measurement instance that is converted to a new
30180  * measurement unit. Measurements can only be converted
30181  * to measurements of the same type.<p>
30182  *  
30183  * @param {string} to The name of the units to convert to
30184  * @return {Measurement|undefined} the converted measurement
30185  * or undefined if the requested units are for a different
30186  * measurement type 
30187  */
30188 MassUnit.prototype.convert = function(to) {
30189 	if (!to || typeof(MassUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30190 		return undefined;
30191 	}
30192 	return new MassUnit({
30193 		unit: to,
30194 		amount: this
30195 	});
30196 };
30197 
30198 MassUnit.aliases = {
30199     "µg":"microgram",
30200     "microgram":"microgram",
30201     "mcg":"microgram",  
30202     "milligram":"milligram",
30203     "mg":"milligram",
30204     "milligrams":"milligram",
30205     "Milligram":"milligram",
30206     "Milligrams":"milligram",
30207     "MilliGram":"milligram",
30208     "MilliGrams":"milligram",
30209     "g":"gram",
30210     "gram":"gram",
30211     "grams":"gram",
30212     "Gram":"gram",
30213     "Grams":"gram",
30214     "ounce":"ounce",
30215     "oz":"ounce",
30216     "Ounce":"ounce",
30217     "℥":"ounce",
30218     "pound":"pound",
30219     "poundm":"pound",
30220     "℔":"pound",
30221     "lb":"pound",
30222     "pounds":"pound",
30223     "Pound":"pound",
30224     "Pounds":"pound",
30225     "kilogram":"kilogram",
30226     "kg":"kilogram",
30227     "kilograms":"kilogram",
30228     "kilo grams":"kilogram",
30229     "kilo gram":"kilogram",
30230     "Kilogram":"kilogram",    
30231     "Kilograms":"kilogram",
30232     "KiloGram":"kilogram",
30233     "KiloGrams":"kilogram",
30234     "Kilo gram":"kilogram",
30235     "Kilo grams":"kilogram",
30236     "Kilo Gram":"kilogram",
30237     "Kilo Grams":"kilogram",
30238     "stone":"stone",
30239     "st":"stone",
30240     "stones":"stone",
30241     "Stone":"stone",
30242     "short ton":"short ton",
30243     "Short ton":"short ton",
30244     "Short Ton":"short ton",
30245     "metric ton":"metric ton",
30246     "metricton":"metric ton",
30247     "t":"metric ton",
30248     "tonne":"metric ton",
30249     "Tonne":"metric ton",
30250     "Metric Ton":"metric ton",
30251     "MetricTon":"metric ton",    
30252     "long ton":"long ton",
30253     "longton":"long ton",
30254     "Longton":"long ton",
30255     "Long ton":"long ton",
30256     "Long Ton":"long ton",
30257     "ton":"long ton",
30258     "Ton":"long ton"
30259 };
30260 
30261 /**
30262  * Convert a mass to another measure.
30263  * @static
30264  * @param to {string} unit to convert to
30265  * @param from {string} unit to convert from
30266  * @param mass {number} amount to be convert
30267  * @returns {number|undefined} the converted amount
30268  */
30269 MassUnit.convert = function(to, from, mass) {
30270     from = MassUnit.aliases[from] || from;
30271     to = MassUnit.aliases[to] || to;
30272     var fromRow = MassUnit.ratios[from];
30273     var toRow = MassUnit.ratios[to];
30274     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30275         return undefined;
30276     }	
30277     return mass * fromRow[toRow[0]];    
30278 };
30279 
30280 /**
30281  * Scale the measurement unit to an acceptable level. The scaling
30282  * happens so that the integer part of the amount is as small as
30283  * possible without being below zero. This will result in the 
30284  * largest units that can represent this measurement without
30285  * fractions. Measurements can only be scaled to other measurements 
30286  * of the same type.
30287  * 
30288  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30289  * or undefined if the system can be inferred from the current measure
30290  * @return {Measurement} a new instance that is scaled to the 
30291  * right level
30292  */
30293 MassUnit.prototype.scale = function(measurementsystem) {
30294     var mSystem;    
30295     if (measurementsystem === "metric" || (typeof(measurementsystem) === 'undefined' 
30296             && typeof(MassUnit.metricSystem[this.unit]) !== 'undefined')) {
30297         mSystem = MassUnit.metricSystem;
30298     } else if (measurementsystem === "imperial" || (typeof(measurementsystem) === 'undefined' 
30299             && typeof(MassUnit.imperialSystem[this.unit]) !== 'undefined')) {
30300         mSystem = MassUnit.imperialSystem;
30301     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined' 
30302             && typeof(MassUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
30303         mSystem = MassUnit.uscustomarySystem;
30304     } else {
30305         return new MassUnit({
30306 			unit: this.unit,
30307 			amount: this.amount
30308 		});
30309     }    
30310     
30311     var mass = this.amount;
30312     var munit = this.amount;
30313     var fromRow = MassUnit.ratios[this.unit];
30314     
30315     mass = 18446744073709551999;
30316     
30317     for (var m in mSystem) {
30318         var tmp = this.amount * fromRow[mSystem[m]];
30319         if (tmp >= 1 && tmp < mass) {
30320         	mass = tmp;
30321             munit = m;
30322         }
30323     }
30324     
30325     return new MassUnit({
30326 		unit: munit,
30327 		amount: mass
30328     });
30329 };
30330 
30331 /**
30332  * @private
30333  * @static
30334  */
30335 MassUnit.getMeasures = function () {
30336 	var ret = [];
30337 	for (var m in MassUnit.ratios) {
30338 		ret.push(m);
30339 	}
30340 	return ret;
30341 };
30342 
30343 //register with the factory method
30344 Measurement._constructors["mass"] = MassUnit;
30345 
30346 
30347 /*< TemperatureUnit.js */
30348 /*
30349  * temperature.js - Unit conversions for Temperature/temperature
30350  * 
30351  * Copyright © 2014-2015, JEDLSoft
30352  *
30353  * Licensed under the Apache License, Version 2.0 (the "License");
30354  * you may not use this file except in compliance with the License.
30355  * You may obtain a copy of the License at
30356  *
30357  *     http://www.apache.org/licenses/LICENSE-2.0
30358  *
30359  * Unless required by applicable law or agreed to in writing, software
30360  * distributed under the License is distributed on an "AS IS" BASIS,
30361  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30362  *
30363  * See the License for the specific language governing permissions and
30364  * limitations under the License.
30365  */
30366 
30367 /*
30368 !depends 
30369 Measurement.js
30370 */
30371 
30372 
30373 /**
30374  * @class
30375  * Create a new Temperature measurement instance.
30376  *  
30377  * @constructor
30378  * @extends Measurement
30379  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30380  * the construction of this instance
30381  */
30382 var TemperatureUnit = function (options) {
30383 	this.unit = "celsius";
30384 	this.amount = 0;
30385 	this.aliases = TemperatureUnit.aliases; // share this table in all instances
30386 
30387 	if (options) {
30388 		if (typeof(options.unit) !== 'undefined') {
30389 			this.originalUnit = options.unit;
30390 			this.unit = this.aliases[options.unit] || options.unit;
30391 		}
30392 
30393 		if (typeof(options.amount) === 'object') {
30394 			if (options.amount.getMeasure() === "temperature") {
30395 				this.amount = TemperatureUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30396 			} else {
30397 				throw "Cannot convert unit " + options.amount.unit + " to a temperature";
30398 			}
30399 		} else if (typeof(options.amount) !== 'undefined') {
30400 			this.amount = parseFloat(options.amount);
30401 		}
30402 	}
30403 };
30404 
30405 TemperatureUnit.prototype = new Measurement();
30406 TemperatureUnit.prototype.parent = Measurement;
30407 TemperatureUnit.prototype.constructor = TemperatureUnit;
30408 
30409 /**
30410  * Return the type of this measurement. Examples are "mass",
30411  * "length", "speed", etc. Measurements can only be converted
30412  * to measurements of the same type.<p>
30413  * 
30414  * The type of the units is determined automatically from the 
30415  * units. For example, the unit "grams" is type "mass". Use the 
30416  * static call {@link Measurement.getAvailableUnits}
30417  * to find out what units this version of ilib supports.
30418  *  
30419  * @return {string} the name of the type of this measurement
30420  */
30421 TemperatureUnit.prototype.getMeasure = function() {
30422 	return "temperature";
30423 };
30424 
30425 TemperatureUnit.aliases = {
30426     "Celsius": "celsius",
30427     "celsius": "celsius",
30428     "C": "celsius",
30429     "centegrade": "celsius",
30430     "Centegrade": "celsius",
30431     "centigrade": "celsius",
30432     "Centigrade": "celsius",
30433     "fahrenheit": "fahrenheit",
30434     "Fahrenheit": "fahrenheit",
30435     "F": "fahrenheit",
30436     "kelvin": "kelvin",
30437     "K": "kelvin",
30438     "Kelvin": "kelvin",
30439     "°F": "fahrenheit",
30440     "℉": "fahrenheit",
30441     "℃": "celsius",
30442     "°C": "celsius"
30443 };
30444 
30445 /**
30446  * Return a new measurement instance that is converted to a new
30447  * measurement unit. Measurements can only be converted
30448  * to measurements of the same type.<p>
30449  *  
30450  * @param {string} to The name of the units to convert to
30451  * @return {Measurement|undefined} the converted measurement
30452  * or undefined if the requested units are for a different
30453  * measurement type 
30454  */
30455 TemperatureUnit.prototype.convert = function(to) {
30456 	if (!to || typeof(TemperatureUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30457 		return undefined;
30458 	}
30459 	return new TemperatureUnit({
30460 		unit: to,
30461 		amount: this
30462 	});
30463 };
30464 
30465 /**
30466  * Convert a temperature to another measure.
30467  * @static
30468  * @param to {string} unit to convert to
30469  * @param from {string} unit to convert from
30470  * @param temperature {number} amount to be convert
30471  * @returns {number|undefined} the converted amount
30472  */
30473 TemperatureUnit.convert = function(to, from, temperature) {
30474 	var result = 0;
30475 	from = TemperatureUnit.aliases[from] || from;
30476 	to = TemperatureUnit.aliases[to] || to;
30477 	if (from === to)
30478 		return temperature;
30479 
30480 	else if (from === "celsius") {
30481 		if (to === "fahrenheit") {
30482 			result = ((temperature * 9 / 5) + 32);
30483 		} else if (to === "kelvin") {
30484 			result = (temperature + 273.15);
30485 		}
30486 
30487 	} else if (from === "fahrenheit") {
30488 		if (to === "celsius") {
30489 			result = ((5 / 9 * (temperature - 32)));
30490 		} else if (to === "kelvin") {
30491 			result = ((temperature + 459.67) * 5 / 9);
30492 		}
30493 	} else if (from === "kelvin") {
30494 		if (to === "celsius") {
30495 			result = (temperature - 273.15);
30496 		} else if (to === "fahrenheit") {
30497 			result = ((temperature * 9 / 5) - 459.67);
30498 		}
30499 	}
30500 
30501 	return result;
30502 };
30503 
30504 /**
30505  * Scale the measurement unit to an acceptable level. The scaling
30506  * happens so that the integer part of the amount is as small as
30507  * possible without being below zero. This will result in the 
30508  * largest units that can represent this measurement without
30509  * fractions. Measurements can only be scaled to other measurements 
30510  * of the same type.
30511  * 
30512  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30513  * or undefined if the system can be inferred from the current measure
30514  * @return {Measurement} a new instance that is scaled to the 
30515  * right level
30516  */
30517 TemperatureUnit.prototype.scale = function(measurementsystem) {
30518     return new TemperatureUnit({
30519         unit: this.unit,
30520         amount: this.amount
30521     }); 
30522 };
30523 
30524 /**
30525  * @private
30526  * @static
30527  */
30528 TemperatureUnit.getMeasures = function () {
30529 	return ["celsius", "kelvin", "fahrenheit"];
30530 };
30531 TemperatureUnit.metricToUScustomary = {
30532 	"celsius": "fahrenheit"
30533 };
30534 TemperatureUnit.usCustomaryToMetric = {
30535 	"fahrenheit": "celsius"
30536 };
30537 
30538 /**
30539  * Localize the measurement to the commonly used measurement in that locale. For example
30540  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30541  * the formatted number should be automatically converted to the most appropriate 
30542  * measure in the other system, in this case, mph. The formatted result should
30543  * appear as "37.3 mph". 
30544  * 
30545  * @abstract
30546  * @param {string} locale current locale string
30547  * @returns {Measurement} a new instance that is converted to locale
30548  */
30549 TemperatureUnit.prototype.localize = function(locale) {
30550     var to;
30551     if (locale === "en-US" ) {
30552         to = TemperatureUnit.metricToUScustomary[this.unit] || this.unit;
30553     } else {
30554         to = TemperatureUnit.usCustomaryToMetric[this.unit] || this.unit;
30555     }
30556     return new TemperatureUnit({
30557         unit: to,
30558         amount: this
30559     });
30560 };
30561 //register with the factory method
30562 Measurement._constructors["temperature"] = TemperatureUnit;
30563 
30564 
30565 /*< TimeUnit.js */
30566 /*
30567  * Time.js - Unit conversions for Times/times
30568  * 
30569  * Copyright © 2014-2015, JEDLSoft
30570  *
30571  * Licensed under the Apache License, Version 2.0 (the "License");
30572  * you may not use this file except in compliance with the License.
30573  * You may obtain a copy of the License at
30574  *
30575  *     http://www.apache.org/licenses/LICENSE-2.0
30576  *
30577  * Unless required by applicable law or agreed to in writing, software
30578  * distributed under the License is distributed on an "AS IS" BASIS,
30579  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30580  *
30581  * See the License for the specific language governing permissions and
30582  * limitations under the License.
30583  */
30584 
30585 /*
30586 !depends 
30587 Measurement.js
30588 */
30589 
30590 
30591 /**
30592  * @class
30593  * Create a new time measurement instance.
30594  * 
30595  * @constructor
30596  * @extends Measurement
30597  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30598  * the construction of this instance
30599  */
30600 var TimeUnit = function (options) {
30601 	this.unit = "second";
30602 	this.amount = 0;
30603 	this.aliases = TimeUnit.aliases; // share this table in all instances
30604 	
30605 	if (options) {
30606 		if (typeof(options.unit) !== 'undefined') {
30607 			this.originalUnit = options.unit;
30608 			this.unit = this.aliases[options.unit] || options.unit;
30609 		}
30610 		
30611 		if (typeof(options.amount) === 'object') {
30612 			if (options.amount.getMeasure() === "time") {
30613 				this.amount = TimeUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30614 			} else {
30615 				throw "Cannot convert units " + options.amount.unit + " to a time";
30616 			}
30617 		} else if (typeof(options.amount) !== 'undefined') {
30618 			this.amount = parseFloat(options.amount);
30619 		}
30620 	}
30621 	
30622 	if (typeof(TimeUnit.ratios[this.unit]) === 'undefined') {
30623 		throw "Unknown unit: " + options.unit;
30624 	}
30625 };
30626 
30627 TimeUnit.prototype = new Measurement();
30628 TimeUnit.prototype.parent = Measurement;
30629 TimeUnit.prototype.constructor = TimeUnit;
30630 
30631 TimeUnit.ratios = {
30632 	/*              index  nsec        msec        mlsec       sec        min          hour          day           week         month        year         decade        century    */           
30633 	"nanosecond":   [ 1,   1,          0.001,      1e-6,       1e-9,      1.6667e-11,  2.7778e-13,   1.1574e-14,   1.6534e-15,  3.8027e-16,  3.1689e-17,  3.1689e-18,   3.1689e-19  ],  
30634 	"microsecond":  [ 2,   1000,       1,          0.001,      1e-6,      1.6667e-8,   2.7778e-10,   1.1574e-11,   1.6534e-12,  3.8027e-13,  3.1689e-14,  3.1689e-15,   3.1689e-16  ],  
30635 	"millisecond":  [ 3,   1e+6,       1000,       1,          0.001,     1.6667e-5,   2.7778e-7,    1.1574e-8,    1.6534e-9,   3.8027e-10,  3.1689e-11,  3.1689e-12,   3.1689e-13  ],
30636 	"second":       [ 4,   1e+9,       1e+6,       1000,       1,         0.0166667,   0.000277778,  1.1574e-5,    1.6534e-6,   3.8027e-7,   3.1689e-8,   3.1689e-9,    3.1689e-10  ],
30637 	"minute":       [ 5,   6e+10,      6e+7,       60000,      60,        1,           0.0166667,    0.000694444,  9.9206e-5,   2.2816e-5,   1.9013e-6,   1.9013e-7,    1.9013e-8   ],
30638     "hour":         [ 6,   3.6e+12,    3.6e+9,     3.6e+6,     3600,      60,          1,            0.0416667,    0.00595238,  0.00136895,  0.00011408,  1.1408e-5,    1.1408e-6   ],
30639     "day":          [ 7,   8.64e+13,   8.64e+10,   8.64e+7,    86400,     1440,        24,           1,            0.142857,    0.0328549,   0.00273791,  0.000273791,  2.7379e-5   ],
30640     "week":         [ 8,   6.048e+14,  6.048e+11,  6.048e+8,   604800,    10080,       168,          7,            1,           0.229984,    0.0191654,   0.00191654,   0.000191654 ],
30641     "month":        [ 9,   2.63e+15,   2.63e+12,   2.63e+9,    2.63e+6,   43829.1,     730.484,      30.4368,      4.34812,     1,           0.0833333,   0.00833333,   0.000833333 ],
30642     "year":         [ 10,  3.156e+16,  3.156e+13,  3.156e+10,  3.156e+7,  525949,      8765.81,      365.242,      52.1775,     12,          1,           0.1,          0.01        ],
30643     "decade":       [ 11,  3.156e+17,  3.156e+14,  3.156e+11,  3.156e+8,  5.259e+6,    87658.1,      3652.42,      521.775,     120,         10,          1,            0.1         ],
30644     "century":      [ 12,  3.156e+18,  3.156e+18,  3.156e+12,  3.156e+9,  5.259e+7,    876581,       36524.2,      5217.75,     1200,        100,         10,           1           ]
30645 };
30646 
30647 /**
30648  * Return the type of this measurement. Examples are "mass",
30649  * "length", "speed", etc. Measurements can only be converted
30650  * to measurements of the same type.<p>
30651  * 
30652  * The type of the units is determined automatically from the 
30653  * units. For example, the unit "grams" is type "mass". Use the 
30654  * static call {@link Measurement.getAvailableUnits}
30655  * to find out what units this version of ilib supports.
30656  *  
30657  * @return {string} the name of the type of this measurement
30658  */
30659 TimeUnit.prototype.getMeasure = function() {
30660 	return "time";
30661 };
30662 
30663 /**
30664  * Return a new measurement instance that is converted to a new
30665  * measurement unit. Measurements can only be converted
30666  * to measurements of the same type.<p>
30667  *  
30668  * @param {string} to The name of the units to convert to
30669  * @return {Measurement|undefined} the converted measurement
30670  * or undefined if the requested units are for a different
30671  * measurement type 
30672  */
30673 TimeUnit.prototype.convert = function(to) {
30674 	if (!to || typeof(TimeUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30675 		return undefined;
30676 	}
30677 	return new TimeUnit({
30678 		unit: to,
30679 		amount: this
30680 	});
30681 };
30682 
30683 TimeUnit.aliases = {
30684     "ns": "nanosecond",
30685     "NS": "nanosecond",
30686     "nS": "nanosecond",
30687     "Ns": "nanosecond",
30688     "Nanosecond": "nanosecond",
30689     "Nanoseconds": "nanosecond",
30690     "nanosecond": "nanosecond",
30691     "nanoseconds": "nanosecond",
30692     "NanoSecond": "nanosecond",
30693     "NanoSeconds": "nanosecond",
30694     "μs": "microsecond",
30695     "μS": "microsecond",
30696     "microsecond": "microsecond",
30697     "microseconds": "microsecond",
30698     "Microsecond": "microsecond",
30699     "Microseconds": "microsecond",
30700     "MicroSecond": "microsecond",
30701     "MicroSeconds": "microsecond",
30702     "ms": "millisecond",
30703     "MS": "millisecond",
30704     "mS": "millisecond",
30705     "Ms": "millisecond",
30706     "millisecond": "millisecond",
30707     "milliseconds": "millisecond",
30708     "Millisecond": "millisecond",
30709     "Milliseconds": "millisecond",
30710     "MilliSecond": "millisecond",
30711     "MilliSeconds": "millisecond",
30712     "s": "second",
30713     "S": "second",
30714     "sec": "second",
30715     "second": "second",
30716     "seconds": "second",
30717     "Second": "second",
30718     "Seconds": "second",
30719     "min": "minute",
30720     "Min": "minute",
30721     "minute": "minute",
30722     "minutes": "minute",
30723     "Minute": "minute",
30724     "Minutes": "minute",
30725     "h": "hour",
30726     "H": "hour",
30727     "hr": "hour",
30728     "Hr": "hour",
30729     "hR": "hour",
30730     "HR": "hour",
30731     "hour": "hour",
30732     "hours": "hour",
30733     "Hour": "hour",
30734     "Hours": "hour",
30735     "Hrs": "hour",
30736     "hrs": "hour",
30737     "day": "day",
30738     "days": "day",
30739     "Day": "day",
30740     "Days": "day",
30741     "week": "week",
30742     "weeks": "week",
30743     "Week": "week",
30744     "Weeks": "week",
30745     "month": "month",
30746     "Month": "month",
30747     "months": "month",
30748     "Months": "month",
30749     "year": "year",
30750     "years": "year",
30751     "Year": "year",
30752     "Years": "year",
30753     "yr": "year",
30754     "Yr": "year",
30755     "yrs": "year",
30756     "Yrs": "year",
30757     "decade": "decade",
30758     "decades": "decade",
30759     "Decade": "decade",
30760     "Decades": "decade",
30761     "century": "century",
30762     "centuries": "century",
30763     "Century": "century",
30764     "Centuries": "century"
30765 };
30766 
30767 /**
30768  * Convert a time to another measure.
30769  * @static
30770  * @param to {string} unit to convert to
30771  * @param from {string} unit to convert from
30772  * @param time {number} amount to be convert
30773  * @returns {number|undefined} the converted amount
30774  */
30775 TimeUnit.convert = function(to, from, time) {
30776     from = TimeUnit.aliases[from] || from;
30777     to = TimeUnit.aliases[to] || to;
30778     var fromRow = TimeUnit.ratios[from];
30779     var toRow = TimeUnit.ratios[to];
30780     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
30781         return undefined;
30782     }	
30783     return time * fromRow[toRow[0]];
30784 };
30785 
30786 /**
30787  * Localize the measurement to the commonly used measurement in that locale. For example
30788  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
30789  * the formatted number should be automatically converted to the most appropriate 
30790  * measure in the other system, in this case, mph. The formatted result should
30791  * appear as "37.3 mph". 
30792  * 
30793  * @abstract
30794  * @param {string} locale current locale string
30795  * @returns {Measurement} a new instance that is converted to locale
30796  */
30797 TimeUnit.prototype.localize = function(locale) {
30798     return new TimeUnit({
30799         unit: this.unit,
30800         amount: this.amount
30801     });
30802 };
30803 
30804 /**
30805  * Scale the measurement unit to an acceptable level. The scaling
30806  * happens so that the integer part of the amount is as small as
30807  * possible without being below zero. This will result in the 
30808  * largest units that can represent this measurement without
30809  * fractions. Measurements can only be scaled to other measurements 
30810  * of the same type.
30811  * 
30812  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
30813  * or undefined if the system can be inferred from the current measure
30814  * @return {Measurement} a new instance that is scaled to the 
30815  * right level
30816  */
30817 TimeUnit.prototype.scale = function(measurementsystem) {
30818 
30819     var fromRow = TimeUnit.ratios[this.unit];
30820     var time = this.amount;
30821     var munit = this.unit;
30822     var i;
30823 
30824     time = 18446744073709551999;
30825     for (var m in TimeUnit.ratios) {
30826     	i = TimeUnit.ratios[m][0];
30827     	var tmp = this.amount * fromRow[i];
30828     	if (tmp >= 1 && tmp < time) {
30829 	        time = tmp;
30830 	        munit = m;
30831     	}
30832     }
30833 
30834     return new TimeUnit({
30835         unit: munit,
30836         amount: time
30837     });
30838 };
30839 /**
30840  * @private
30841  * @static
30842  */
30843 TimeUnit.getMeasures = function () {
30844 	var ret = [];
30845 	for (var m in TimeUnit.ratios) {
30846 		ret.push(m);
30847 	}
30848 	return ret;
30849 };
30850 
30851 //register with the factory method
30852 Measurement._constructors["time"] = TimeUnit;
30853 
30854 
30855 /*< VelocityUnit.js */
30856 /*
30857  * VelocityUnit.js - Unit conversions for VelocityUnits/speeds
30858  * 
30859  * Copyright © 2014-2015, JEDLSoft
30860  *
30861  * Licensed under the Apache License, Version 2.0 (the "License");
30862  * you may not use this file except in compliance with the License.
30863  * You may obtain a copy of the License at
30864  *
30865  *     http://www.apache.org/licenses/LICENSE-2.0
30866  *
30867  * Unless required by applicable law or agreed to in writing, software
30868  * distributed under the License is distributed on an "AS IS" BASIS,
30869  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30870  *
30871  * See the License for the specific language governing permissions and
30872  * limitations under the License.
30873  */
30874 
30875 /*
30876 !depends 
30877 Measurement.js
30878 */
30879 
30880 
30881 /**
30882  * @class
30883  * Create a new speed measurement instance.
30884  * 
30885  * @constructor
30886  * @extends Measurement
30887  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
30888  * the construction of this instance
30889  */
30890 var VelocityUnit = function (options) {
30891 	this.unit = "meters/second";
30892 	this.amount = 0;
30893 	this.aliases = VelocityUnit.aliases; // share this table in all instances
30894 	
30895 	if (options) {
30896 		if (typeof(options.unit) !== 'undefined') {
30897 			this.originalUnit = options.unit;
30898 			this.unit = this.aliases[options.unit] || options.unit;
30899 		}
30900 		
30901 		if (typeof(options.amount) === 'object') {
30902 			if (options.amount.getMeasure() === "speed") {
30903 				this.amount = VelocityUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
30904 			} else {
30905 				throw "Cannot convert units " + options.amount.unit + " to a speed";
30906 			}
30907 		} else if (typeof(options.amount) !== 'undefined') {
30908 			this.amount = parseFloat(options.amount);
30909 		}
30910 	}
30911 	
30912 	if (typeof(VelocityUnit.ratios[this.unit]) === 'undefined') {
30913 		throw "Unknown unit: " + options.unit;
30914 	}
30915 };
30916 
30917 VelocityUnit.prototype = new Measurement();
30918 VelocityUnit.prototype.parent = Measurement;
30919 VelocityUnit.prototype.constructor = VelocityUnit;
30920 
30921 VelocityUnit.ratios = {
30922 	/*                 index, k/h         f/s         miles/h      knot         m/s        km/s         miles/s */
30923     "kilometer/hour":   [ 1,  1,          0.911344,   0.621371,    0.539957,    0.277778,  2.77778e-4,  1.72603109e-4 ],
30924 	"feet/second":      [ 2,  1.09728,    1,          0.681818,    0.592484,    0.3048,    3.048e-4,    1.89393939e-4 ],  
30925     "miles/hour":       [ 3,  1.60934,    1.46667,    1,           0.868976,    0.44704,   4.4704e-4,   2.77777778e-4 ],
30926     "knot":             [ 4,  1.852,      1.68781,    1.15078,     1,           0.514444,  5.14444e-4,  3.19660958e-4 ],
30927   	"meters/second":    [ 5,  3.6,        3.28084,    2.236936,    1.94384,     1,         0.001,       6.21371192e-4 ],	
30928     "kilometer/second": [ 6,  3600,       3280.8399,  2236.93629,  1943.84449,  1000,      1,           0.621371192   ],
30929     "miles/second":     [ 7,  5793.6384,  5280,       3600,        3128.31447,  1609.344,  1.609344,    1             ]
30930 };
30931 
30932 VelocityUnit.metricSystem = {
30933     "kilometer/hour": 1,
30934     "meters/second": 5,
30935     "kilometer/second": 6
30936 };
30937 VelocityUnit.imperialSystem = {
30938     "feet/second": 2,
30939     "miles/hour": 3,
30940     "knot": 4,
30941     "miles/second": 7
30942 };
30943 VelocityUnit.uscustomarySystem = {
30944     "feet/second": 2,
30945     "miles/hour": 3,
30946     "knot": 4,
30947     "miles/second": 7
30948 };
30949 
30950 VelocityUnit.metricToUScustomary = {
30951     "kilometer/hour": "miles/hour",
30952     "meters/second": "feet/second",
30953     "kilometer/second": "miles/second"
30954 };
30955 VelocityUnit.UScustomaryTometric = {
30956     "miles/hour": "kilometer/hour",
30957     "feet/second": "meters/second",
30958     "miles/second": "kilometer/second",
30959     "knot": "kilometer/hour"
30960 };
30961 
30962 /**
30963  * Return the type of this measurement. Examples are "mass",
30964  * "length", "speed", etc. Measurements can only be converted
30965  * to measurements of the same type.<p>
30966  * 
30967  * The type of the units is determined automatically from the 
30968  * units. For example, the unit "grams" is type "mass". Use the 
30969  * static call {@link Measurement.getAvailableUnits}
30970  * to find out what units this version of ilib supports.
30971  *  
30972  * @return {string} the name of the type of this measurement
30973  */
30974 VelocityUnit.prototype.getMeasure = function() {
30975 	return "speed";
30976 };
30977 
30978 /**
30979  * Return a new measurement instance that is converted to a new
30980  * measurement unit. Measurements can only be converted
30981  * to measurements of the same type.<p>
30982  *  
30983  * @param {string} to The name of the units to convert to
30984  * @return {Measurement|undefined} the converted measurement
30985  * or undefined if the requested units are for a different
30986  * measurement type 
30987  */
30988 VelocityUnit.prototype.convert = function(to) {
30989 	if (!to || typeof(VelocityUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
30990 		return undefined;
30991 	}
30992 	return new VelocityUnit({
30993 		unit: to,
30994 		amount: this
30995 	});
30996 };
30997 
30998 /**
30999  * Scale the measurement unit to an acceptable level. The scaling
31000  * happens so that the integer part of the amount is as small as
31001  * possible without being below zero. This will result in the 
31002  * largest units that can represent this measurement without
31003  * fractions. Measurements can only be scaled to other measurements 
31004  * of the same type.
31005  * 
31006  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
31007  * or undefined if the system can be inferred from the current measure
31008  * @return {Measurement} a new instance that is scaled to the 
31009  * right level
31010  */
31011 VelocityUnit.prototype.scale = function(measurementsystem) {
31012 	var mSystem;
31013 	if (measurementsystem === "metric" ||
31014 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.metricSystem[this.unit]) !== 'undefined')) {
31015 		mSystem = VelocityUnit.metricSystem;
31016 	} else if (measurementsystem === "imperial" ||
31017 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.imperialSystem[this.unit]) !== 'undefined')) {
31018 		mSystem = VelocityUnit.imperialSystem;
31019 	} else if (measurementsystem === "uscustomary" ||
31020 	    (typeof (measurementsystem) === 'undefined' && typeof (VelocityUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
31021 		mSystem = VelocityUnit.uscustomarySystem;
31022 	} else {
31023 		return new VelocityUnit({
31024 		    unit: this.unit,
31025 		    amount: this.amount
31026 		});
31027 	}
31028 
31029 	var speed = this.amount;
31030 	var munit = this.unit;
31031 	var fromRow = VelocityUnit.ratios[this.unit];
31032 
31033 	speed = 18446744073709551999;
31034 	
31035     for ( var m in mSystem) {
31036 		var tmp = this.amount * fromRow[mSystem[m]];
31037 		if (tmp >= 1 && tmp < speed) {
31038 			speed = tmp;
31039 			munit = m;
31040 		}
31041 	}
31042 
31043 	return new VelocityUnit({
31044 	    unit: munit,
31045 	    amount: speed
31046 	});
31047 };
31048 
31049 /**
31050  * Localize the measurement to the commonly used measurement in that locale. For example
31051  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
31052  * the formatted number should be automatically converted to the most appropriate 
31053  * measure in the other system, in this case, mph. The formatted result should
31054  * appear as "37.3 mph". 
31055  * 
31056  * @abstract
31057  * @param {string} locale current locale string
31058  * @returns {Measurement} a new instance that is converted to locale
31059  */
31060 VelocityUnit.prototype.localize = function(locale) {
31061     var to;
31062     if (locale === "en-US" || locale === "en-GB") {
31063         to = VelocityUnit.metricToUScustomary[this.unit] || this.unit;
31064     } else {
31065         to = VelocityUnit.UScustomaryTometric[this.unit] || this.unit;
31066     }
31067     return new VelocityUnit({
31068 		unit: to,
31069 		amount: this
31070     });
31071 };
31072 
31073 VelocityUnit.aliases = {
31074     "foot/sec": "feet/second",
31075     "foot/s": "feet/second",
31076     "feet/s": "feet/second",
31077     "f/s": "feet/second",
31078     "feet/second": "feet/second",
31079     "feet/sec": "feet/second",
31080     "meter/sec": "meters/second",
31081     "meter/s": "meters/second",
31082     "meters/s": "meters/second",
31083     "metre/sec": "meters/second",
31084     "metre/s": "meters/second",
31085     "metres/s": "meters/second",
31086     "mt/sec": "meters/second",
31087     "m/sec": "meters/second",
31088     "mt/s": "meters/second",
31089     "m/s": "meters/second",
31090     "mps": "meters/second",
31091     "meters/second": "meters/second",
31092     "meters/sec": "meters/second",
31093     "kilometer/hour": "kilometer/hour",
31094     "km/hour": "kilometer/hour",
31095     "kilometers/hour": "kilometer/hour",
31096     "kmh": "kilometer/hour",
31097     "km/h": "kilometer/hour",
31098     "kilometer/h": "kilometer/hour",
31099     "kilometers/h": "kilometer/hour",
31100     "km/hr": "kilometer/hour",
31101     "kilometer/hr": "kilometer/hour",
31102     "kilometers/hr": "kilometer/hour",
31103     "kilometre/hour": "kilometer/hour",
31104     "mph": "miles/hour",
31105     "mile/hour": "miles/hour",
31106     "mile/hr": "miles/hour",
31107     "mile/h": "miles/hour",
31108     "miles/h": "miles/hour",
31109     "miles/hr": "miles/hour",
31110     "miles/hour": "miles/hour",
31111     "kn": "knot",
31112     "kt": "knot",
31113     "kts": "knot",
31114     "knots": "knot",
31115     "nm/h": "knot",
31116     "nm/hr": "knot",
31117     "nauticalmile/h": "knot",
31118     "nauticalmile/hr": "knot",
31119     "nauticalmile/hour": "knot",
31120     "nauticalmiles/hr": "knot",
31121     "nauticalmiles/hour": "knot",
31122     "knot": "knot",
31123     "kilometer/second": "kilometer/second",
31124     "kilometer/sec": "kilometer/second",
31125     "kilometre/sec": "kilometer/second",
31126     "Kilometre/sec": "kilometer/second",
31127     "kilometers/second": "kilometer/second",
31128     "kilometers/sec": "kilometer/second",
31129     "kilometres/sec": "kilometer/second",
31130     "Kilometres/sec": "kilometer/second",
31131     "km/sec": "kilometer/second",
31132     "Km/s": "kilometer/second",
31133     "km/s": "kilometer/second",
31134     "miles/second": "miles/second",
31135     "miles/sec": "miles/second",
31136     "miles/s": "miles/second",
31137     "mile/s": "miles/second",
31138     "mile/sec": "miles/second",
31139     "Mile/s": "miles/second"
31140 };
31141 
31142 /**
31143  * Convert a speed to another measure.
31144  * @static
31145  * @param to {string} unit to convert to
31146  * @param from {string} unit to convert from
31147  * @param speed {number} amount to be convert
31148  * @returns {number|undefined} the converted amount
31149  */
31150 VelocityUnit.convert = function(to, from, speed) {
31151     from = VelocityUnit.aliases[from] || from;
31152     to = VelocityUnit.aliases[to] || to;
31153 	var fromRow = VelocityUnit.ratios[from];
31154 	var toRow = VelocityUnit.ratios[to];
31155 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
31156 		return undefined;
31157 	}	
31158 	var result = speed * fromRow[toRow[0]];
31159     return result;
31160 };
31161 
31162 /**
31163  * @private
31164  * @static
31165  */
31166 VelocityUnit.getMeasures = function () {
31167 	var ret = [];
31168 	for (var m in VelocityUnit.ratios) {
31169 		ret.push(m);
31170 	}
31171 	return ret;
31172 };
31173 
31174 //register with the factory method
31175 Measurement._constructors["speed"] = VelocityUnit;
31176 Measurement._constructors["velocity"] = VelocityUnit;
31177 
31178 
31179 /*< VolumeUnit.js */
31180 /*
31181  * volume.js - Unit conversions for volume
31182  * 
31183  * Copyright © 2014-2015, JEDLSoft
31184  *
31185  * Licensed under the Apache License, Version 2.0 (the "License");
31186  * you may not use this file except in compliance with the License.
31187  * You may obtain a copy of the License at
31188  *
31189  *     http://www.apache.org/licenses/LICENSE-2.0
31190  *
31191  *
31192  * Unless required by applicable law or agreed to in writing, software
31193  * distributed under the License is distributed on an "AS IS" BASIS,
31194  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31195  *
31196  * See the License for the specific language governing permissions and
31197  * limitations under the License.
31198  */
31199 
31200 /*
31201 !depends 
31202 Measurement.js
31203 */
31204 
31205 
31206 /**
31207  * @class
31208  * Create a new Volume measurement instance.
31209  * 
31210  * @constructor
31211  * @extends Measurement
31212  * @param options {{unit:string,amount:number|string|undefined}} Options controlling 
31213  * the construction of this instance
31214  */
31215 var VolumeUnit = function (options) {
31216 	this.unit = "cubic meter";
31217 	this.amount = 0;
31218 	this.aliases = VolumeUnit.aliases; // share this table in all instances
31219 	
31220 	if (options) {
31221 		if (typeof(options.unit) !== 'undefined') {
31222 			this.originalUnit = options.unit;
31223 			this.unit = this.aliases[options.unit] || options.unit;
31224 		}
31225 		
31226 		if (typeof(options.amount) === 'object') {
31227 			if (options.amount.getMeasure() === "volume") {
31228 				this.amount = VolumeUnit.convert(this.unit, options.amount.getUnit(), options.amount.getAmount());
31229 			} else {
31230 				throw "Cannot convert unit " + options.amount.unit + " to a volume";
31231 			}
31232 		} else if (typeof(options.amount) !== 'undefined') {
31233 			this.amount = parseFloat(options.amount);
31234 		}
31235 	}
31236 	
31237 	if (typeof(VolumeUnit.ratios[this.unit]) === 'undefined') {
31238 		throw "Unknown unit: " + options.unit;
31239 	}
31240 };
31241 
31242 VolumeUnit.prototype = new Measurement();
31243 VolumeUnit.prototype.parent = Measurement;
31244 VolumeUnit.prototype.constructor = VolumeUnit;
31245 
31246 VolumeUnit.ratios = {
31247     /*                 index, tsp,      tbsp,          cubic inch  us ounce, cup,        pint,       quart,      gallon,      cubic foot,  milliliter  liter,      cubic meter, imperial tsp,  imperial tbsp, imperial ounce,  imperial pint,  imperial quart, imperial gal, */
31248     "tsp" :            [1,    1,        0.333333,      0.300781,   0.166667, 0.0208333,  0.0104167,  0.00520833, 0.00130208,  0.000174063, 4.92892,    0.00492892, 4.9289e-6,   0.832674,      0.277558,      0.173474,        0.00867369,     0.00433684,     0.00108421          ],
31249     "tbsp":            [2,    3,        1,             0.902344,   0.5,      0.0625,     0.0312,     0.015625,   0.00390625,  0.00052219,  14.7868,    0.0147868,  1.4787e-5,   2.49802,       0.832674,      0.520421,        0.0260211,      0.0130105,      0.00325263          ],
31250     "cubic inch":      [3,    3.32468,  1.10823,       1,          0.554113, 0.0692641,  0.034632,   0.017316,   0.004329,    0.000578704, 16.3871,    0.0163871,  1.6387e-5,   2.76837,       0.92279,       0.576744,        0.0288372,      0.0144186,      0.00360465          ],
31251     "us ounce":        [4,    6,        2,             1.80469,    1,        0.125,      0.0625,     0.0078125,  0.0078125,   0.00104438,  29.5735,    0.0295735,  2.9574e-5,   4.99604,       1.04084,       1.04084,         0.0520421,      0.0260211,      0.00650526          ],
31252     "cup":             [5,    48,       16,            14.4375,    8,        1,          0.5,        0.25,       0.0625,      0.00835503,  236.588,    0.236588,   0.000236588, 39.9683,       13.3228,       8.32674,         0.416337,       0.208168,       0.0520421           ],
31253     "pint":            [6,    96,       32,            28.875,     16,       2,          1,          0.5,        0.125,       0.0167101,   473.176,    0.473176,   0.000473176, 79.9367,       26.6456,       16.6535,         0.832674,       0.416337,       0.104084            ],
31254     "quart":           [7,    192,      64,            57.75,      32,       4,          2,          1,          0.25,        0.0334201,   946.353,    0.946353,   0.000946353, 159.873,       53.2911,       33.307,          1.66535,        0.832674,       0.208168            ],
31255     "gallon":          [8,    768,      256,           231,        128,      16,         8,          4,          1,           0.133681,    3785.41,    3.78541,    0.00378541,  639.494,       213.165,       133.228,         6.66139,        3.3307,         0.832674            ],
31256     "cubic foot":      [9,    5745.04,  1915.01,       1728,       957.506,  119.688,    59.8442,    29.9221,    7.48052,     1,           28316.8,    28.3168,    0.0283168,   4783.74,       1594.58,       996.613,         49.8307,        24.9153,        6.22883             ],
31257     "milliliter":      [10,   0.202884, 0.067628,      0.0610237,  0.033814, 0.00422675, 0.00211338, 0.00105669, 0.000264172, 3.5315e-5,   1,          0.001,      1e-6,        0.168936,      0.0563121,     0.0351951,       0.00175975,     0.000879877,    0.000219969         ],
31258     "liter":           [11,   202.884,  67.628,        61.0237,    33.814,   4.22675,    2.11338,    1.05669,    0.264172,    0.0353147,   1000,       1,          0.001,       56.3121,       56.3121,       35.191,          1.75975,        0.879877,       0.219969            ],
31259     "cubic meter":     [12,   202884,   67628,         61023.7,    33814,    4226.75,    2113.38,    1056.69,    264.172,     35.3147,     1e+6,       1000,       1,           168936,        56312.1,       35195.1,         1759.75,        879.877,        219.969             ],
31260     "imperial tsp":    [13,   1.20095,  0.200158,      0.361223,   0.600475, 0.0250198,  0.0125099,  0.00625495, 0.00156374,  0.000209041, 5.91939,    0.00591939, 5.9194e-6,   1,             0.333333,      0.208333,        0.0104167,      0.00520833,     0.00130208          ],
31261     "imperial tbsp":   [14,   3.60285,  1.20095,       1.08367,    0.600475, 0.0750594,  0.0375297,  0.0187649,  0.00469121,  0.000627124, 17.7582,    0.0177582,  1.7758e-5,   3,             1,             0.625,           0.03125,        0.015625,       0.00390625          ],
31262     "imperial ounce":  [15,   5.76456,  1.92152,       1.73387,    0.96076,  0.120095,   0.0600475,  0.0300238,  0.00750594,  0.0010034,   28.4131,    0.0284131,  2.8413e-5,   4.8,           1.6,           1,               0.05,           0.025,          0.00625             ],
31263     "imperial pint":   [16,   115.291,  38.4304,       34.6774,    19.2152,  2.4019,     1.20095,    0.600475,   0.150119,    0.020068,    568.261,    0.568261,   0.000568261, 96,            32,            20,              1,              0.5,            0.125               ],
31264     "imperial quart":  [17,   230.582,  76.8608,       69.3549,    38.4304,  4.8038,     2.4019,     1.20095,    0.300238,    0.0401359,   1136.52,    1.13652,    0.00113652,  192,           64,            40,              2,              1,              0.25                ],
31265     "imperial gallon": [18,   922.33,   307.443,       277.42,     153.722,  19.2152,    9.6076,     4.8038,     1.20095,     0.160544,    4546.09,    4.54609,    0.00454609,  768,           256,           160,             8,              4,              1                   ]
31266 };
31267 
31268 /**
31269  * Return the type of this measurement. Examples are "mass",
31270  * "length", "speed", etc. Measurements can only be converted
31271  * to measurements of the same type.<p>
31272  * 
31273  * The type of the units is determined automatically from the 
31274  * units. For example, the unit "grams" is type "mass". Use the 
31275  * static call {@link Measurement.getAvailableUnits}
31276  * to find out what units this version of ilib supports.
31277  *  
31278  * @return {string} the name of the type of this measurement
31279  */
31280 VolumeUnit.prototype.getMeasure = function() {
31281 	return "volume";
31282 };
31283 
31284 /**
31285  * Return a new measurement instance that is converted to a new
31286  * measurement unit. Measurements can only be converted
31287  * to measurements of the same type.<p>
31288  *  
31289  * @param {string} to The name of the units to convert to
31290  * @return {Measurement|undefined} the converted measurement
31291  * or undefined if the requested units are for a different
31292  * measurement type 
31293  */
31294 VolumeUnit.prototype.convert = function(to) {
31295 	if (!to || typeof(VolumeUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
31296 		return undefined;
31297 	}
31298 	return new VolumeUnit({
31299 		unit: to,
31300 		amount: this
31301 	});
31302 };
31303 
31304 VolumeUnit.aliases = {
31305     "US gal": "gallon",
31306     "US gallon": "gallon",
31307     "US Gal": "gallon",
31308     "US Gallons": "gallon",
31309     "Gal(US)": "gallon",
31310     "gal(US)": "gallon",
31311     "gallon": "gallon",
31312     "quart": "quart",
31313     "US quart": "quart",
31314     "US quarts": "quart",
31315     "US Quart": "quart",
31316     "US Quarts": "quart",
31317     "US qt": "quart",
31318     "Qt(US)": "quart",
31319     "qt(US)": "quart",
31320     "US pint": "pint",
31321     "US Pint": "pint",
31322     "pint": "pint",
31323     "pint(US)": "pint",
31324     "Pint(US)": "pint",
31325     "US cup": "cup",
31326     "US Cup": "cup",
31327     "cup(US)": "cup",
31328     "Cup(US)": "cup",
31329     "cup": "cup",
31330     "us ounce": "us ounce",
31331     "US ounce": "us ounce",
31332     "℥": "us ounce",
31333     "US Oz": "us ounce",
31334     "oz(US)": "us ounce",
31335     "Oz(US)": "us ounce",
31336     "US tbsp": "tbsp",
31337     "tbsp": "tbsp",
31338     "tbsp(US)": "tbsp",
31339     "US tablespoon": "tbsp",
31340     "US tsp": "tsp",
31341     "tsp(US)": "tsp",
31342     "tsp": "tsp",
31343     "Cubic meter": "cubic meter",
31344     "cubic meter": "cubic meter",
31345     "Cubic metre": "cubic meter",
31346     "cubic metre": "cubic meter",
31347     "m3": "cubic meter",
31348     "Liter": "liter",
31349     "Liters": "liter",
31350     "liter": "liter",
31351     "L": "liter",
31352     "l": "liter",
31353     "Milliliter": "milliliter",
31354     "ML": "milliliter",
31355     "ml": "milliliter",
31356     "milliliter": "milliliter",
31357     "mL": "milliliter",
31358     "Imperial gal": "imperial gallon",
31359     "imperial gallon": "imperial gallon",
31360     "Imperial gallon": "imperial gallon",
31361     "gallon(imperial)": "imperial gallon",
31362     "gal(imperial)": "imperial gallon",
31363     "Imperial quart": "imperial quart",
31364     "imperial quart": "imperial quart",
31365     "Imperial Quart": "imperial quart",
31366     "IMperial qt": "imperial quart",
31367     "qt(Imperial)": "imperial quart",
31368     "quart(imperial)": "imperial quart",
31369     "Imperial pint": "imperial pint",
31370     "imperial pint": "imperial pint",
31371     "pint(Imperial)": "imperial pint",
31372     "imperial oz": "imperial ounce",
31373     "imperial ounce": "imperial ounce",
31374     "Imperial Ounce": "imperial ounce",
31375     "Imperial tbsp": "imperial tbsp",
31376     "imperial tbsp": "imperial tbsp",
31377     "tbsp(Imperial)": "imperial tbsp",
31378     "Imperial tsp": "imperial tsp",
31379     "imperial tsp": "imperial tsp",
31380     "tsp(Imperial)": "imperial tsp",
31381     "Cubic foot": "cubic foot",
31382     "cubic foot": "cubic foot",
31383     "Cubic Foot": "cubic foot",
31384     "Cubic feet": "cubic foot",
31385     "cubic Feet": "cubic foot",
31386     "cubic ft": "cubic foot",
31387     "ft3": "cubic foot",
31388     "Cubic inch": "cubic inch",
31389     "Cubic inches": "cubic inch",
31390     "cubic inches": "cubic inch",
31391     "cubic inch": "cubic inch",
31392     "cubic in": "cubic inch",
31393     "cu in": "cubic inch",
31394     "cu inch": "cubic inch",
31395     "inch³": "cubic inch",
31396     "in³": "cubic inch",
31397     "inch^3": "cubic inch",
31398     "in^3": "cubic inch",
31399     "c.i": "cubic inch",
31400     "CI": "cubic inch",
31401     "cui": "cubic inch"
31402 };
31403 
31404 /**
31405  * Convert a volume to another measure.
31406  * @static
31407  * @param to {string} unit to convert to
31408  * @param from {string} unit to convert from
31409  * @param volume {number} amount to be convert
31410  * @returns {number|undefined} the converted amount
31411  */
31412 VolumeUnit.convert = function(to, from, volume) {
31413     from = VolumeUnit.aliases[from] || from;
31414     to = VolumeUnit.aliases[to] || to;
31415 	var fromRow = VolumeUnit.ratios[from];
31416 	var toRow = VolumeUnit.ratios[to];
31417 	if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
31418 		return undefined;
31419 	}	
31420 	var result = volume * fromRow[toRow[0]];
31421     return result;
31422 };
31423 
31424 /**
31425  * @private
31426  * @static
31427  */
31428 VolumeUnit.getMeasures = function () {
31429 	var ret = [];
31430 	for (var m in VolumeUnit.ratios) {
31431 		ret.push(m);
31432 	}
31433 	return ret;
31434 };
31435 VolumeUnit.metricSystem = {
31436     "milliliter": 10,
31437     "liter": 11,
31438     "cubic meter": 12
31439 };
31440 VolumeUnit.imperialSystem = {
31441     "imperial tsp": 13,
31442     "imperial tbsp": 14,
31443     "imperial ounce": 15,
31444     "imperial pint": 16,
31445     "imperial quart": 17,
31446     "imperial gallon": 18
31447 };
31448 VolumeUnit.uscustomarySystem = {
31449     "tsp": 1,
31450     "tbsp": 2,
31451     "cubic inch": 3,
31452     "us ounce": 4,
31453     "cup": 5,
31454     "pint": 6,
31455     "quart": 7,
31456     "gallon": 8,
31457     "cubic foot": 9
31458 };
31459 
31460 VolumeUnit.metricToUScustomary = {
31461     "milliliter": "tsp",
31462     "liter": "quart",
31463     "cubic meter": "cubic foot"
31464 };
31465 VolumeUnit.metricToImperial = {
31466     "milliliter": "imperial tsp",
31467     "liter": "imperial quart",
31468     "cubic meter": "imperial gallon"
31469 };
31470 
31471 VolumeUnit.imperialToMetric = {
31472     "imperial tsp": "milliliter",
31473     "imperial tbsp": "milliliter",
31474     "imperial ounce": "milliliter",
31475     "imperial pint": "liter",
31476     "imperial quart": "liter",
31477     "imperial gallon": "cubic meter"
31478 };
31479 VolumeUnit.imperialToUScustomary = {
31480     "imperial tsp": "tsp",
31481     "imperial tbsp": "tbsp",
31482     "imperial ounce": "us ounce",
31483     "imperial pint": "pint",
31484     "imperial quart": "quart",
31485     "imperial gallon": "gallon"
31486 };
31487 
31488 VolumeUnit.uScustomaryToImperial = {
31489     "tsp": "imperial tsp",
31490     "tbsp": "imperial tbsp",
31491     "cubic inch": "imperial tbsp",
31492     "us ounce": "imperial ounce",
31493     "cup": "imperial ounce",
31494     "pint": "imperial pint",
31495     "quart": "imperial quart",
31496     "gallon": "imperial gallon",
31497     "cubic foot": "imperial gallon"
31498 };
31499 VolumeUnit.uScustomarylToMetric = {
31500     "tsp": "milliliter",
31501     "tbsp": "milliliter",
31502     "cubic inch": "milliliter",
31503     "us ounce": "milliliter",
31504     "cup": "milliliter",
31505     "pint": "liter",
31506     "quart": "liter",
31507     "gallon": "cubic meter",
31508     "cubic foot": "cubic meter"
31509 };
31510 
31511 /**
31512  * Localize the measurement to the commonly used measurement in that locale. For example
31513  * If a user's locale is "en-US" and the measurement is given as "60 kmh", 
31514  * the formatted number should be automatically converted to the most appropriate 
31515  * measure in the other system, in this case, mph. The formatted result should
31516  * appear as "37.3 mph". 
31517  * 
31518  * @abstract
31519  * @param {string} locale current locale string
31520  * @returns {Measurement} a new instance that is converted to locale
31521  */
31522 VolumeUnit.prototype.localize = function(locale) {
31523 	var to;
31524 	if (locale === "en-US") {
31525 		to = VolumeUnit.metricToUScustomary[this.unit] ||
31526 		    VolumeUnit.imperialToUScustomary[this.unit] ||
31527 		    this.unit;
31528 	} else if (locale === "en-GB") {
31529 		to = VolumeUnit.metricToImperial[this.unit] ||
31530 		    VolumeUnit.uScustomaryToImperial[this.unit] ||
31531 		    this.unit;
31532 	} else {
31533 		to = VolumeUnit.uScustomarylToMetric[this.unit] ||
31534 		    VolumeUnit.imperialToUScustomary[this.unit] ||
31535 		    this.unit;
31536 	}
31537 	return new VolumeUnit({
31538 	    unit: to,
31539 	    amount: this
31540 	});
31541 };
31542 
31543 /**
31544  * Scale the measurement unit to an acceptable level. The scaling
31545  * happens so that the integer part of the amount is as small as
31546  * possible without being below zero. This will result in the 
31547  * largest units that can represent this measurement without
31548  * fractions. Measurements can only be scaled to other measurements 
31549  * of the same type.
31550  * 
31551  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
31552  * or undefined if the system can be inferred from the current measure
31553  * @return {Measurement} a new instance that is scaled to the 
31554  * right level
31555  */
31556 VolumeUnit.prototype.scale = function(measurementsystem) {
31557     var fromRow = VolumeUnit.ratios[this.unit];
31558     var mSystem;
31559 
31560     if (measurementsystem === "metric"|| (typeof(measurementsystem) === 'undefined'
31561         && typeof(VolumeUnit.metricSystem[this.unit]) !== 'undefined')) {
31562         mSystem = VolumeUnit.metricSystem;
31563     } else if (measurementsystem === "uscustomary" || (typeof(measurementsystem) === 'undefined'
31564         && typeof(VolumeUnit.uscustomarySystem[this.unit]) !== 'undefined')) {
31565         mSystem = VolumeUnit.uscustomarySystem;
31566     } else if (measurementsystem === "imperial"|| (typeof(measurementsystem) === 'undefined'
31567         && typeof(VolumeUnit.imperialSystem[this.unit]) !== 'undefined')) {
31568         mSystem = VolumeUnit.imperialSystem;
31569     }
31570 
31571     var volume = this.amount;
31572     var munit = this.unit;
31573 
31574     volume = 18446744073709551999;
31575     
31576     for (var m in mSystem) {
31577     	var tmp = this.amount * fromRow[mSystem[m]];
31578         if (tmp >= 1 && tmp < volume) {
31579         	volume = tmp;
31580 	        munit = m;
31581         }
31582     }
31583     
31584     return new VolumeUnit({
31585         unit: munit,
31586         amount: volume
31587     });
31588 };
31589 
31590 //register with the factory method
31591 Measurement._constructors["volume"] = VolumeUnit;
31592 
31593 
31594 
31595 /*< MeasurementFactory.js */
31596 /*
31597  * MeasurementFactory.js - Function to instantiate the appropriate subclasses of
31598  * the Measurement class.
31599  *
31600  * Copyright © 2015, JEDLSoft
31601  *
31602  * Licensed under the Apache License, Version 2.0 (the "License");
31603  * you may not use this file except in compliance with the License.
31604  * You may obtain a copy of the License at
31605  *
31606  *     http://www.apache.org/licenses/LICENSE-2.0
31607  *
31608  * Unless required by applicable law or agreed to in writing, software
31609  * distributed under the License is distributed on an "AS IS" BASIS,
31610  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31611  *
31612  * See the License for the specific language governing permissions and
31613  * limitations under the License.
31614  */
31615 
31616 /*
31617 !depends
31618 UnknownUnit.js
31619 AreaUnit.js
31620 DigitalStorageUnit.js
31621 EnergyUnit.js
31622 FuelConsumptionUnit.js
31623 LengthUnit.js
31624 MassUnit.js
31625 TemperatureUnit.js
31626 TimeUnit.js
31627 VelocityUnit.js
31628 VolumeUnit.js
31629 Measurement.js
31630 */
31631 
31632 // TODO: make these dependencies dynamic or at least generate them in the build
31633 // These will each add themselves to Measurement._constructors[]
31634 
31635 
31636 /**
31637  * Create a measurement subclass instance based on a particular measure
31638  * required. The measurement is immutable once
31639  * it is created, but it can be converted to other measurements later.<p>
31640  *
31641  * The options may contain any of the following properties:
31642  *
31643  * <ul>
31644  * <li><i>amount</i> - either a numeric amount for this measurement given
31645  * as a number of the specified units, or another Measurement instance
31646  * to convert to the requested units. If converting to new units, the type
31647  * of measure between the other instance's units and the current units
31648  * must be the same. That is, you can only convert one unit of mass to
31649  * another. You cannot convert a unit of mass into a unit of length.
31650  *
31651  * <li><i>unit</i> - units of this measurement. Use the
31652  * static call {@link MeasurementFactory.getAvailableUnits}
31653  * to find out what units this version of ilib supports. If the given unit
31654  * is not a base unit, the amount will be normalized to the number of base units
31655  * and stored as that number of base units.
31656  * For example, if an instance is constructed with 1 kg, this will be converted
31657  * automatically into 1000 g, as grams are the base unit and kg is merely a
31658  * commonly used scale of grams. 
31659  * </ul>
31660  *
31661  * Here are some examples of converting a length into new units. 
31662  * The first method is via this factory function by passing the old measurement 
31663  * in as the "amount" property.<p>
31664  * 
31665  * <pre>
31666  * var measurement1 = MeasurementFactory({
31667  *   amount: 5,
31668  *   units: "kilometers"
31669  * });
31670  * var measurement2 = MeasurementFactory({
31671  *   amount: measurement1,
31672  *   units: "miles"
31673  * });
31674  * </pre>
31675  * 
31676  * The value in measurement2 will end up being about 3.125 miles.<p>
31677  * 
31678  * The second method uses the convert method.<p>
31679  * 
31680  * <pre>
31681  * var measurement1 = MeasurementFactory({
31682  *   amount: 5,
31683  *   units: "kilometers"
31684  * });
31685  * var measurement2 = measurement1.convert("miles");
31686  * });
31687  * </pre>
31688  *
31689  * The value in measurement2 will again end up being about 3.125 miles.
31690  * 
31691  * @static
31692  * @param {Object=} options options that control the construction of this instance
31693  */
31694 var MeasurementFactory = function(options) {
31695 	if (!options || typeof(options.unit) === 'undefined') {
31696 		return undefined;
31697 	}
31698 
31699 	var measure = undefined;
31700 
31701 	for (var c in Measurement._constructors) {
31702 		var measurement = Measurement._constructors[c];
31703 		if (typeof(measurement.aliases[options.unit]) !== 'undefined') {
31704 			measure = c;
31705 			break;
31706 		}
31707 	}
31708 
31709 	if (!measure || typeof(measure) === 'undefined') {
31710 		return new UnknownUnit({
31711 			unit: options.unit,
31712 			amount: options.amount
31713 		});
31714 	} else {
31715 		return new Measurement._constructors[measure](options);
31716 	}
31717 };
31718 
31719 /**
31720  * Return a list of all possible units that this version of ilib supports.
31721  * Typically, the units are given as their full names in English. Unit names
31722  * are case-insensitive.
31723  *
31724  * @static
31725  * @return {Array.<string>} an array of strings containing names of measurement 
31726  * units available
31727  */
31728 MeasurementFactory.getAvailableUnits = function () {
31729 	var units = [];
31730 	for (var c in Measurement._constructors) {
31731 		var measure = Measurement._constructors[c];
31732 		units = units.concat(measure.getMeasures());
31733 	}
31734 	return units;
31735 };
31736 
31737 
31738 
31739 /*< UnitFmt.js */
31740 /*
31741  * UnitFmt.js - Unit formatter class
31742  * 
31743  * Copyright © 2014-2015, JEDLSoft
31744  *
31745  * Licensed under the Apache License, Version 2.0 (the "License");
31746  * you may not use this file except in compliance with the License.
31747  * You may obtain a copy of the License at
31748  *
31749  *     http://www.apache.org/licenses/LICENSE-2.0
31750  *
31751  * Unless required by applicable law or agreed to in writing, software
31752  * distributed under the License is distributed on an "AS IS" BASIS,
31753  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31754  *
31755  * See the License for the specific language governing permissions and
31756  * limitations under the License.
31757  */
31758 
31759 /*
31760 !depends 
31761 ilib.js 
31762 Locale.js 
31763 ResBundle.js 
31764 LocaleInfo.js
31765 IString.js
31766 NumFmt.js
31767 Utils.js
31768 */
31769 
31770 // !data unitfmt
31771 
31772 
31773 
31774 /**
31775  * @class
31776  * Create a new unit formatter instance. The unit formatter is immutable once
31777  * it is created, but can format as many different strings with different values
31778  * as needed with the same options. Create different unit formatter instances 
31779  * for different purposes and then keep them cached for use later if you have 
31780  * more than one unit string to format.<p>
31781  * 
31782  * The options may contain any of the following properties:
31783  * 
31784  * <ul>
31785  * <li><i>locale</i> - locale to use when formatting the units. The locale also
31786  * controls the translation of the names of the units. If the locale is
31787  * not specified, then the default locale of the app or web page will be used.
31788  * 
31789  * <li><i>autoScale</i> - when true, automatically scale the amount to get the smallest
31790  * number greater than 1, where possible, possibly by converting units within the locale's
31791  * measurement system. For example, if the current locale is "en-US", and we have
31792  * a measurement containing 278 fluid ounces, then the number "278" can be scaled down
31793  * by converting the units to a larger one such as gallons. The scaled size would be
31794  * 2.17188 gallons. Since iLib does not have a US customary measure larger than gallons,
31795  * it cannot scale it down any further. If the amount is less than the smallest measure
31796  * already, it cannot be scaled down any further and no autoscaling will be applied.
31797  * Default for the autoScale property is "true", so it only needs to be specified when
31798  * you want to turn off autoscaling.
31799  * 
31800  * <li><i>autoConvert</i> - automatically convert the units to the nearest appropriate
31801  * measure of the same type in the measurement system used by the locale. For example, 
31802  * if a measurement of length is given in meters, but the current locale is "en-US" 
31803  * which uses the US Customary system, then the nearest appropriate measure would be 
31804  * "yards", and the amount would be converted from meters to yards automatically before
31805  * being formatted. Default for the autoConvert property is "true", so it only needs to 
31806  * be specified when you want to turn off autoconversion.
31807  * 
31808  * <li><i>maxFractionDigits</i> - the maximum number of digits that should appear in the
31809  * formatted output after the decimal. A value of -1 means unlimited, and 0 means only print
31810  * the integral part of the number.
31811  * 
31812  * <li><i>minFractionDigits</i> - the minimum number of fractional digits that should
31813  * appear in the formatted output. If the number does not have enough fractional digits
31814  * to reach this minimum, the number will be zero-padded at the end to get to the limit.
31815  * 
31816  * <li><i>roundingMode</i> - When the maxFractionDigits or maxIntegerDigits is specified,
31817  * this property governs how the least significant digits are rounded to conform to that
31818  * maximum. The value of this property is a string with one of the following values:
31819  * <ul>
31820  *   <li><i>up</i> - round away from zero
31821  *   <li><i>down</i> - round towards zero. This has the effect of truncating the number
31822  *   <li><i>ceiling</i> - round towards positive infinity
31823  *   <li><i>floor</i> - round towards negative infinity
31824  *   <li><i>halfup</i> - round towards nearest neighbour. If equidistant, round up.
31825  *   <li><i>halfdown</i> - round towards nearest neighbour. If equidistant, round down.
31826  *   <li><i>halfeven</i> - round towards nearest neighbour. If equidistant, round towards the even neighbour
31827  *   <li><i>halfodd</i> - round towards nearest neighbour. If equidistant, round towards the odd neighbour
31828  * </ul>
31829  * 
31830  * <li><i>onLoad</i> - a callback function to call when the date format object is fully 
31831  * loaded. When the onLoad option is given, the UnitFmt object will attempt to
31832  * load any missing locale data using the ilib loader callback.
31833  * When the constructor is done (even if the data is already preassembled), the 
31834  * onLoad function is called with the current instance as a parameter, so this
31835  * callback can be used with preassembled or dynamic loading or a mix of the two.
31836  * 
31837  * <li><i>sync</i> - tell whether to load any missing locale data synchronously or 
31838  * asynchronously. If this option is given as "false", then the "onLoad"
31839  * callback must be given, as the instance returned from this constructor will
31840  * not be usable for a while.
31841  *  
31842  * <li><i>loadParams</i> - an object containing parameters to pass to the 
31843  * loader callback function when locale data is missing. The parameters are not
31844  * interpretted or modified in any way. They are simply passed along. The object 
31845  * may contain any property/value pairs as long as the calling code is in
31846  * agreement with the loader callback function as to what those parameters mean.
31847  * </ul>
31848  * 
31849  * Here is an example of how you might use the unit formatter to format a string with
31850  * the correct units.<p>
31851  * 
31852  *  
31853  * @constructor
31854  * @param {Object} options options governing the way this date formatter instance works
31855  */
31856 var UnitFmt = function(options) {
31857 	var sync = true, 
31858 		loadParams = undefined;
31859 	
31860     this.length = "long";
31861     this.scale  = true;
31862     this.measurementType = 'undefined';
31863     this.convert = true;
31864 	this.locale = new Locale();
31865 
31866     if (options) {
31867     	if (options.locale) {
31868     		this.locale = (typeof(options.locale) === 'string') ? new Locale(options.locale) : options.locale;
31869     	}
31870 
31871     	if (typeof(options.sync) === 'boolean') {
31872     		sync = options.sync;
31873     	}
31874 
31875     	if (typeof(options.loadParams) !== 'undefined') {
31876     		loadParams = options.loadParams;
31877     	}
31878 
31879     	if (options.length) {
31880     		this.length = options.length;
31881     	}
31882 
31883     	if (typeof(options.autoScale) === 'boolean') {
31884     		this.scale = options.autoScale;
31885     	}
31886 
31887     	if (typeof(options.autoConvert) === 'boolean') {
31888     		this.convert = options.autoConvert;
31889     	}
31890         
31891         if (typeof(options.useNative) === 'boolean') {
31892     		this.useNative = options.useNative;
31893     	}
31894 
31895     	if (options.measurementSystem) {
31896     		this.measurementSystem = options.measurementSystem;
31897     	}
31898         
31899         if (typeof (options.maxFractionDigits) === 'number') {
31900             /** 
31901              * @private
31902              * @type {number|undefined} 
31903              */
31904             this.maxFractionDigits = options.maxFractionDigits;
31905         }
31906         if (typeof (options.minFractionDigits) === 'number') {
31907             /** 
31908              * @private
31909              * @type {number|undefined} 
31910              */
31911             this.minFractionDigits = options.minFractionDigits;
31912         }
31913         /** 
31914          * @private
31915          * @type {string} 
31916          */
31917         this.roundingMode = options.roundingMode;
31918     }
31919 
31920     if (!UnitFmt.cache) {
31921     	UnitFmt.cache = {};
31922     }
31923 
31924 	Utils.loadData({
31925 		object: UnitFmt, 
31926 		locale: this.locale, 
31927 		name: "unitfmt.json", 
31928 		sync: sync, 
31929 		loadParams: loadParams, 
31930 		callback: ilib.bind(this, function (format) {                      
31931 			var formatted = format;
31932 			this.template = formatted["unitfmt"][this.length];
31933 			
31934 			new NumFmt({
31935 	    		locale: this.locale,
31936 	    		useNative: this.useNative,
31937 	            maxFractionDigits: this.maxFractionDigits,
31938 	            minFractionDigits: this.minFractionDigits,
31939 	            roundingMode: this.roundingMode,
31940 	            sync: sync,
31941 	            loadParams: loadParams,
31942 	            onLoad: ilib.bind(this, function (numfmt) {
31943 	            	this.numFmt = numfmt;
31944 	            	
31945 	    			if (options && typeof(options.onLoad) === 'function') {
31946 	    				options.onLoad(this);
31947 	    			}
31948 	            })
31949 	    	});
31950 		})
31951 	});
31952 };
31953 
31954 UnitFmt.prototype = {
31955 	
31956 	/**
31957 	 * Return the locale used with this formatter instance.
31958 	 * @return {Locale} the Locale instance for this formatter
31959 	 */
31960 	getLocale: function() {
31961 		return this.locale;
31962 	},
31963 	
31964 	/**
31965 	 * Return the template string that is used to format date/times for this
31966 	 * formatter instance. This will work, even when the template property is not explicitly 
31967 	 * given in the options to the constructor. Without the template option, the constructor 
31968 	 * will build the appropriate template according to the options and use that template
31969 	 * in the format method. 
31970 	 * 
31971 	 * @return {string} the format template for this formatter
31972 	 */
31973 	getTemplate: function() {
31974 		return this.template;
31975 	},
31976 	
31977 	/**
31978 	 * Convert this formatter to a string representation by returning the
31979 	 * format template. This method delegates to getTemplate.
31980 	 * 
31981 	 * @return {string} the format template
31982 	 */
31983 	toString: function() {
31984 		return this.getTemplate();
31985 	},
31986     
31987 	/**
31988 	 * Return whether or not this formatter will auto-scale the units while formatting.
31989 	 * @returns {boolean} true if auto-scaling is turned on
31990 	 */
31991     getScale: function() {
31992         return this.scale;
31993     },
31994 
31995     /**
31996      * Return the measurement system that is used for this formatter.
31997      * @returns {string} the measurement system used in this formatter
31998      */
31999     getMeasurementSystem: function() {
32000         return this.measurementSystem;
32001     },
32002 
32003 	/**
32004 	 * Format a particular unit instance according to the settings of this
32005 	 * formatter object.
32006 	 * 
32007 	 * @param {Measurement} measurement measurement to format	 
32008 	 * @return {string} the formatted version of the given date instance
32009 	 */
32010     format: function (measurement) {
32011     	var u = this.convert ? measurement.localize(this.locale.getSpec()) : measurement;
32012     	u = this.scale ? u.scale(this.measurementSystem) : u;
32013     	var formatted = new IString(this.template[u.getUnit()]);
32014     	// make sure to use the right plural rules
32015     	formatted.setLocale(this.locale, true, undefined, undefined);
32016     	formatted = formatted.formatChoice(u.amount,{n:this.numFmt.format(u.amount)});
32017     	return formatted.length > 0 ? formatted : u.amount +" " + u.unit;
32018     }
32019 };
32020 
32021 
32022 /*< /mnt/Terasaur/root/home/edwin/src/ilib-sf-trunk/js/lib/ilib-full-inc.js */
32023 /**
32024  * @license
32025  * Copyright © 2012-2015, JEDLSoft
32026  *
32027  * Licensed under the Apache License, Version 2.0 (the "License");
32028  * you may not use this file except in compliance with the License.
32029  * You may obtain a copy of the License at
32030  *
32031  *     http://www.apache.org/licenses/LICENSE-2.0
32032  *
32033  * Unless required by applicable law or agreed to in writing, software
32034  * distributed under the License is distributed on an "AS IS" BASIS,
32035  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32036  *
32037  * See the License for the specific language governing permissions and
32038  * limitations under the License.
32039  */
32040 
32041 /*
32042  * ilib-full-inc.js - metafile that includes all other js files
32043  */
32044 
32045 /* !depends
32046 ilib.js
32047 DateRngFmt.js
32048 IDate.js
32049 DateFactory.js
32050 HebrewDate.js
32051 HebrewCal.js
32052 IslamicCal.js
32053 IslamicDate.js
32054 JulianCal.js
32055 JulianDate.js
32056 GregorianCal.js
32057 GregorianDate.js
32058 ThaiSolarCal.js
32059 ThaiSolarDate.js
32060 PersianCal.js
32061 PersianDate.js
32062 PersianAlgoCal.js
32063 PersianAlgoDate.js
32064 HanCal.js
32065 HanDate.js
32066 EthiopicCal.js
32067 EthiopicDate.js
32068 CopticCal.js
32069 CopticDate.js
32070 INumber.js
32071 NumFmt.js
32072 JulianDay.js
32073 DateFmt.js
32074 Calendar.js
32075 CalendarFactory.js
32076 Utils.js
32077 Locale.js
32078 IString.js
32079 DurationFmt.js
32080 ResBundle.js
32081 CType.js
32082 LocaleInfo.js
32083 DateRngFmt.js
32084 isAlnum.js
32085 isAlpha.js
32086 isAscii.js
32087 isBlank.js
32088 isCntrl.js
32089 isDigit.js
32090 isGraph.js
32091 isIdeo.js
32092 isLower.js
32093 isPrint.js
32094 isPunct.js
32095 isSpace.js
32096 isUpper.js
32097 isXdigit.js
32098 isScript.js
32099 ScriptInfo.js
32100 Name.js
32101 NameFmt.js
32102 Address.js
32103 AddressFmt.js
32104 Collator.js
32105 nfkc/all.js
32106 LocaleMatcher.js
32107 NormString.js
32108 CaseMapper.js
32109 GlyphString.js
32110 PhoneFmt.js
32111 PhoneGeoLocator.js
32112 PhoneNumber.js
32113 Measurement.js
32114 MeasurementFactory.js
32115 UnitFmt.js
32116 LengthUnit.js
32117 VelocityUnit.js
32118 DigitalStorageUnit.js
32119 TemperatureUnit.js
32120 UnknownUnit.js
32121 TimeUnit.js
32122 MassUnit.js
32123 AreaUnit.js
32124 FuelConsumptionUnit.js
32125 VolumeUnit.js	
32126 EnergyUnit.js
32127 */
32128 
32129